Tcache Attack 学习
字数 2143 2025-08-24 16:48:07
Tcache Attack 全面解析
1. tcache机制概述
tcache全名thread local caching,是glibc 2.26版本引入的机制,它为每个线程创建一个缓存(cache),实现无锁的分配算法,提升性能。
关键特性:
- 默认开启
- 每个线程独立
- 无锁分配
- 性能优化
2. tcache数据结构
主要定义:
#define TCACHE_MAX_BINS 64 // 每个线程默认64个单链表bins
#define MAX_TCACHE_SIZE tidx2usize(TCACHE_MAX_BINS-1)
#define TCACHE_FILL_COUNT 7 // 每个bins最多存放7个chunk
核心结构体:
typedef struct tcache_entry {
struct tcache_entry *next; // 指向同bins中的下一个chunk
} tcache_entry;
typedef struct tcache_perthread_struct {
char counts[TCACHE_MAX_BINS]; // 记录每个bins中的chunk数量
tcache_entry *entries[TCACHE_MAX_BINS]; // 64个bins的入口指针
} tcache_perthread_struct;
大小分类:
- 64位机器:以16B递增,从24B到1032B
- 32位机器:以8B递增,从12B到512B
- 只用于存放non-large的chunk
3. tcache操作机制
放入chunk的触发点:
- free时:在fastbin操作之前,如果chunk size符合要求且对应bin未满
- malloc时:
- 从fastbin返回chunk后,剩余chunk放入tcache直到上限
- 从smallbin返回chunk后,剩余chunk放入tcache直到上限
- binning code中优先放入tcache
取出chunk的触发点:
__libc_malloc()调用_int_malloc()前检查tcache- bining code中达到上限时返回最后一个chunk
- binning code结束后返回符合条件的最后一个chunk
关键函数:
// 放入tcache
static void tcache_put(mchunkptr chunk, size_t tc_idx) {
tcache_entry *e = (tcache_entry *)chunk2mem(chunk);
e->next = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}
// 从tcache取出
static void *tcache_get(size_t tc_idx) {
tcache_entry *e = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]);
return (void *)e;
}
4. tcache安全性问题
主要漏洞:
-
缺乏检查:
- 不检查size标志
- 不检查double free
- 操作在malloc/free流程中靠前,绕过许多安全检查
-
利用方式:
- tcache_dup (Double Free)
- house of spirit (伪造chunk)
- tcache_overlapping_chunks (堆块重叠)
- tcache_poisoning (指针污染)
5. 典型攻击手法详解
5.1 tcache_dup (Double Free)
原理:利用tcache不检查double free的特性
示例代码:
void *p1 = malloc(0x10);
free(p1);
free(p1); // 二次释放
void *p2 = malloc(0x10); // 获取相同地址
void *p3 = malloc(0x10); // 再次获取相同地址
利用效果:
- 可获取多个指向同一内存的指针
- 可用于UAF攻击
5.2 house of spirit (伪造chunk)
原理:伪造一个fake chunk并释放,后续分配可获取该fake chunk
示例代码:
unsigned long long fake_chunk[64];
fake_chunk[1] = 0x110; // 设置伪造的size
void *a = &fake_chunk[2];
free(a); // 释放伪造的chunk
void *b = malloc(0x100); // 获取伪造的chunk
利用效果:
- 可在栈、数据段等区域伪造chunk
- 可实现任意地址读写
5.3 tcache_overlapping_chunks (堆块重叠)
原理:修改chunk的size字段造成堆块重叠
示例步骤:
- 分配多个chunk
- 修改某个chunk的size字段
- 释放并重新分配,造成堆块重叠
利用效果:
- 可实现堆块重叠
- 可泄露敏感信息
- 可实现任意地址读写
5.4 tcache_poisoning (指针污染)
原理:修改tcache中的fd指针,控制下次分配的位置
示例步骤:
- 释放一个chunk到tcache
- 修改该chunk的fd指针到目标地址
- 两次malloc获取目标地址的控制权
利用效果:
- 可实现任意地址写
- 可劫持控制流
6. 实际案例分析
6.1 HITCON2018 child_tcache
漏洞点:
- NULL byte off-by-one
- 可通过unsorted bin泄露libc
利用步骤:
- 构造overlap chunk泄露libc
- 修改tcache的fd指向
__malloc_hook - 分配chunk写入one_gadget
6.2 HITCON2018 baby_tcache
漏洞点:
- NULL byte off-by-one
- 无show函数,需通过IO_FILE结构泄露
利用步骤:
- 构造overlap chunk
- 修改
_IO_2_1_stdout_结构泄露libc - 修改tcache的fd指向
__free_hook - 分配chunk写入one_gadget
6.3 QCTF2018 babyheap
漏洞点:
- NULL byte off-by-one
- 有show函数可直接泄露
利用步骤:
- 构造overlap chunk泄露libc
- 修改tcache的fd指向
__free_hook - 分配chunk写入system地址
- 释放包含"/bin/sh"的chunk
6.4 BCTF2018 houseofAtum
漏洞点:
- UAF漏洞
- 只能申请两个note
利用步骤:
- 通过多次释放构造tcache链
- 修改fd指针泄露heap和libc
- 修改tcache的fd指向
__free_hook - 分配chunk写入one_gadget
7. 防御措施
- 升级glibc:新版glibc增加了更多检查
- 堆保护机制:
- 检查double free
- 验证chunk的完整性
- 增加随机化
- 编译选项:
-D_FORTIFY_SOURCE=2-fstack-protector-strong
8. 总结
tcache机制虽然提升了性能,但由于缺乏足够的检查,引入了多种攻击面。理解tcache的内部机制和各种攻击手法,对于二进制安全研究和CTF竞赛都至关重要。实际利用时需要根据具体情况组合不同的技术,并注意不同glibc版本间的差异。