chunk extend and overlapping
本来打算先写off-by-one和unsorted bin atack的…但是鉴于off-by-one和overlapping的联系以及,,,unsorted bin attack..看起来好像真的用处颇少…于是就偷懒先写这个了(逃
chunk extend
chunk的拓展?? 是叫这么魔性的东西吗….大概是对下一个chunk有什么操作吧QAQ,打扰了…
功能
- 泄露地址
- Libc地址
- heap地址
- 泄露数据
- 泄露已经释放的堆中的数据
- 泄露chunk内的内容
- 覆盖指针
利用条件
- 有堆的漏洞
- 可以改变下一个chunk的header域
一般就用在off-by-one了吧..绝配
利用原理
我们知道我们释放的堆块是先不还给操作系统而是由ptmalloc来接管的
而ptmalloc在获取chunk大小时的代码如下:1
2
3
4
5/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask(p) & ~(SIZE_BITS))
/* Like chunksize, but do not mask SIZE_BITS. */
#define chunksize_nomask(p) ((p)->mchunk_size)
- 全部获取
- 忽略源码
而获取下一块chunk地址代码如下:1
2/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr)(((char *) (p)) + chunksize(p)))
也就是当前块地址+当前块大小
上一块chunk地址:1
2
3
4
5
6/* Size of the chunk below P. Only valid if prev_inuse (P). */
#define prev_size(p) ((p)->mchunk_prev_size)
/* Ptr to previous physical malloc_chunk. Only valid if prev_inuse (P). */
#define prev_chunk(p) ((mchunkptr)(((char *) (p)) - prev_size(p)))
当前块-上一块大小
判断是否inuse1
2#define inuse(p)
((((mchunkptr)(((char *) (p)) + chunksize(p)))->mchunk_size) & PREV_INUSE)
查看prev_inuse域,此域为1即为inuse
小总结
也就是说,对于如何判断本chunk相邻chunk的地址完全是通过size来确定的,因而给了我们机会,前辈们真的tql…
利用姿势
这里引用了ctf-wiki的代码,并且我做了一点点小修改:
inuse状态下
- fastbin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <stdlib.h>
#include <stdio.h>
int main(void)
{
void *ptr,*ptr1;
ptr=malloc(0x10);
malloc(0x10);
printf("[*]ptr:%p\n",ptr);
*(long long *)((long long)ptr-0x8)=0x41;
free(ptr);
ptr1=malloc(0x30);
printf("[*]ptr1:%p\n",ptr1);
return 0;
}
}
我在第一次malloc处下了断点,然后我们来看看现在堆的情况:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x20fe1
}
0x602020 PREV_INUSE {
prev_size = 0,
size = 135137,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
发现此时的size是0x21…这里还是想吐槽一些pwndbg把size部分改成了十进制..真的苟..这个docker我忘记改代码了…
然后程序继续1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
240x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602020 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x20fc1
}
0x602040 PREV_INUSE {
prev_size = 0,
size = 135105,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
可以看到这里已经分配完了,此时的堆1
2
3
4
5
6pwndbg> x/10gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000020fc1
没有问题,下一步进行size的改写,至于为什么是chunk-8呢,因为我们知道chunk给我们的地址其实是mem的地址,也就是0x602010处,因此减8可以到pre_size处1
2
3
4
5
6
7
80x602000 FASTBIN {
prev_size = 0,
size = 65,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
这里已经改写成功了,此时的heap分析出来的是这样的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 65,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602040 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x303a7274705d2a5b,
bk = 0x6666666666663778,
fd_nextsize = 0xa3836356566,
bk_nextsize = 0x0
}
0x602450 PREV_INUSE {
prev_size = 0,
size = 134065,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
成功通过size欺骗到了ptmalloc机制1
2
3
4
5
6
7
8pwndbg> x/14gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000041
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411
0x602050: 0x303a7274705d2a5b 0x6666666666663778
0x602060: 0x00000a3836356566 0x0000000000000000
然后我们让程序到下一个分配1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 65,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602040 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x303a7274705d2a5b,
bk = 0x6666666666663778,
fd_nextsize = 0xa3836356566,
bk_nextsize = 0x0
}
0x602450 PREV_INUSE {
prev_size = 0,
size = 134065,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
此时这里虽然没变,但是1
2pwndbg> p/x ptr1
$4 = 0x602010
也就是说我们成功分配了free掉的chunk1
程序运行结果:1
2
3╰─# ./fast_in
[*]ptr:0x180e010
[*]ptr1:0x180e010
- smallbin
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <stdlib.h>
#include <stdio.h>
int main()
{
void *ptr,*ptr1;
ptr=malloc(0x80);
malloc(0x10);
malloc(0x10);
*(long long *)((long long)ptr-0x8)=0xb1;
// printf("[*]%p\n",&ptr);
printf("[*]%p\n",ptr);
free(ptr);
ptr1=malloc(0xa0);
printf("[*]%p\n",ptr1);
}
程序运行结果:1
2
3╰─# ./pwn
[*]0x7a3010
[*]0x7a3010
这个程序就不做深入分析了,和fastbin的一样
free状态下
1 |
|
程序运行结果:1
2
3╰─# ./pwn
[*]ptr:0x149b010
[*]ptr:0x149b010
这个就是先释放,然后才进行大小的更改
通过extend后向overlapping
1 |
|
我在第一次分配处下了断点,此时的堆:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x20fe1
}
0x602020 PREV_INUSE {
prev_size = 0,
size = 135137,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
随后分配完全结束时我们再看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
33
34
35
36
37
38
39
40
41pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602020 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602040 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602060 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x20f81
}
0x602080 PREV_INUSE {
prev_size = 0,
size = 135041,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
这时:1
2
3
4
5
6
7
8
9
10
11pwndbg> x/20gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000021
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000020f81
0x602090: 0x0000000000000000 0x0000000000000000
随后我们更改了size的大小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
33pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 97,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602060 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x411
}
0x602080 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x303a7274705d2a5b,
bk = 0xa30313032303678,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602490 PREV_INUSE {
prev_size = 0,
size = 134001,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
free之后我们可以看到: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
33pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 97,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602060 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x411
}
0x602080 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x303a7274705d2a5b,
bk = 0xa30313032303678,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602490 PREV_INUSE {
prev_size = 0,
size = 134001,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
再分配一次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
33pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 97,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x602060 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x411
}
0x602080 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x303a7274705d2a5b,
bk = 0xa30313032303678,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602490 PREV_INUSE {
prev_size = 0,
size = 134001,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
此时1
2
3
4
5
6
7
8
9
10
11pwndbg> x/20gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000061
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000021
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000411
0x602090: 0x303a7274705d2a5b 0x0a30313032303678
这时就可以进行fastbin attack了
通过extend进行前向合并
之前的后向合并都是通过更改size实现的,但extend的前向合并则不一样,但原理是类似的
后向合并是通过更改size实现的,而前向合并顾名思义需要我们更改pre_size才行1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include<stdlib.h>
#include<stdio.h>
int main(void)
{
void *ptr1,*ptr2,*ptr3,*ptr4,*ptr5;
ptr1=malloc(128);//smallbin1
ptr2=malloc(0x10);//fastbin1
ptr3=malloc(0x10);//fastbin2
ptr4=malloc(128);//smallbin2
malloc(0x10);//防止与top合并
printf("[*]ptr1:%p\n",ptr1);
printf("[*]ptr2:%p\n",ptr2);
printf("[*]ptr3:%p\n",ptr3);
printf("[*]ptr4:%p\n",ptr4);
free(ptr1);
*(long long *)((long long)ptr4-0x8)=0x90;//修改pre_inuse域
*(long long *)((long long)ptr4-0x10)=0xd0;//修改pre_size域
free(ptr4);//unlink进行前向extend
ptr5=malloc(0x150);//占位块
printf("[*]ptr5:%p\n",ptr5);
}
先看程序的运行结果:1
2
3
4
5
6╰─# ./pwn
[*]ptr1:0x10c2010
[*]ptr2:0x10c20a0
[*]ptr3:0x10c20c0
[*]ptr4:0x10c20e0
[*]ptr5:0x10c2010
然后再调试一下,这次我断点下在了第一free的地方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
33
34
35
36
37
38
39
40
41pwndbg> heap
0x602000 PREV_INUSE {
prev_size = 0,
size = 145,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602090 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x21
}
0x6020b0 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x91
}
0x6020d0 PREV_INUSE {
prev_size = 0,
size = 145,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602160 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x411
}
可以看到我们的符合smallbin和fastbin的四个chunk已经分配完成了,然后先free掉ptr1,修改ptr4的pre_inuse和pre_size1
2
3
4
5
6
7
8
9
10
11pwndbg> x/20gx ptr4-0x10
0x6020d0: 0x00000000000000d0 0x0000000000000090
0x6020e0: 0x0000000000000000 0x0000000000000000
0x6020f0: 0x0000000000000000 0x0000000000000000
0x602100: 0x0000000000000000 0x0000000000000000
0x602110: 0x0000000000000000 0x0000000000000000
0x602120: 0x0000000000000000 0x0000000000000000
0x602130: 0x0000000000000000 0x0000000000000000
0x602140: 0x0000000000000000 0x0000000000000000
0x602150: 0x0000000000000000 0x0000000000000000
0x602160: 0x0000000000000000 0x0000000000000021
这里已经改好了,然后进行free(ptr4),此时的heap1
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
33pwndbg> heap
0x602000 PREV_INUSE {
prev_size = 0,
size = 353,
fd = 0x7ffff7dd1b78 <main_arena+88>,
bk = 0x7ffff7dd1b78 <main_arena+88>,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602160 {
prev_size = 352,
size = 32,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x411
}
0x602180 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x3a347274705d2a5b,
bk = 0x3065303230367830,
fd_nextsize = 0xa,
bk_nextsize = 0x0
}
0x602590 PREV_INUSE {
prev_size = 0,
size = 133745,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
此时的bins:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
smallbins
empty
largebins
empty
然后再分配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
33pwndbg> heap
0x602000 PREV_INUSE {
prev_size = 0,
size = 353,
fd = 0x7ffff7dd1b78 <main_arena+88>,
bk = 0x7ffff7dd1b78 <main_arena+88>,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602160 FASTBIN {
prev_size = 352,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x411
}
0x602180 PREV_INUSE {
prev_size = 0,
size = 1041,
fd = 0x3a347274705d2a5b,
bk = 0x3065303230367830,
fd_nextsize = 0xa,
bk_nextsize = 0x0
}
0x602590 PREV_INUSE {
prev_size = 0,
size = 133745,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
成功跨多域进行分配1
2
3
4
5
6pwndbg> x/10gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000161
0x602010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
over~ 得,乖乖回去写off-by-one去了
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!