首页
社区
课程
招聘
[原创]初识堆喷射及事例(暴雷漏洞)分析
发表于: 2018-11-23 11:11 9639

[原创]初识堆喷射及事例(暴雷漏洞)分析

2018-11-23 11:11
9639

暴雷漏洞CVE-2012-1889

一.堆喷简介

打开Poc利用文件,发现使用了HeapSpray(堆喷技术),堆喷射实现的主要因素为以下两点

(堆喷射将shellcode放置在了堆中,在堆中执行代码)

1. 使用浏览器程序打开我们的poc样本时,它会执行我们样本文件中的JavaScript代码

2. 控制程序eip,使其指向0x0C0C0C0C地址

下面我们来了解一下堆喷射的实现流程

1. 我们首先创建一个大小为1mb的堆块,并使用0x0C0C0C0C填充

1.1为什么使用0x0C0C0C0C填充呢?有两点因素

(1)0x0C0C0C0C会被程序解释成 OR AL,0C 可以作为滑板指令(即执行此种指令不会对程序的后续行为产生影响),有人说为什么不使用0x90(也是滑板指令)呢?请看下一条

(2)之前说过,我们的shellcode会被放到堆中去执行,也就是所谓的使eip指向0x0C0C0C0C这个地址,而0x0C0C0C0C这个地址从0计算的话,大概在192mb左右,但0x90909090就不言而喻了,需要申请的堆空间那就相当大了。又有人会说为甚麽一定要让我们的eip指向0x0C0C0C0C呢?继续往下看

2. 计算好shellcode的字节数,将shellcode的代码贴到我们申请的1mb堆块的尾部,控制总大小刚好为1MB

 

3. 创建一个成员数为200的数组,数组的每个成员都是这样的堆块(为什么是200MB呢?因为可以保证0x0C0C0C0C这个地址指向我们所构造的这个数组中)


 

4. 为什么有很大概率指向我们的滑块指令0x0C0C0C0C ( 此处作为滑块指令)?而不是ShellCode代码呢?

一般我们的ShellCode的大小在500字节左右(也许会更小),而一个块的大小为1MB,相当于我们的Shellcode只占了整个块1/2000。当eip指向我们的滑板指令0x0C时,会一点点地往后执行到我们的ShellCode,此时我们的漏洞就算利用成功了。我们从事例中讲解堆喷的实现。

二.事例分析

1. 暴雷漏洞环境

虚拟机环境:WinXpSP3

漏洞软件:ie6.0

调试工具:OD、IDA

样本文件缀至文末

2. Poc样本中堆喷块的详细构造流程

 

3. 漏洞分析

3.1 配置环境

虚拟机环境就不多说了

ie的环境大家可以下载一个 IECollection ,里面有IE各版本的集合

3.2 触发漏洞

(1)修改Poc样本,不构造堆块,直接触发漏洞溢出(换言之就是将poc样本中的前 三个步骤删掉直接触发漏洞),同时修改OD的异常选项,使其不忽略任何异常。

 

(2) OD附加,拖入样本,中断至下图所示

 

(3)追栈,查找溢出点

 

(4)77f5f87b下软断,0x13df98下硬断(凡是被覆盖的点都可以,最好选择中间位置下断),查找何时溢出

(5)查看此时的edi(0x13DEFA被我们覆盖的栈),esi(0x1885D8A好像是个堆地址)

 

(6)IDA查看相关代码

 

(7)我们继续往上追esi的来源,即ebp - 0x94(ida中的pszUrl)(0x13A090),硬断写 入0x13A090,当该地址内被填充为一个明显堆地址时断下,此时,堆地址已被填充为 0x1000字节的图片原路径

 

(8)至此,我们便可以下结论了,由于程序员的疏忽,并未对图片源路径的长度做限 制,在对图片源路径拷贝时,造成了栈溢出,覆盖了栈中的重要指针,从而使eip指向 0x0C0C0C0C

