large_bin_attack1
largebin_运行机制
- 前提:
largebin与smallbin有点类似,都是两个bins管理一组堆块。但是也存在不同点,largebin是管理一定size范围的堆块,而smallbin是管理固定size的堆块,这里在glibc中的bins其实就是smallbin、largebin堆块的总和。 - 这里
乘2的意思其实就表示着俩个bins组合成一个smallbin或者一个largebin,其中一个bin用于指向最后被释放的堆块,另一个bin用于指向最先被释放的堆块,这样其实就构成了一个双向链表。
1 | // 两个数组宏定义 |
- 我们先使用一个程序,查看一下bins的结构吧
1 |
|
- 直接动调到
malloc(0x780)这边,查看堆块我们就会发现如下堆块信息,fd_nextsize、bk_nextsize竟然已经被启用了。

- 我们查看
bins,还会发现一些信息,信息如下,注意到如下要点:largebin中的堆块,一个bins管理的是一定范围内size的堆块,而不是管理固定大小的堆块(像0x70、0x80)这样

- 接下来我们就以
0x700-0x730的这个bins做个例子,画个图之后再来详细描述一下bins的结构。下面给出0x710、0x720、0x730的三个堆块,结合上图的bins链表,我们就可以画出一个简单的bins堆块结构的图片

- 我们bins结构的图片如下,这样其实看不出什么东西,主要简单介绍一下有这么一个结构

bins中的结构
- 对于
largebin如果是被释放的状态,并且已经被放入了largebin这个链表中,那该堆块的结构就与放入其他bins的堆块结构不同。 - 一般我们放入其他
bins的堆块,其chunk的结构是如下的。
1 | struct chunk{ |
- 而我们处于
largebin中的堆块,其结构是像这样的一个结构,其实也就是堆块结构中的fd_nextsize和bk_nextsize这两个结构被启用了。
1 | struct chunk{ |
nextsize链接机制
情况1
- 正如上图所示,
nextsize是连接的是同一个bins中,size大小相邻的堆块。由于large_bin是管理一定范围的堆块,所以我们就需要nextsize位去管理它的size位,这样才能将不同size的堆块统一管理起来。 - 接下来为了深度理解一下
nextsize的链接机制,我会给出几种情况的例子,以便于我们更好理解。接下来就是第一种情况,一个large_bin中,有多个相同大小的堆块,此时我们的nextsize应该如何。
1 |
|
- 我们执行完
malloc(0x780)后查看堆块布局,此时我们发现只有在我们最先释放的堆块中,启用了fd_nextsize、bk_nextsize,但是我们释放的堆块中并没有不同size大小的堆块,所以我们就会导致,我们的fd_nextsize、bk_nextsize都会指向自己。


情况2
- 如果我们不同
size的大小相互交替进行释放,该堆块的布局会是这样的。
1 |
|
- 接下来我们查看一下这个堆块的布局,我们发现我们释放两个大小相同的堆块,但是我们的
fd_nextsize和bk_nextsize只有最先释放的堆块被启用

- 接下来我们查看一下
bins的结构,此时我们bins的结构可以做如下总结:chunk的size位越大的chunk,逻辑位置更靠近largebin,chunk的size位越小的chunk,更远离largebin- 相同
size位越大的chunk,越迟释放的chunk,越远离largebin,而越早释放的chunk,越靠近largebin的大小

- 接下来我们给出
nextsize的逻辑结构

情况3
- 我们接下来查看一下
4个不同大小的chunk释放之后nextsize的逻辑结构。
1 |
|
- 调试发现如下图所示:


- 再来查看一下bins的堆块结构

- 接下来我们就来描述一下bins中
nextsize的逻辑结构

实验
- 了解了
large_bin的运行机制后,我们就可以进行如下实验,学习一下large_bin攻击 - 这里是
glibc2.31以前版本的利用,接下来还有一个glibc2.31版本以上的堆利用(这个利用与高版本堆利用很多打法都相关,所以要好好学习一下。)
源码(英文)
1 | /* |
源码(中文)
1 | /* |
布置堆和栈结构
- 首先我们先选择一个劫持的目标,这里我们选择栈上的一块地址,由于我关闭了地址随机化技术,所以这块地址在本地调试的时候是静止不变的。
- 此时我们选定了如下俩个栈地址,具体请看下图


- 接下来我们申请一个
0x420大小的堆块,这个大小的堆块被释放后就先会被放入到unsorted_bin中,在之后一次程序调用malloc如果该堆块没有被切割,它就会被放入对应的largebin中



- 由于这样大小的堆块在释放后就很容易触发
unlink从而和其他堆块进行合并操作,所以我们为了避免该堆块被合并,导致没法进入lareg_bin这个堆块中,此时我们就申请一个0x20的堆块,使用该堆块将size=0x430的堆块物理内存进行隔离操作 - 这里节省画图空间就将一下没必要的先节省一下


- 接下来我们按照
malloc大小为0x500、0x20、0x500、0x20这样的顺序申请四个堆块,此时我们的堆块物理结构就如下图所示。



- 此时我们的堆就布置好了,现在我们就要开始进行
largebin_attack的进一步利用了。
释放堆块
-
接下来我们要先将第一次申请的
0x430大小的堆块给释放了,再将第二次申请的0x510的堆块给释放了,使得这两个堆块被放入unsortedbin中 -
如下图所示:



- 接下来我们先申请一个
0x90大小的堆块,此时我们0x430大小的堆块就会被切割一部分下来,并且还继续被放在unsorted_bin中 - 但是
size = 0x510的这个堆块就会被放入到largebin中去



- 完成以上操作后,我们再释放第三次malloc出来的堆块,大小为
size=0x510,这个时候该堆块会被放入到unsortedbin中去,此时堆块的布局如下:



修改size、bk、bk_nextsize
- 释放堆块到如上布局后,我们就要来修改释放后堆块的一些指针和
size位,这一步就是攻击的重点步骤。 - 根据
how2heap这个代码,我们就会发现我们要修改的是第一个申请的堆块,也就是已经被放入large_bin中的这个堆块

- 我们在图上将这个堆块要修改的部分标红,查看一下哪些部分需要修改。


- 修改之后我们再申请一个
0x90大小的堆块,这个时候我们的堆块布局是这样的,此时我们仍然从第一次申请的堆块即size=0x430这个堆块切割内存下来分配。

- 所以此时我们第三个申请的堆块即
size=0x510大小的堆块就会被放入large_bin中去,但是由于我们伪造了bk指针和bk_nextsize这个指针,所以我们此时bins结构如下,并且我们发现栈上的值已经被我们修改成了0x6039a0


- 这样的来自于源代码的这样一个段,也就是在将处于
large_bin大小的堆块,并被释放到unsorted_bin的堆块被放入到large_bin中的更新链表的操作
1 |
|
图解攻击利用
- 这个时候堆块是这样的


large_bin_attack_leve_2
-
题目来源:
2019年西湖论剑初赛Storm_note -
题目附件这里可以获取:[原创]西湖论剑storm_note Large bin Attack-Pwn-看雪-安全社区|安全招聘|kanxue.com
large_bin_attack_level_2
- 题目来源:
2019 RCTF babyheap - 附件可以在这里获取:BUUCTF在线评测
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 iyheart的博客!

