文章目录
本文涉及的libc版本为libc-2.23和libc-2.27
fastbin
malloc
在从free fastbin从取出空闲块malloc的时候,会有如下比较
比如说我们实际需要的块大小(包括header是0x40),那么只要当前将要被取出的free fastbin size在0x40~0x4f之间,就可以通过比较,不然就报错
一般在double free的时候,我们可以把指针改到libc里面,这样就可以任意地址写,但在把这个地址malloc出来的时候会做一遍大小check,所以一般fastbin attack需要分配到malloc_hook-0x23,这里对应的size是0x7f,只要我们malloc(0x68)就可以过了check
fastbin通过NULL判断是否为空
这一点很有意思,tcache里面会额外记载空闲的数量(这当然是一个进步),而fastbin不会,他会每次malloc的时候取出当前free fastbin的fd指针作为fastbinY的值,只要这个值不为0,他就认为里面还有空闲的块,就还可以继续分配
这一点攻击区别也是体现在double free上面,对于tcache的double free,你要保证count>=0,不然就算有你也malloc不出来,而fastbin则不是,只要你把fastbin的单向链表修改了,你一定可以malloc出来(当然要过size的check)
free
在free的时候会做如下的check防止double free
比较当前要被free的指针和对应fastbinY最外侧的指针,如果一样就报错
那么绕过就很简单,中间随便再free一个就好
检查当前要free的fastbin紧挨着的的下一块
根据p+size来寻找下一个chunk,比较这个chunk的size是否合理
所以一般最好伪造块的时候还是要保证前后块的连续性
如果我们在堆溢出的时候随便修改了size,导致它下一块不是个正常的块,我们就会报错
tcache
malloc
在libc2.27中,这里的tcache几乎没有检查
只要当前malloc的大小再tcache里面并且对应的tcache的堆地址>0(额这个check有点emm不太明白,难道是呼应之前的if判断),就会去get
里面只有两个assert,而且一个assert还是做过的,他只判断了对应的堆地址是不是大于0,然后就会给你malloc出来
所以我们如果double free之后修改了tcache->entries,不用像fastbin一样还要考虑大小是否匹配,直接指向free-hoook就ok
这里注意在libc.2.30之前不会check tcache的count,就算你是0也可以分配的,在2.30之后会check count,如果count不够就无法分配
free
几乎也没有检查
这里就是如果在tcache范围并且对应的还有空闲,就放进去
只有一个assert,就是是否在范围内,可以看到它没有检查double free,所以对于这个版本的tcache,我们可以直接free一个块n次