tcache attack
tcache double free
double free可以通过对同一块内存free两次,实现任意地址写。当libc版本在2.26以上时,free的块优先放入tcache,malloc也优先从tcache中取,性能更好。但是安全检查变弱了。
static void
tcache_put (mchunkptr chunk, size_t tc_idx)
{
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
assert (tc_idx < TCACHE_MAX_BINS);
e->next = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}
tcache free代码如上,只校验了tc_idx的值是否到达TCACHE_MAX_BINS(7),并没有其他的检查,相比fastbin或者其它bin的double free,tcache double free更加简单。
double free 原理
如果程序存在某些漏洞可以对同一个地址free两次,则存在double free。比如,在调用free函数后,不把指针变量置NULL,或者不检查该内存是否被free过了。
如果存在,对于tcache,那么通常的利用步骤是:
- double free 地址A,让A进入tcache,并A的fd指针指向自己。(tcache[7]: A----->A)
- 调用malloc,将A分配出来,这时tcache中还有一个A(tcache[7]: A);
- 伪造tcache中的A,修改A的fd为free函数或者print函数got表中地址,或者hook地址,或者任意地址。这样让free函数地址插入到了tcache中;(tcache[7]: A—>__free_hook)
- 再调用一次malloc,将tcache剩余的一个A分配出来。
- 最后调用malloc的时候,就能将__free_hook的地址分配出来了。实现任意地址写。
- 最后我们可以向__free_hook地址中(或者其它任意地址)写入system函数或者one_gadget地址。调用free的时候就能跳转到one_gadget去实现程序流控制;
例题
tcache-uaf-attack
用ctfwiki的例题做讲解
题目漏洞点在malloc的地方,存在一个null-byte-overflow的漏洞:
if ( sz )
{
while ( 1 )
{
read(0, &malloc_p[i], 1uLL);
if ( sz - 1 < i || !malloc_p[i] || malloc_p[i] == '\n' )
break;
++i;
}
malloc_p[i] = 0;
malloc_p[sz] = 0; // null-byte-overflow
}
可以将下一个chunk头的p_inuse位置零,实现double free。
大体思路:
1. 题目libc版本为2.27,存在tcache。需要转换为unsorted bin的double free;
2. 泄露libc地址,需要使用unsorted bin泄露,先把tcache填满,然后构造unsorted bins:
A->B->C, C有main_arena的地址,将C 分配出来,打印,注意不覆盖bk;
3. 程序流控制:需要利用null-byteo-verflow实现double free,实现任意地址写:
a. 在之前构造的unsorted bin链基础上,将ABC分配出来,分配B时,利用漏洞溢出修改A的头部p_inuse位;
b. 重新free C和A,由于A的p_inuse为0,会触发chunk合并,将ABC合成一个大free chunk(B还在使用中);
c. 使用malloc功能,重新将B分配出来,这样,表中就有两个B chunk。
d. 这时候使用free功能就能将B free两次,触发double free
e. 然后将B分配出来,写入free_hook地址,再分配一次B,就能将free_hook分配出来(详情见double free原理),我们写入one_gadget地址。
附录
- __free_hook:
它是libc free函数中使用的一个全局变量:
unsigned __int64 __fastcall free(unsigned __int64 *a1)
{
...
if ( _free_hook )
{
_free_hook(a1, retaddr);
return __readfsqword(0x28u) ^ v77;
}
...
}
如果free_hook不为0,则直接跳转到free_hook的函数,通常用于堆利用时,got表无法修改时的情况(开启了RELRO)。可以将free_hook存的值修改为system,可实现控制程序流。
malloc_hook类似。
libc2.27—>ubuntu18
2.123