fastbin_attack系列
fastbin_attack
Introduction
fastbin attack指所有基于fastbin机制的漏洞利用方法,利用前提:
- 存在堆溢出、uaf等能控制chunk内容的漏洞
- 漏洞发生于 fastbin类型的chunk中
细分可做到如下分类
- Fastbin Double Free
- House of Spirit
Fastbin Double Free 和 House of Spirit 侧重“正常由用户创建的chunk”和“由攻击者伪造的chunk”,然后再次申请chunk进行攻击
- Alloc to Stack
- Arbitary Alloc
Alloc to Stack 和 Arbitary Alloc 侧重利用堆溢出等方式修改chunk的fd指针,即直接申请指定位置的chunk进行攻击
Principle
if a chunk is freed and goes into fastbin the prev_inuse flag of the next heap will not be cleared
PREV_INUSE(abbreviated as P,in the lowest bit of the chunk size field)
Record whether the previous chunk block is in the allocated state.In general,the P-bit of the size field of the first allocated memory block in the heap is set to 1 to prevent access to the previous illegal memory. When the P-bit of a chunk is 0,we can use the prev_size field to get the size and address of the previous chunk.This also facilitates merging between idle chunks.


1. double free
- Once the fastbin’s heap is freed the P-bit of the next chunk will not be emptied
- when free fastbin,just verify the chunk that the main arena points to,i.e.,the chunk at the head of the linked list pointer.For the chunks behind the linked list,there’s no validation.
https://xuanxuanblingbling.github.io/assets/pwn/paper
example
paper
withoutlink_list[del_index]=NULL,UAF
利用思想: 利用fastbin的free只检查是否和上一个freechunk相等,使得同一个chunk两次进入free list,造成UAF,可以更改fastbin free chunk的fd信息,最终分配一个特定地址
利用难点
需要能够两次free同一个chunk
更改fd的时候,为了能够在之后的malloc之后返回这个值,需要通过一个check,会检查fd指向的这个位置的size(这个位置可以不用对齐),看是否属于正要malloc的这个bin的范围。
详细信息
其漏洞的主要原因在于fastbin
的实现其实是一个单链表实现的栈,后进先出,free的时候只检查了这个栈的栈顶,这样的话,
只要不是连续的free两次同一个chunk,就可以顺利的将一个chunk放进free list。之后的分配会使得
chunk虽然在free list里,但是也被分配了出来,这样就可以更改到fd指针,使其指向其他位置。
检查栈顶的代码如下:
/* Check that the top of the bin is not the record we are going to add
(i.e., double free). */
if (__builtin_expect (old == p, 0))
{
errstr = "double free or corruption (fasttop)";
goto errout;
}
需要注意的一点是,在分配的时候还有一个检查:
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
{
errstr = "malloc(): memory corruption (fast)";
errout:
malloc_printerr (check_action, errstr, chunk2mem (victim), av);
return NULL;
}
check_remalloced_chunk (av, victim, nb);
这个检查是指即将分配的这个chunk大小应该在其相应大小的idx上,比如size都为0x20大小的
fastbin,能够接受的值就是0x20-0x27范围,分配过去应该有这个范围的值(被当做size),
否则将会出现memory corruption。
所以利用的时候需要想办法找到一个相应的size,这个size其实是不需要对齐的(just check low 4 bytes),所以可以通过
错位的方式构造一个假的size值出来。找到相应的size就可以进行分配到相应位置了。
exp
from pwn import * |
2. House of Spirit
principle
The key to using house of Spirit is the ability to override a heap poiont(the address that malloc_data returned in the chunk after calling malloc)to point an area can be controlled.
- 伪造堆块
- 覆盖堆指针指上一步伪造的堆块
- 释放堆块,将伪造的堆块放入fastbin的单链表里面(绕过检测)
- 申请堆块,释放刚才申请的堆块,最终可以使向目标区域中写入数据,以达到控制内存的目的
一般来说想要控制的目标区域多为返回地址或是一个函数指针,正常情况下,该内存区域我们是无法通过输入数据来进行控制的,想要利用hos攻击技术来改写该区域,首先需要我们可以控制那片目标区域的前面空间和后面空间。

free时需要被绕过的检测
fake chunk的ISMMAP位不能为1,free时,mmap的chunk会单独处理fake chunk地址对齐,MALLOC_ALIGN_MASKsize大小要满足对应fastbin的需求,同时也得对齐fake_chunk的next chunk的大小不能小于2*SIZE_SZ,同时也不能大于av->system_memfastbin的链表头部不能是该fake_chunk,否则不能构成double free
summary
总的来说,houseofspirit的主要意思是我们想要控制的区域控制不了,但是它前面和后面都可以控制,所以伪造好数据将它放入fastbin中,后面将该内存区域当作堆块申请出来,致使该区域被当作普通的内存使用,从而使目标区域变成可控的。
example
LCTF 2016 : PWN200 - 吾爱破解 - 52pojie.cn
2016-iscc-pwn200

循环48次,分配了48字节,填满由于printf的特性(打印直到\x00)可以泄露ebp
如果输入0x38位,那么实际输入的会是0x39位,因为read函数也会将’/n’输入到内存中,结果是会覆盖掉dest最低的一个字节,导致不能查看堆信息。

溢出

exp
输入name的时候,将shellcode输入,并补齐0x30字节,以通过off-by-one漏洞泄漏rbp地址;

输入money的时候,在money里伪造chunk,注意要绕过free函数的检查。并通过相邻变量覆盖漏洞覆盖dest指针,将其覆盖为fake chunk的user data地址,那么输入完之后,dest指针赋值给ptr,ptr也指向fake chunk的user data地址。

框中依次为size,return_address,shellcode
调用checkout,将伪造chunk放入fastbin中,并置ptr指针为NULL;

fastbins中有了栈地址。申请0x30大小即可将其申请出来
该地址+0x10即为用户区
填充0x18的nop,再写入shellcode的地址即可让程序转而执行shellcode调用checkin,因为ptr==NULL,将重新malloc指定大小的chunk并输入数据,此时,便可以malloc可控1区域下方的不可控区域,覆盖input_number_and_menu函数的返回地址为shellcode地址;
看到返回地址已经变为shellcode地址退出时choose函数跳转去执行shellcode。getshell!

from pwn import * |
Alloc to Stack
模拟样例
|
Arbitrary Alloc
要利用Alloc to Stack这个条件,对应的堆的地址必须要有合法的size,这样才能将堆内存分配到栈中,从而控制栈中的任意内存地址。而这个ArbitraryAlloc和AlloctoStack基本上完全相同,但是控制的内存地址不在仅仅局限于栈,而是任意的内存地址,比如说bss、heap、data、stack等等。
模拟示例:
|

错位构造出一个0x00……007f,计算出的chunk的大小为0x70,包含0x10的chunk_header,分配0x60的内容。
free之后伪造fd为0x7ffff7dd1af5 - 0x8,2次malloc后出现的地址就会是0x7ffff7dd1af5 + 0x8此时堆内存已经分配到了栈上,并且可以继续向下延伸控制栈空间。
example

分析
对主要的函数进行分析,
并简单修正IDA反编译结果,看起来舒服多了
主要函数为Allocate,Fill,Free,Dump

这里让我们重新输入Size,但是没有修改chunk的size域,所以我们可以进行任意堆溢出
我们希望使用unsortedbin来泄漏libc基地址,所以必须要有chunk可以被链接到unsorted bin中,所以该chunk不能被回收到 fastbin chunk,也不能和 top chunk相邻。因为后者在不是fastbin的情况下,会被合并到top chunk中。
exp
参考exp如下:
from pwn import * |