tcache的发展历程
tcache的发展历程
前言
经建议,笔者打算参加一次xctf 的分站赛,为此开始备注。遂开始复现往届比赛赛题。先从这次sekaictf-2025开始。这是从第一题开始的分析与延伸。
tcache的引入及更新
2.26-2.27
首先,tcache 在glibc 2.26 版本登场,其目的是为了加快堆块的管理。因此在没有作安全的检测,也为之后的利用埋下了隐患。
相关源码
1 |
|
在glibc2.26 和 glibc2.27 的版本中,没有任何安全检测的手段。可以修改tcache chunk(指链入tache bins 中的堆块) 的next 字段,完成任意地址分配。
当然,为了便于tcache 的管理,加入了tcache_perthread_struct 结构体.counts 数组,用来记录每个大小的tcache bins 中的数量entries数组用来记录每个tcache chunk的next字段的地址
同理,我们可以修改counts 和entries来欺骗系统,完成任意地址分配.
因为没有任何检测,所以我们可以完成double free,甚至你可以把同一个堆块连续free 7次,把tcache bins 填满.
2.28 第一次补丁
显然,注意到了double free的利用过于easy, 于是tcache 迎来了他的第一次更新, 添加了 key 这个变量. 在2.29 版本没有什么改动
相关源码
1 | typedef struct tcache_entry { |
简单解析一下:
- key字段开始不作设置
- 当堆块通过
double-free时,也就是e->key!=tcache时,e进入tcache bins中,并把key设置为tcahche - 那么下次
free(e),就会检测到这个的key,从而判断是否double-free.
但是,想要绕过也非常简单.想要继续double free,只要能修改到key字段就可以继续这个利用.
而修改next的方法可以照旧.
这个检测,仅仅是为了针对double free而已,所以局限很大.对安全方面的加强有点,但多.
2.30微调-counts加宽
没有大改,也不知道为啥要这么改动.效果不知道,目的不知道.
1 |
|
在2.26 和 2.27 中, 这个字段是char 类型,也就是只有8位, 1字节. 现在加宽, 改为16位, 2字节.
以后修改 entries 数组时,需要把偏移调整一下.
2.32小加强-entries加密
entries的加密,让之前直接修改next 的利用变得稍微困难了一点. 我们必须明确一个点,tcache bins 中, chunk 的 下一个堆块 原本是有next 决定的,因为entries 就是 直接 用next的值.
但是现在不是了, entries 是 (&next>>12) ^ next . 但是因为加密的算法是固定的,所以 我们只要能泄露堆地址,就可以继续伪造.
相关源码
1 |
假设 你要写入的 地址是 target , 你现在修改的chunk 的 next 指针的地址是addr. 那么你实际需要写入next 的值是 (addr>>12) ^ target.
计算同样非常简单.
2.34小加强-key随机化
1 | static __thread tcache_perthread_struct *tcache = NULL; |
虽然是小加强, 因为此时要获取key似乎只能爆破.但是我不明白,因为对key字段的检测,只有在这个堆块被free 要进入tcache bins 时.
也就是说,其实很多时候根本触发不了这个检测.

