PWN-堆基础之FastBin_Attack
FastBin_Attack
FastBin_dup
1.FastBin
fastbin采用LIFO的单链表方式管理空闲chunk,fastbin不会修改空闲chunk的prev_inuse标志位,也不会进行堆块合并。
fastbin的大小范围为0x20-0x80,共7个单链表数组(只有fd指针,即单向链表)。每个链表数组依次递增0x10大小。相同大小的chunk会被分配到同一个链表数组中。
当某个堆块被释放后,它的fd指针会指向下一个空闲chunk,arena会保存每个链表头部chunk的地址。
注:free释放堆块后,会将堆块链入到main_arena对应大小的bin中,可以用dq &main_arena 20
查看main_arean中存放的各个bin的头结点。从上到下分别对应main_arean布局中的不同大小的chunk块。
Double Free
简介
Double Free即两次释放同一个chunk,可以伪造该chunk的fd指针,在fastbin链表中增加一个fake_chunk地址,实现任意地址写。
由于libc中加入了double free缓解机制,即会检查当前释放的chunk是否和chunk头结点的chunk相同,若相同则程序终止。因此我们
可以构造如下代码段绕过double free检查机制
1 | int main() |
之所以在0x30大小的fastbin链表数组中,是因为数据块大小被分配0x20,chunk_head大小0x10。
此时,我们malloc(0x28)即可申请到chunk1,使用程序的edit修改chunk1的fd指针。
再次申请到chunk1时,继续申请chunk即可申请到fd指针指向的fake_chunk区域,实现任意地址写。
注:libc会检查申请到的chunk的大小,因此,我们需要提前伪造fake_chunk的大小(chunk_head的size域)以符合要求。
通常情况下,我们可以将__malloc_hook附近作为fake_chunk,但是我们需要找到一个合适的size域
我们可以使用find_fake_fast
这个指令查看想要修改的位置附近是否有可能存在可以伪造的chunk内存地址
可以看到,再__malloc_hook-35处是存在一个0x7f字段的,我们可以们设法把0x7f
这个位置放在size的地方再对齐,靠这个0x7f绕过free对size的检查。之所以能这样利用,是因为malloc既不检查地址对齐,也不检查size的flag标志位是否损坏。
因此完整构造如下:
1 | a=malloc(0x68) |
House of Spirit
House_of_spirit是一种fastbins攻击方法,通过构造fake chunk,然后将其free掉,就可以在下一次malloc时返回fake chunk的地址,即任意我们可控的区域。House_of_spirit是一种通过堆的fast bin机制来辅助栈溢出的方法,一般的栈溢出漏洞的利用都希望能够覆盖函数的返回地址以控制EIP来劫持控制流,但如果栈溢出的长度无法覆盖返回地址,同时却可以覆盖栈上的一个即将被free的堆指针,此时可以将这个指针改写为栈上的地址并在相应位置构造一个fast bin块的元数据,接着在free操作时,这个栈上的堆块被放到fast bin中,下一次malloc对应的大小时,由于fast bin的先进后出机制,这个栈上的堆块被返回给用户,再次写入时就可能造成返回地址的改写。所以利用的第一步不是去控制一个 chunk,而是控制传给 free 函数的指针,将其指向一个fake chunk。所以 fake chunk的伪造是关键。
通俗的来说,该攻击方法就是在可写位置伪造一个size和next_size,然后free该位置后再malloc该位置就可以实现对该区域的可控操作,即不通过malloc产生一个伪造chunk,free后利用。
要想构造 fastbin fake chunk,并且将其释放时,可以将其放入到对应的 fastbin 链表中,需要绕过一些必要的检测,即
fake chunk 的 ISMMAP 位不能为 1,因为 free 时,如果是 mmap 的 chunk,会单独处理。
fake chunk 地址需要对齐, MALLOC_ALIGN_MASK
fake chunk 的 size 大小需要满足对应的 fastbin 的需求,同时也得对齐。
fake chunk 的 next chunk 的大小不能小于
2 * SIZE_SZ
,同时也不能大于av->system_mem
。fake chunk 对应的 fastbin 链表头部不能是该 fake chunk,即不能构成 double free 的情况。
经典利用场景的条件如下
(1)想要控制的目标区域的前段空间与后段空间都是可控的内存区域
一般来说想要控制的目标区域多为返回地址或是一个函数指针,正常情况下,该内存区域我们输入的数据是无法控制的,想要利用hos攻击技术来改写该区域,首先需要我们可以控制那片目标区域的前面空间和后面空间,示意图如下。
(2)存在可将堆变量指针覆盖指向为可控区域,即上一步中的区域
利用思路:
在可控区域1伪造fake_chunk的size,并在可控区域2伪造next_chunk,free掉可控1的fake_chunk后再malloc回来,就可实现对中间原本不可控区域的控制(大多数情况为栈上的返回地址)
例题:LCTF 2016 PWN200
checksec发现NX未开启,考虑写入shellcode,但程序不存在栈溢出,因此不能直接将返回地址写为shellcode地址。
主要函数:
首先,利用输入用户名输入48个字符打印出rbp栈地址,进而获取shellcode地址(将shellcode写入栈上)。
之后,由于set_id首先调用,因此在栈上位于A29函数的高地址处,在id处伪造next_chunk_size。
最后,在A29函数中构造fake_chunk_size,构造完成后,即可实现上面可控1和可控2中间夹着返回地址,free后申请回来填充返回地址为shellcode_addr。
构造后内存如下:
其中,1为shellcode地址,2为dest指向地址,3为buf地址,4(0x….798)为A29函数的返回地址,已被覆盖成shellcode_addr,5和6分别为fake_chunk_size和next_chunk_size。
exp:
1 | from pwn import * |
当然,该题也可以不通过House of Spirit,由于strcpy处可进行任意地址修改,且got表可改,可将free_got表内容改为shellcode_addr,之后调用free。
1 | payload = p64(shellcode_addr) |