Unsorted bin
CTF pwn题堆入门 – Tcache bin
CTF pwn题堆入门 – Fast bin
CTF pwn题堆入门 – Large bin
序言
无奈于pwn题中与堆相关的东西实在是比较多,加上到了2021年的现在,ctf比赛中一来就是堆题,还都是新版本libc,对我这种新手中的新手实在不太友好,以此写下这个系列文章,记录自己学习堆漏洞利用过程中的点滴,同时也是个总结吧。结合自己做题的理解,将堆攻击常见的手段和方式按照一定的规律记录下来。
本文章系列将分成五大块,即tcache bin --> fast bin --> unsorted bin --> small bin --> large bin。
概述
Unsorted bin也是堆题中常见的,当一个堆块被释放时,且该堆块大小不属于fast bin(libc-2.26之后要填满tcache),那么在进入small bin和large bin之前,都是先加入到unsorted bin的。之后当我们需要再次分配内存时,如果tcache bin和fastbin上都找不到合适的匹配就会到unsorted bin上寻找,如果申请的内存堆块小于寻找的unsorted bin,那么会将该内存块切割后返回给用户,剩下的仍然保存在unsorted bin上;如果申请的内存堆块大于unsorted bin上存放的,那么会从Top chunk上重新分割,此时就会把unsorted bin上的堆块按照大小放回small bin和large bin中。
所以这里我们可以将unsorted bin看成一个缓存机制,这样可以加快内存的分配。除此之外,unsorted bin采用的也是双链表结构,先进先出策略,同时需要注意的是unsorted bin只有一条链,该链上会存放不同的堆块大小。
攻击方式
这里记录一下我做题常见的利用unsorted bin的方式。
unlink
接下来介绍的方法就是堆中的unlink,该机制的存在就是为了防止内存过度碎片化。当一个chunk被释放时,该chunk非fast bin,当然也不能是tcache,此时libc会检查堆块前后是否有chunk处于被释放的状态。如果存在,那么前后的堆块将会被bins中取出并进行合并,即使相邻的堆块是在fast bin或者tcache中。上述的过程就是unlink,按理说和unsorted bin没啥关系,这是系统内存整理的一种机制。不过要知道unlink之后的堆块也是放在unsorted bin中,所以将这种方法归纳在这里,具体攻击方式见下面阐述。
其实unlink方法并不能将堆分配到目标地址上,它能实现的效果是将目标地址的值修改为自身地址减去0x18(64位),这样通过在目标地址时写入值的时候加上0x18的padding就可以对该内存地址的数据进行修改,所以和分配堆块到这里的目的一样。实现unlink攻击不算复杂,但要追究其具体原理的话得看源码或者参见ctf-wiki,这里我直接展示攻击方式和效果,当大家熟悉整个过程后再看源码,想必印象更加深刻。具体操作如下代码所示:假设要分配得目标地址为ptr,该地址必须对应要修改的chunk(见代码中的ptr = malloc(0x20));然后修改伪装chunk的size大小以及其fd和bk指针,即fd = &ptr-0x18, bk=&ptr-0x10;最后修改要释放chunk的prev_size和prev_inuse。
#include <stdio.h>
#include <stdlib.h>
long long *ptr;
int main()
{
long long *ptr = malloc(0x20); // 这里非常重要,并非任意给定的地址
long long *vic = malloc(0x80);
malloc(0x1); // 防止堆块合并,同时prev_inuse也会被检查
printf("target addr is %p, value is %p\n", &ptr, ptr);
ptr[0] = 0;
ptr[1] = 0x21; // 设置size
ptr[2] = (long long)&ptr-0x18; // fd
ptr[3] = (long long)&ptr-0x10; // bk
vic<