Glibc2.29及以上版本的利用
House of botcake
由于tcache加入了key值来进行double free检测,以至于在旧版本时的直接进行double free变的无效,所以自然就有了绕过方法,绕过方法其中比较典型的就是house of botcake,他的本质也是通过UAF来达到绕过的目的。
利用条件
1.glibc > 2.25(有tcache)
2.可以double free
利用过程
1.把指定size的tcache填充满。
2.填充满后,再次free就可以进入到unsorted bin,这里free两个相邻的chunk(prev chunk和利用堆块a,要与top chunk隔开),接着会触发合并。
3.取出tcache中的一个堆块,再把利用 free chunk a进入tcache。
4.申请一个tcache不存在的size,这时候就会从unsorted bin中取出,我们只需要保证申请的size可以包括到利用堆块a即可。
5.利用4中申请的chunk进行其他操作..
利用理解
1.利用的本质是什么?
利用的本质是让chunk在unsorted bin和tcache中同时存在,从而造成UAF可以修改key的内容。
2.为什么要让unsorted bin中的堆块合并?
合并的目的是让unsorted bin中的堆块size变大。
我们知道在malloc的时候会优先去tcache中取出内容,但能取出的前提是tcache中的size和申请的size相等。所以我们需要用不同与原来的size进行申请,才能从unsorted bin中取出。
当然还有一种方法是,把tcache中这个size的全部chunk都拿出来,接下来就能申请到unsorted bin中的这个chunk。
所以如果要考察house of botcake那么一般会对申请次数做一个限制,否则使用这个方法意义不大。
总结
其实这种方法只能算是一个小技巧,我认为不应该是一个house of系列中的一员。但它的确绕过了tcache中的限制,也算是有实际意义吧。
EXP:https://github.com/shellphish/how2heap/blob/master/glibc_2.31/house_of_botcake.c
fastbin reverse into tcache
由于glibc2.29在unsorted bin遍历的时候加入了新的检测,以至于无法进行unsorted bin attack,这也同时对largebin attack造成了一定程度上的伤害,由于检测无法篡改BK,largebin attack从原来写两个堆地址转变成了只能写一个堆地址。
这里要解决的问题是,在程序无法申请largebin大小的size的情况下,如何任意写一个堆地址。
利用条件
1.glibc > 2.25(有tcache)
2.UAF
原理分析
1.我们知道在开启tcache机制的版本中,申请fastbin chunk过程中堆管理器发现此size的fastbin中任有其他堆块(同size的fastbin中有两个及其以上的堆块)。那么就会把需要的取出返回给用户,其余的全部都放入到空闲的tcache(直到填满tcache或该size的fastbin为空停止)
|
|
2.在把剩余chunk放入tcache的过程中相当于把fastbin逆序了。也就是fastbin中的链表尾部成为了tcache中的链表头部,fastbin中的链表头部成为了tcache中的链表尾部。 3.我们可以借助这个过程,伪造可控的fastbin堆块ptr的FD为target(利用UAF),最终在放入tcache的时候会修改
|
|
这里的ptr也就是我们写入的堆块地址。
利用过程
1.我们需要先把tcache填充满,这样再free的时候才会进入到fastbin中。
2.我们分别free两个chunk(a 和 b),使其进入到fastbin中。
2.我们利用UAF漏洞来修改a的fd,使其指向target - 0x10。这样我们就伪造了链表中多出的一项。(但是原来的target位置的内容最好为NULL,否则又会指向下一层)
3.清空tcache(全部取出),接下来再申请就会申请到b堆块。tcache检测到fastbin堆块中还有其他内容(a堆块以及target - 0x10),所以会把fastbin堆块的链表reverse_into到tcache中。
4.这个过程中
|
|
5.同时tcache也有了target和a
利用理解
1.为什么可以UAF还要这些操作?
UAF可以有很多不同的表现,当我们无法直接利用tcache的时候(使用calloc申请堆块的时候不会从tcache中取出、UAF无法覆盖到key的值等等…)
这时候我们可能由于size的限制(不能申请0x68等原因),无法利用fastbin进行攻击(fastbin有size检测),那么就可以利用这个方法来写一个堆地址。
2.可以提供一些意外解(待实践)
例如用这个方法来打**_IO_list_all**(由于_IO_list_all本来是有值的,目前不清楚会不会写到一些无法访问内容的地址,但可以确定的是应该可以用类似tcache stashing unlink attack的方法来防止接着访问),就可以做到在限制了size的情况下(无法使用largebin attack和unsorted bin attack),在libc-2.27下利用IO_FILE来getshell。
总结
这个方法和接下来的tcache stashing unlink attack实际上是比较类似的,但是这里的好处是不需要用calloc,接下来的方法中,需要用calloc的原因是需要控制tcache中的size,让攻击发生后及时停止遍历(否则就会访问到无效地址),但是这个方法是访问到NULL停止,所以不需要控制tcache的size。
这个利用方法应该更多的是为其他方法提供辅助作用,我对其的了解还不够深刻,期待各位师傅在此之上出题。
tcache stashing unlink attack
这个技巧是在2019年由Angelboy在HITCON CTF当中提出的。
一直想要学习的一直攻击方法,在上次V&N面试的时候就被问到了,但是我一直没有搞懂他的原理。等考完试就来好好学习一下吧
考完啦!高数比想象的要简单,感觉厉害的人都能满分吧。(当然不是我)
利用条件
1.glibc > 2.25(有tcache)
2.UAF
3.用calloc申请
攻击目标
1.如果有calloc函数,可以对任意地址写一个main_arena上的一个地址(大数字),可以考虑在glibc2.29及其以上用于取代unsorted bin attack。(BUUOJ-2020 新春红包题-3)
2.如果还有malloc函数,那么可以利用这个操作来申请到目标地址。(2020-XCTF-高校战疫赛 two_chunk)
原理分析
在申请一块一块从smallbin中取出的chunk的情况下,若tcache没有满且smallbin有其他内容的情况下,会把剩余的全部堆块放入到tcache中。
在这个插入的过程中,会从最后一块开始遍历,根据BK依次往前找chunk,直到重新遍历到main_arena再停止。如果我们可以修改其中一块堆块的BK,修改成target - 0x10,那么在遍历的过程中通过如下代码的**bck->fd = bin;**这条语句就可以对(target - 0x10) -> fd进行修改,修改的值结果是bin,bin是main_arena上的一个位置。
|
|
但是我们需要对tcache中已有的数量做一个构造,构造成正好只能再插入一个来自smallbin中的chunk。 原因是:在正常的遍历过程中,判断指针是否重新回到main_arena上的一个位置来确定是否遍历结束。(因为遍历的是双向循环链表),但是如果这个链表的BK被我们所修改成目标地址,那么这个遍历就不能正常的结束了,所以我们要在程序访问到不可访问的地址前,让他从循环中跳出来。也就是控制下面这一行语句为false
|
|
第二行的条件是比较难控制的(如果能控制那不是就已经有了目标地址的控制权限了?) 所以利用第一行的方法来停止遍历,也就是控制插入时的tcache->counts。
但是在一般情况下,我们优先从tcache取出size,直到tcache取完了才会到smallbin中取,这就与我们要控制counts而矛盾了。
这时候就可以想到另一个也可以申请chunk的函数——calloc
这个函数在申请的过程中,会绕过tcache进行申请,所以就可以满足我们需要构造的条件了(控制counts)。
例题:BUUOJ-2020 新春红包题-3
题目分析:可以看参考链接1里面的内容,写的相当好。
EXP
|
|
参考
ERROR404 - Tcache Stashing Unlink Attack利用思路:https://www.anquanke.com/post/id/198173
hitcon-ctf-2019(fq):https://medium.com/@kteCV2000/hitcon-ctf-2019-quals-one-punch-man-pwn-292pts-3e94eb3fd312