chunk extend/overlapping

本文的思路来自:https://blog.csdn.net/qq_41202237/article/details/108320408

hollk tql

学习一下chunk extend/overlapping吧

Chunk Extend and Overlapping

chunk extend 是堆漏洞的一种常见利用手法,通过 extend 可以实现 chunk overlapping 的效果。这种利用方法需要以下的时机和条件:

  • 程序中存在基于堆的漏洞
  • 漏洞可以控制 chunk header 中的数据

1:对inuse的fastbin进行extend

直接来个源码吧

1
2
3
4
5
6
7
8
9
10
11
12
//gcc -g z1r01.c -o z1r01
#include<stdio.h>
int main(void)
{
void *p, *q;
p = malloc(0x10);//分配第一个0x10的chunk
malloc(0x10);//分配第二个0x10的chunk
*(long long *)((long long)p - 0x8) = 0x41;// 修改第一个块的size域
free(p);
q = malloc(0x30);// 实现extend,控制了第二个块的内容
return 0;
}

libc-2.23.so的版本来gdb吧

因为我们在gcc阶段使用了-g所以我们可以在gdb中使用b + 行号在任意行号进行gdb。在第8行下个断点gdb一下

因为堆块的结构分为prev_size、size、块内容,拿上面这个64位程序举例:malloc(0x10)其中的0x10指得是内容部分申请0x10大小的空间,,prev_size和size部分各占8个字节,size记录的是整个堆块的大小,并且size的最后一位用来记录前一个块的状态,所以
size = 0x8(prev_size) + 0x8(size) + 0x10(内容) + 0x1(标志位) = 0x21

接下来我们在第9行下断点b 9执行*(long long *)((long long)p - 0x8) = 0x41,依然还是在这个位置看两个块有什么变化,p指针指向的地址再减0x8的位置修改成0x41,也就是说chunk1的size从0x21被修改成0x41。整整扩大了32字节,chunk1与chunk2的范围如下图所示:

但是这样一看,chunk1的0x41却包含了下面的chunk2。接下来直接第十行下个断点看一下。

执行了free(p)。可以看到两个块直接被合并成了一个块都进了fastbin这里

接下来直接十一行下断点

最后我们重新申请一个大小为0x30的chunk时,fastbin中刚好有合适的大小块,这个时候chunk1与chunk2合并的chunk就会重新被启用,启用的同时原有chunk2中的内容也会连带着被启用,这个时候就可以直接通过这个新申请的块来对chunk2中的内容进行操作了


2:对inuse的smallbin进行extend

话不多说上源码

1
2
3
4
5
6
7
8
9
10
11
12
//gcc -g z1r02.c -o z1r02
#include<stdio.h>
int main()
{
void *p, *q;
p = malloc(0x80);//分配第一个 0x80 的chunk1
malloc(0x10); //分配第二个 0x10 的chunk2
malloc(0x10); //防止与top chunk合并
*(long *)((long)p-0x8) = 0xb1;
free(p);
q = malloc(0xa0);
}

首先在第9行下断点b 9,我们看一下申请完三个chunk之后内存中的样子:

接下来我们在第10行下断点,执行*(int *)((int)p-0x8) = 0xb1;这段代码:

可以看到chunk1和chunk2合并了

在第11行下断点:

可以看到执行了free(p);这行代码之后,原来的chunk1和chunk2合并之后直接进入了unsortedbin,至于下面的b0 20为什么会是这两个数值后面的blog再讲解,这里说一下为什么会进unstortedbin:

  • 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中
  • 释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中

继续下一行代码:

可以看到执行q = malloc(0xa0);这个之后,0xb1这个块重新被启用,这个块是由chunk1和chunk2合并起来的,在pwn题中,有show函数可以直接leak libc了

3:对 free 的 smallbin 进行 extend

话不多说直接上源码

1
2
3
4
5
6
7
8
9
10
11
//gcc -g z1r03 -o z1r03
#include<stdio.h>
int main()
{
void *p, *q;
p = malloc(0x80);//分配第一个0x80的chunk1
malloc(0x10);//分配第二个0x10的chunk2
free(p);//首先进行释放,使得chunk1进入unsorted bin
*(long *)((long)p - 0x8) = 0xb1;
q = malloc(0xa0);
}

第三个例子和前面两个有一些区别,前面两个都是先修改chunk1的size大小然后进行释放,但是这个例子是先进行释放,然后重新修改chunk1的size大小,依然还是一步一步来,首先在第8行下断点,使程序完成申请chunk的操作:

接下来我们在第9行下断点,使程序完成对chunk1的释放:

free(p)之后chunk1直接进入unstorted bin至于进这个的原因(上面写过了

接下来 我们将断点下载第10行,需要注意的是此时更改size大小的操作是在free之后完成的:

修改了大小可以看到chunk2和chunk1一起被合并进了unstorted bin了

继续代码之后不需要多想了,chunk2和chunk1(你懂的

4:通过 extend 后向 overlapping

直接上源码

1
2
3
4
5
6
7
8
9
10
11
12
13
//gcc -g z1r04.c  -o z1r04
#include<stdio.h>
int main()
{
void *z1r0, *z1r01;
z1r0 = malloc(0x10);//分配第1个 0x10 的chunk1
malloc(0x10); //分配第2个 0x10 的chunk2
malloc(0x10); //分配第3个 0x10 的chunk3
malloc(0x10); //分配第4个 0x10 的chunk4
*(long *)((long)z1r0 - 0x8) = 0x61;
free(z1r0);
z1r01 = malloc(0x50);
}

在 malloc(0x50) 对 extend 区域重新占位后,其中 0x10 的 fastbin 块依然可以正常的分配和释放,此时已经构成 overlapping,通过对 overlapping 的进行操作可以实现 fastbin attack

5:通过 extend 前向 overlapping

上源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//gcc -g test5.c -o test
#include<stdio.h>
int main(void)
{
void *z1r01, *z1r02, *z1r03, *z1r04;
z1r01 = malloc(128);//smallbin1
z1r02 = malloc(0x10);//fastbin1
z1r03 = malloc(0x10);//fastbin2
z1r04 = malloc(128);//smallbin2
malloc(0x10);//防止与top合并
free(z1r01);
*(int *)((long long)z1r04 - 0x8) = 0x90;//修改pre_inuse域
*(int *)((long long)z1r04 - 0x10) = 0xd0;//修改pre_size域
free(z1r04);//unlink进行前向extend
malloc(0x150);//占位块
}

前向 extend 利用了 smallbin 的 unlink 机制,通过修改 pre_size 域可以跨越多个 chunk 进行合并实现 overlapping