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的触发点:

  1. free时:在fastbin操作之前,如果chunk size符合要求且对应bin未满
  2. malloc时
    • 从fastbin返回chunk后,剩余chunk放入tcache直到上限
    • 从smallbin返回chunk后,剩余chunk放入tcache直到上限
    • binning code中优先放入tcache

取出chunk的触发点:

  1. __libc_malloc()调用_int_malloc()前检查tcache
  2. bining code中达到上限时返回最后一个chunk
  3. 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安全性问题

主要漏洞:

  1. 缺乏检查

    • 不检查size标志
    • 不检查double free
    • 操作在malloc/free流程中靠前,绕过许多安全检查
  2. 利用方式

    • 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字段造成堆块重叠

示例步骤

  1. 分配多个chunk
  2. 修改某个chunk的size字段
  3. 释放并重新分配,造成堆块重叠

利用效果

  • 可实现堆块重叠
  • 可泄露敏感信息
  • 可实现任意地址读写

5.4 tcache_poisoning (指针污染)

原理:修改tcache中的fd指针,控制下次分配的位置

示例步骤

  1. 释放一个chunk到tcache
  2. 修改该chunk的fd指针到目标地址
  3. 两次malloc获取目标地址的控制权

利用效果

  • 可实现任意地址写
  • 可劫持控制流

6. 实际案例分析

6.1 HITCON2018 child_tcache

漏洞点

  • NULL byte off-by-one
  • 可通过unsorted bin泄露libc

利用步骤

  1. 构造overlap chunk泄露libc
  2. 修改tcache的fd指向__malloc_hook
  3. 分配chunk写入one_gadget

6.2 HITCON2018 baby_tcache

漏洞点

  • NULL byte off-by-one
  • 无show函数,需通过IO_FILE结构泄露

利用步骤

  1. 构造overlap chunk
  2. 修改_IO_2_1_stdout_结构泄露libc
  3. 修改tcache的fd指向__free_hook
  4. 分配chunk写入one_gadget

6.3 QCTF2018 babyheap

漏洞点

  • NULL byte off-by-one
  • 有show函数可直接泄露

利用步骤

  1. 构造overlap chunk泄露libc
  2. 修改tcache的fd指向__free_hook
  3. 分配chunk写入system地址
  4. 释放包含"/bin/sh"的chunk

6.4 BCTF2018 houseofAtum

漏洞点

  • UAF漏洞
  • 只能申请两个note

利用步骤

  1. 通过多次释放构造tcache链
  2. 修改fd指针泄露heap和libc
  3. 修改tcache的fd指向__free_hook
  4. 分配chunk写入one_gadget

7. 防御措施

  1. 升级glibc:新版glibc增加了更多检查
  2. 堆保护机制
    • 检查double free
    • 验证chunk的完整性
    • 增加随机化
  3. 编译选项
    • -D_FORTIFY_SOURCE=2
    • -fstack-protector-strong

8. 总结

tcache机制虽然提升了性能,但由于缺乏足够的检查,引入了多种攻击面。理解tcache的内部机制和各种攻击手法,对于二进制安全研究和CTF竞赛都至关重要。实际利用时需要根据具体情况组合不同的技术,并注意不同glibc版本间的差异。

Tcache Attack 全面解析 1. tcache机制概述 tcache全名thread local caching,是glibc 2.26版本引入的机制,它为每个线程创建一个缓存(cache),实现无锁的分配算法,提升性能。 关键特性: 默认开启 每个线程独立 无锁分配 性能优化 2. tcache数据结构 主要定义: 核心结构体: 大小分类: 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 关键函数: 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的特性 示例代码 : 利用效果 : 可获取多个指向同一内存的指针 可用于UAF攻击 5.2 house of spirit (伪造chunk) 原理 :伪造一个fake chunk并释放,后续分配可获取该fake 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版本间的差异。