3.3利用流程如下

 

① 栈被覆盖后,从栈中取出指针(0x0C0C0C0C)赋值给eax

② 由于堆喷射原理,所以0x0C0C0C0C地址内的数据大概率还是0x0C0C0C0C(滑块),此时ecx = 0x0C0C0C0C

③ 同理,ecx + 0x18该地址内大概率也是0x0C0C0C0C(滑块),从而滑向我们的ShellCode

4.漏洞利用(具体利用流程参照Poc样本)

(1) 先将自己的shellcode由ascii格式转换成unicode格式,具体转换方式如图

 

(2) 制作滑板数据

每个滑板块均为1mb

申请1024*1024 - 32 - 4 -2 字节的空间

具体填充方式如图

 

注意:填充内容为0x0C,而不是图中的0x90

(3) 制造200个这样的数据,形成堆喷区

(4) 触发漏洞,使eip指向0x0C0C0C0C

 

(5) 利用成功,哈哈哈 ,窗口全部拆解(个人ShellCode功能为拆解桌面所有窗口。。。)

 


[课程]Android-CTF解题方法汇总!

最后于 2018-11-23 11:20 被F4our444编辑 ,原因: 修改
上传的附件:
收藏
免费 13
支持
分享
最新回复 (17)
雪    币: 1535
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
666
2018-11-23 11:20
1
雪    币: 293
活跃值: (287)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
那为什么不用 0x04040404 呢 
2018-11-23 13:42
1
雪    币: 3499
活跃值: (770)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
4
瀚海云烟 那为什么不用 0x04040404 呢
因为很多程序的默认加载基址为0x400000,像0x04040404这个地址很容易被程序所占用
2018-11-23 14:13
0
雪    币: 2473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
不好意思我看成 
初识堆喷射及事例(暴露年龄)分析
2018-11-23 14:52
0
雪    币: 2473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
1. 我们首先创建一个大小为1mb的堆块,并使用0x0C0C0C0C填充
1.1为什么使用0x0C0C0C0C填充呢?有两点因素
(1)0x0C0C0C0C会被程序解释成 OR AL,0C 可以作为滑板指令(即执行此种指令不会对程序的后续行为产生影响),有人说为什么不使用0x90(也是滑板指令)呢?请看下一条
-------------------------
0x0c0c0c0c   or al,0xc  你确定这样不会影响reg?
0x06070607   表示不服
2018-11-23 15:09
3
雪    币: 3499
活跃值: (770)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
7
PYGame 1. 我们首先创建一个大小为1mb的堆块,并使用0x0C0C0C0C填充 1.1为什么使用0x0C0C0C0C填充呢?有两点因素 (1)0x0C0C0C0C会被程序解释成 OR AL,0C 可以作 ...
1.首先0x0c0c0c0c作为滑块,滑到我们的shellcode时,我们可以在Shellcode中对寄存器环境进行初始化(对Shellcode的执行影响不大)
2.0x0607作为双字节滑块,对应指令为 0x06 (push es) 0x07  (pop es)    我们使eip指向 0x06070607地址时,难以保证此时的滑块指令是指向了0x06 还是 0x07
 此时滑到shellcode时,我们无法确定栈顶esp的位置(说白了你的0x06 与 0x07必须成对出现才不会对栈有影响),而栈对漏洞利用的影响可就相当大了,比如我们执行完shellcode返回时,如果栈顶刚好为 es 的值,程序就无法返回到正常的执行流程
