Dance In Heap(三):一些堆利用的方法(中)

0x00 前面的话

在前一篇堆的利用方法里面,我们简单的提了一下UAF,并主要对从 bin 中释放 chunk 的操作,即 unlink 宏、unsortedbin attack,进行了利用。那么在本篇中,我们主要讨论如何将对一个对一个chunk进行复用来进行某种攻击。

在这里面我们要当心,chunk size的计算是个需要小心的地方,因为这里包括了 prev_size的复用,以及根据不同系统考虑的对齐情况,还有 chunk 的size位表示的是包括chunk header在内的size,而实际可用的size与此不同,它是减去chunk header后的大小。

本篇文章目录

0x01 fastbin attack
0x02 overlapping chunk 1
0x03 overlapping chunk 2
0x04 小结

0x01 fastbin attack

还记不记得我们在第一篇中那个介绍 fastbin 中 dobule free的例子

#include <stdio.h>
#include <stdlib.h>
int main() {
    char *a=malloc(24);
    char *b=malloc(24);
    free(a);
    free(b);
    free(a);
}

这个运行是没有问题的,但是想象一下,这样做之后,现在的 fastbin 中是什么样子

  -------     -------     -------     -------    -------
 | 头结点 |-> |   a   |-> |   b   |-> |   a   |->|  null |
  -------     -------     -------     -------    -------

其中的指向关系由chunk的 fd 指针标识。此时我们再从 fastbin中 malloc 出一个 chunk

c = malloc(24);

此时的 fastbin

  -------     -------     -------     -------
 | 头结点 |-> |   b   |-> |   a   |-> |  null |
  -------     -------     -------     -------

现在我们得到了一个chunk,并且这个 chunk 同时在 fastbin中也存在,那么此时如果我们修改 c 的 fd 指针位置为任意地址,那么 fastbin 中 a 的指向也会发生改变

  -------     -------     -------     -------
 | 头结点 |-> |   b   |-> |   a   |-> |任意地址|
  -------     -------     -------     -------

我们之后连续 malloc 两次

malloc(24);
malloc(24);

现在的 fastbin

  -------     -------
 | 头结点 |-> |任意地址|
  -------     -------

那我们再次 malloc 时,就可以在任意地址创建一个 chunk 了,但是要注意的是,我们在之前提到过,从 fastbin 中取出 chunk 的时候会对 chunk 的size 做检查,也就是这个任意位置的 chunk 的 size 位必须构造。我们可以在栈中构造

int stack = 0x30 // 24 + header = 0x28 ,0x10 对齐后 0x30

这个变量作为size位,我们可以将任意地址填充为 &stack - 8,然后 malloc 之后会返回这个地址的 chunk,在栈中变量无法溢出时,我们可以向 chunk 里面写入数据来造成栈溢出。

d = malloc(24);
d[20] = 0xdeadbeef //控制rip

fastbin attack 中令人兴奋的一点是,它不需要对 chunk 进行溢出就可以进行攻击,这在一些对输入长度检查严格的地方可以得到奇妙的应用。

0x02 overlapping chunk 1

幸运的是,并不是所有的程序都会对输入长度有严格的约束,当我们能够溢出到下一个 chunk 时,我们可以修改它的 size 位来造成 chunk 的覆盖。

首先,我们创建三个chunk,考虑 prev_size 的复用和 0x10字节对齐,我们将 malloc(0x100-8), 系统会给我们(0x100-8)+0x10-0x8,即0x100(0x10对齐)的空间,实际可用的空间正好是0x100-8,并没有多分配,而要是malloc(0x100)的话,你会看到实际可用的空间是0x108(这个不是必须的,只是向大家强调一下 chunk 大小的计算)

a = malloc(0x100-8);
b = malloc(0x100-8);
c = malloc(0x100-8);

然后 free 掉 b,b就会放到 unsortedbin 中 ,这个bin只有一个链表,并不对size进行区分,所以我们可以放入0x100的chunk,修改为size为0x180后就可以拿出0x180的chunk

free(b);

然后我们利用a溢出到b的size位

*(a+0xf8) = 0x181 // 0x01标识a为inuse状态

现在我们malloc一个0x180的 chunk,系统就会将从b开始的0x180大小的空间返还,这其中包括c

d = malloc(0x180-8);

ok,现在我们就可以更改利用d更改c中的内容,如果c中包含某个函数指针,我们也可以去改变它,当然

0x03 overlapping chunk 2

我们在前面先释放再修改size来获得了一个覆盖掉后面chunk 的 chunk,那么如果我们先修改size为一个大值,然后free会怎样呢?

首先我们创建4个chunk

a = malloc(0x100-8);
b = malloc(0x100-8);
c = malloc(0x100-8);
d = malloc(0x100-8);// 第四个为了防止被top chunk 合并,以及应对 free的检查

我们通过a溢出到b的size

*(a+0xf8) = 0x201 // 0x1为inuse标识

我们这里讲b的size扩大到了c,由于free时需要检查下一个chunk的size,所以我们预留了d,并且防止free后直接与top chunk合并,之后我们free掉b,然后再次malloc就又包括了c

free(p);
e = malloc(0x200-8);

然后就可以可以像0x02一样去利用。

0x04 小结

除了这些之外,我们还可以根据不同的条件去构造不同的chunk复用,像是只利用一个字节溢出(off-by-one)来使chunk size减小,以此来构造的poison_null_byte 漏洞等等。了解chunk复用的原理,就是去改变 size 位来使系统对错误的长度进行 malloc、free,这就是我们的目的。

原文发布于微信公众号 - FreeBuf(freebuf)

原文发表时间:2017-10-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java成长之路

五、Java对象的访问定位

Java对象在访问的时候,我们需要通过java虚拟机栈的reference类型的数据去操作具体的对象。由于reference类型在java虚拟机规范中只规定了一...

1512
来自专栏对角另一面

lodash源码分析之缓存方式的选择

每个人心里都有一团火,路过的人只看到烟。 ——《至爱梵高·星空之谜》 本文为读 lodash 源码的第八篇,后续文章会更新到这个仓库中,欢迎 star:po...

3419
来自专栏CodingToDie

java 代理

java 代理 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额...

3484
来自专栏程序员互动联盟

【答疑释惑】java中的全局变量

首先,java中是没有全局变量这个概念的,java程序中不能像C++那样在类外定义全局变量,因为JAVA当初出现的初衷就是为了安全性和跨平台性,所以去掉了类似C...

39111
来自专栏IMWeb前端团队

Nodejs进阶:服务端字符编解码&乱码处理

本文作者:IMWeb 陈映平 原文出处:IMWeb社区 未经同意,禁止转载 写在前面 在web服务端开发中,字符的编解码几乎每天都要打交道。编解码一旦...

33010
来自专栏Python中文社区

Python3.7 contextvars 初探

Python 3.7 于2018年6月27日发布,本篇文章将对其中新增模块contextvars 做初步介绍,为读者勾勒一个大概轮廓。

1435
来自专栏大数据架构师专家

Python操作Redis的最佳实践

4154
来自专栏Small Code

Python中strptime的简单使用

strptime是python datetime库中的函数,用于将一个日期字符串转成datetime日期格式便于后期处理,使用格式为datetime.strpt...

2278
来自专栏C/C++基础

C++中关于main函数的几点说明

main函数是C++程序的入口函数,C++标准要求main()函数的返回值类型为int。

792
来自专栏Java开发者杂谈

Python(1):入门

安装:    在linux中一般都自带有python2.7的版本,如果想升级python到最新的版本可以参考其他博客(http://www.cnblogs.c...

3658

扫码关注云+社区