0.libc2.27版本下的tcache机制
tcache是libc2.26版本后引入的新机制,其广泛应用于Ubuntu18.04及以后的系统。tcache的管理机制类似于fastbin,每个bins上最多可以有7个chunk。每个bins都是单链表,与fastbin同为LIFO。tcache的优先级大于fastbin。只有当tcache满了后 (这里的满指的是对应的bins上已有7个chunk,无法再放入后续chunk),chunk才会被放回其他链表,而在申请操作时,tcache也会被首先分配。
在tcache中新增了两个结构体,分别是tcache_entry和tcache_perthread_struct:
1 | /* We overlay this structure on the user-data portion of a chunk when the chunk is stored in the per-thread cache. */ |
其中TCACHE_MAX_BINS的默认值是64,这也就意味着tcache相当于有64个bins。堆空间的起始部分都会有一块先于用户申请分配的堆空间,大小为0x250。
其中有两个重要的函数, tcache_get() 和 tcache_put(),分别用于获取tcache和释放tcache:
1 | static void |
这两个函数会在函数 _int_free 和 _libc_malloc 的开头被调用,其中 tcache_put 当所请求的分配大小不大于0x408并且当给定大小的 tcache bin 未满时调用。一个 tcache bin 中的最大块数mp.tcache_count是7。
在 tcache_get 中,仅仅检查了 tc_idx ,此外,我们可以将 tcache 当作一个类似于 fastbin 的单独链表,只是它的 check,并没有 fastbin 那么复杂,仅仅检查 tcache->entries[tc_idx] = e->next;
(以上部分多数摘自ctf-wiki。)
对于tcache,有几个关键点:
- 1)tcache管理是单链表,采用LIFO原则。
- 2)tcache的管理结构存在于堆中,默认有64个entry,每个entry最多存放7个chunk。
- 3)tcache的fd指向chunk的user_data区,而fastbin是指向chunk头部。
- 4)tcache的某个entry被占满后,符合该大小的chunk被free后的规则与原有机制(未使用tcache的)相同。
1.简述利用double free实现简单的tcache attack
libc2.27~2.29版本的tcache无对double free的检测。
tcache的检测机制比fastbin还松,甚至没有对size的检测。
用tcache实现double free比fastbin还简单。我们知道,如有要利用fastbin实现double free,要先构造两个等大的同属于fastbin的堆块A和B,依次释放A、B、A才能达到A->B->A的效果。如果直接释放两次,系统是不会通过的。但是,tcache不一样,它允许同一个堆块释放两次构成A->A。
而tcache attack也远比fastbin attack要求来的低。之前说了,tcache不会检查放入堆块的size是否符合,因此,不需要费尽心机构造fake chunk来绕过检测,直接让fd指向target_addr即可,这样最终拿到的fake chunk就是从target_addr-0x10开始的(因为tcache的chunk->fd指向数据区),也就是意味着我们可以直接从target_addr开始写。
我们还是以之前学习fastbin attack和unsortedbin attack的附件heap为例,测试环境为Ubuntu18.04,libc使用版本是2.27。
如果我还是攻击__malloc_hook的话,自然需要leak出libc中的地址。
如果像之前一样,申请大小为0x100的话,释放后chunk是不会进入unsortedbin的,而是会被放入tcache:
那么,如果我依然想要使用unsortedbin leak该怎么做呢?
很简单,只要申请的chunk大小大于0x408就行了。
之后leak的方法与2.23版本的基本相同。
之后的攻击也比fastbin attack简单:
可以看出double free可以直接A->A。
__malloc_hook也能顺利进入tcache。
下面给出一个exp:
1 | from pwn import * |
顺利获取了shell:
2.小结
这只是tcache最简单的一种利用方法,实际上在一般题目中更多涉及了tcache的处理、绕过,这不是一朝一夕能够学会的,需要不断积累。
处理有tcache机制的题还需学习。