2018-11-23 15:58
0
雪    币: 293
活跃值: (287)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
噗咚Four 因为很多程序的默认加载基址为0x400000,像0x04040404这个地址很容易被程序所占用
可是 0x00400000 跟 0x04040404 地址差别有点大。也就是可以用的,忽略这个。
讨论另外一个问题: 最后你回复 PYGame 的也提到了跳转地址不确定是06 还是 07 ,那么是否应该在 0C0C 到 shellcode 之前要插入1~2 个单字节指令比如 0x90 呢,以防止前面 jmp 地址不是双数,而导致 最后一个指令变成  0C  + shellcode 第一个字节 ( OR  AL, XX )
最后于 2018-11-23 17:27 被瀚海云烟编辑 ,原因:
2018-11-23 17:26
0
雪    币: 3499
活跃值: (770)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
9
瀚海云烟 噗咚Four 因为很多程序的默认加载基址为0x400000,像0x04040404这个地址很容易被程序所占用 可是 0x0040000 ...
哦哦,不好意思,把0x04040404看错了。。这个0x0404指令应该也可以吧。。具体我也没有尝试过,我也只是刚接触堆喷射。
不过事例中从0x0c0c0c0c这个地址到我们的Shellcode之间应该可以保证有偶数个0x0C,因为我们的shellcode的字节数就是偶数啊(JS使用的是Unicode的编码方式),而0x0C0C0C0C这个地址也是个偶数地址,所以中间也相隔了偶数个0x0C吧。。。哈哈,希望大佬有答案的话也告知小弟一声。。
2018-11-23 18:58
0
雪    币: 4402
活跃值: (1336)
能力值: ( LV7,RANK:113 )
在线值:
发帖
回帖
粉丝
10
来支持一下学弟 :)
2018-11-26 09:55
0
雪    币: 4174
活跃值: (777)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
学弟你好!
2018-11-26 10:30
0
雪    币: 3499
活跃值: (770)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
12
Hades一KXXY 学弟你好!
学长们好!
2018-11-26 10:58
0
雪    币: 28
活跃值: (52)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
坦克班的
2018-11-26 12:51
0
雪    币: 3850
活跃值: (292)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
请问OD如何调试IE的呢?
2018-11-27 11:02
0
雪    币: 3499
活跃值: (770)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
15
dodohit 请问OD如何调试IE的呢?
打开ie,OD附加,激活所有线程,让它跑起来就行,当然使用windbg也可以
2018-11-27 15:57
0
雪    币: 3850
活跃值: (292)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
16
你好,上个问题解决了,不过。

我调试到3.2 触发漏洞第(3)步了,第(4)调试时,我先重新OD附加,恢复OD忽略异常设置,下软断点和硬断点,但是没有找到溢出函数。

请问我得操作对吗?您时如何下断点和找到溢出函数得呢?能详细说说嘛?硬件断点下执行还是访问?IDA打开得是什么文件?

万分感谢!!!
2018-11-28 16:57
0
雪    币: 3499
活跃值: (770)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
17
dodohit 你好,上个问题解决了,不过。 我调试到3.2 触发漏洞第(3)步了,第(4)调试时,我先重新OD附加,恢复OD忽略异常设置,下软断点和硬断点,但是没有找到溢出函数。 请问我得操作对吗?您时 ...
到了第(2)步的时候,此时的情况是我们的栈已经被溢出,却不知道在哪里溢出的。这时我们看poc样本

样本用于构造溢出的数据 头(\\\\15PB_Com) + 身(0x0C0C0C0C) , 然而我们第(2)步中

ebp - 0x14 只是身体上的0x0C0C0C0C , 此时我们往上查找头的位置 ,以此我们就能知道 被覆盖栈的起始地址 ,起始地址再往上便是还没有产生溢出时调用的函数,这样便到了第(3)步
第(4)步的做法是 找到一个还未产生溢出的函数地址,这个函数下软断,重新附加执行,
程序断下后,此时栈还未被覆盖,我们此时下硬断 ,找到一个即将被覆盖的栈地址下硬件写入断点,当我们被下硬断的地方被填充为0x0C0C0C0C时,此时便找到了溢出点,也就是第(5)步


2018-11-28 19:23
0
雪    币: 413
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
为什么eip指向的地址要与填充的地址一致
2018-12-21 11:01
0
游客
登录 | 注册 方可回帖
返回
//