IE8 sc.txt exploit 分析学习 | ZeroBox Notes

IE8 sc.txt exploit 分析学习

来源:http://blog.vulnhunt.com/index.php/2011/11/17/ie8-sc-txt-exploit-analysis/

软件版本:Internet Explorer8.0.7601.17514 WIN7 SP1

分析者 :phperl of Code Audit Labs of vulnhunt.com

http://blog.vulnhunt.com/index.php/2011/11/17/ie8-sc-txt-exploit-analysis/

已有参考

http://www.80vul.com/ie8/win7/sc.txt
http://hi.baidu.com/ring04h/blog/item/eecf13adcd7e05154b36d68d.html

2 Vulnerability Details

该exploit利用了两个漏洞实现了不用heap spray方法bypass DEP&ASLR,第一个漏洞是use after free类型的漏洞,通过此漏洞可以获取到mshtml的地址并触发shellcode的执行,第二个漏洞是信息泄露漏洞,漏洞泄露的地址指向我们可以通过JavaScript语句控制的内存。

3 漏洞分析

3.1.      use after free漏洞分析

当执行expvalueclass.onpropertychange = null;时,会调用到下面的方法,该方法先删除原来的属性值,然后设置新值。

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
.text:74DC4275 ; public: long __thiscall CBase::SetCodeProperty(long, struct IDispatch *, int *)
.text:74DC4275 ?SetCodeProperty@CBase@@QAEJJPAUIDispatch@@PAH@Z proc near
.text:74DC4275                                         ; CODE XREF: BASICPROPPARAMS::SetCodeProperty(tagVARIANT *,CBase *,CVoid *)+2Ep
.text:74DC4275                                         ; CScriptElement::CommitFunctionPointersCode(CBase *,int)+1F7065p ...
.text:74DC4275
.text:74DC4275 var_4           = dword ptr -4
.text:74DC4275 arg_0           = dword ptr  8
.text:74DC4275 arg_4           = dword ptr  0Ch
.text:74DC4275 arg_8           = dword ptr  10h
.text:74DC4275
.text:74DC4275 ; FUNCTION CHUNK AT .text:74EA8AA0 SIZE 00000007 BYTES
.text:74DC4275
.text:74DC4275                 mov     edi, edi
.text:74DC4277                 push    ebp
.text:74DC4278                 mov     ebp, esp
.text:74DC427A                 push    ecx
.text:74DC427B                 and     [ebp+var_4], 0
.text:74DC427F                 push    edi
.text:74DC4280                 push    0
.text:74DC4282                 push    [ebp+arg_0]
.text:74DC4285                 push    esi
.text:74DC4286                 call    ?DidFindAAIndexAndDelete@CBase@@QAEHJW4AATYPE@CAttrValue@@@Z ; CBase::DidFindAAIndexAndDelete(long,CAttrValue::AATYPE)
//调用函数删除原来的属性
.text:74DC428B                 push    3
.text:74DC428D                 push    [ebp+arg_0]
.text:74DC4290                 mov     edi, eax
.text:74DC4292                 push    esi
.text:74DC4293                 call    ?DidFindAAIndexAndDelete@CBase@@QAEHJW4AATYPE@CAttrValue@@@Z ; CBase::DidFindAAIndexAndDelete(long,CAttrValue::AATYPE)
.text:74DC4298                 mov     ecx, [ebp+arg_4]
.text:74DC429B                 or      edi, eax
.text:74DC429D                 test    ecx, ecx
.text:74DC429F                 jz      short loc_74DC42B0
.text:74DC42A1                 push    20h
.text:74DC42A3                 push    [ebp+arg_0]
.text:74DC42A6                 mov     eax, esi
.text:74DC42A8                 call    ?AddDispatchObject@CBase@@QAEJJPAUIDispatch@@W4AATYPE@CAttrValue@@W4AAExtraBits@4@@Z ; CBase::AddDispatchObject(long,IDispatch *,CAttrValue::AATYPE,CAttrValue::AAExtraBits)
.text:74DC42AD                 mov     [ebp+var_4], eax
.text:74DC42B0
.text:74DC42B0 loc_74DC42B0:                           ; CODE XREF: CBase::SetCodeProperty(long,IDispatch *,int *)+2Aj
.text:74DC42B0                 mov     eax, [esi]
.text:74DC42B2                 push    0
.text:74DC42B4                 push    0
.text:74DC42B6                 push    800117B6h
.text:74DC42BB                 mov     ecx, esi
.text:74DC42BD                 call    dword ptr [eax+98h]
.text:74DC42C3                 mov     eax, [ebp+arg_8]
.text:74DC42C6                 test    eax, eax
.text:74DC42C8                 jnz     loc_74EA8AA0
.text:74DC42CE
.text:74DC42CE loc_74DC42CE:                           ; CODE XREF: CBase::SetCodeProperty(long,IDispatch *,int *)+E482Dj
.text:74DC42CE                 mov     eax, [ebp+var_4]
.text:74DC42D1                 pop     edi
.text:74DC42D2                 leave
.text:74DC42D3                 retn    0Ch
.text:74DC42D3 ?SetCodeProperty@CBase@@QAEJJPAUIDispatch@@PAH@Z endp

最终会调用到CAttrArray::Destroy方法,该方法先释放属性值,返回后从属性数组中删除该属性。

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
.text:74E3F034 ; protected: void __thiscall CAttrArray::Destroy(int)
.text:74E3F034 ?Destroy@CAttrArray@@IAEXH@Z proc near  ; CODE XREF: CAttrArray::Set(long,PROPERTYDESC const *,tagVARIANT const *,CAttrValue::AATYPE,ushort,int)+D506p
.text:74E3F034                                         ; CBase::DeleteAt(ulong)+10p ...
.text:74E3F034
.text:74E3F034 ; FUNCTION CHUNK AT .text:74E784C3 SIZE 0000001E BYTES
.text:74E3F034 ; FUNCTION CHUNK AT .text:74E8909D SIZE 0000000C BYTES
.text:74E3F034
.text:74E3F034                 mov     edi, edi
.text:74E3F036                 push    edi
.text:74E3F037                 mov     edi, eax
.text:74E3F039                 mov     eax, [esi+10h]
.text:74E3F03C                 mov     ecx, eax
.text:74E3F03E                 shr     ecx, 1
.text:74E3F040                 test    cl, 1
.text:74E3F043                 jnz     loc_74E8909D
.text:74E3F049
.text:74E3F049 loc_74E3F049:                           ; CODE XREF: CAttrArray::Destroy(int)+4A06Aj
.text:74E3F049                 mov     ecx, edi
.text:74E3F04B                 shl     ecx, 4
.text:74E3F04E                 add     ecx, [esi+0Ch]
.text:74E3F051                 cmp     byte ptr [ecx], 3
.text:74E3F054                 jnz     loc_74E784C3
.text:74E3F05A
.text:74E3F05A loc_74E3F05A:                           ; CODE XREF: CAttrArray::Destroy(int)+394A8j
.text:74E3F05A                 call    ?Free@CAttrValue@@QAEXXZ ; CAttrValue::Free(void)
.text:74E3F05F                 mov     eax, [esi+10h]
.text:74E3F062                 shr     eax, 1
.text:74E3F064                 test    al, 1
.text:74E3F066                 jnz     loc_74E890A3
.text:74E3F06C
.text:74E3F06C loc_74E3F06C:                           ; CODE XREF: CAttrArray::Destroy(int)+4A070j
.text:74E3F06C                 push    10h
.text:74E3F06E                 pop     eax
.text:74E3F06F                 mov     edx, esi
.text:74E3F071                 call    ?Delete@CImplAry@@IAEXIH@Z ; CImplAry::Delete(uint,int)
//调用函数从属性数组中删除该索引对应的属性
.text:74E3F076                 pop     edi
.text:74E3F077                 retn
.text:74E3F077 ?Destroy@CAttrArray@@IAEXH@Z endp

如果该项属性值指向的是接口指针,则会释放该接口,此处onpropertychange属性指向的是TEAROFF_THUNK结构,使用PlainRelease函数释放该接口指针。

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
int __stdcall PlainRelease(LONG a1)
{
LONG v1; // eax@7
LONG v2; // eax@8
bool v3; // zf@1
int result; // eax@1
v3 = (*(_DWORD *)(a1 + 4))-- == 1;
result = *(_DWORD *)(a1 + 4);
if ( v3 )
{
if ( *(_DWORD *)(a1 + 12) && !(*(_BYTE *)(a1 + 28) & 4) )
(*(void (__stdcall **)(_DWORD))(*(_DWORD *)(a1 + 16) + 8))(*(_DWORD *)(a1 + 12));
if ( *(_DWORD *)(a1 + 20) )
(*(void (__stdcall **)(_DWORD))(*(_DWORD *)(a1 + 24) + 8))(*(_DWORD *)(a1 + 20));
v1 = InterlockedExchange(&dword_7515B03C, a1);
if ( v1 )
{
v2 = InterlockedExchange(&dword_7515B040, v1);
if ( v2 )
HeapFree(g_hProcessHeap, 0, (LPVOID)v2);
}
result = 0;
}
return result;
}
struct TEAROFF_THUNK
{
void *      papfnVtblThis;     // Thunk's vtable
ULONG       ulRef;             // Reference count for this thunk.
IID const * const * apIID;     // Short circuit QI using these IIDs.
void *      pvObject1;         // Delegate other methods to this object using...
const void * apfnVtblObject1;  // ...this array of pointers to member functions.
void *      pvObject2;         // Delegate methods to this object using...
void *      apfnVtblObject2;   // ...this array of pointers to member functions...
DWORD       dwMask;            // ...the index of the method is set in the mask.
DWORD       n;                 // index of method into vtbl
void *      apVtblPropDesc;    // array of propdescs in Vtbl order
}

如上所示,同时会释放pvObject1和pvObject2,会调用到CAttrCollectionator::~CAttrCollectionator,该函数会删除属性数组中DISPID为8001145a的属性,而onpropertychange的DISPID为8001179f,因此会导致onpropertychange在属性数组中的位置前移,导致CAttrValue::Free 返回后调用CImplAry::Delete时无法删除onpropertychange属性,但是又释放了该接口指针,放入了dword_7515B03C、dword_7515B040指向的TEAROFF_THUNK缓存中,导致下次获取onpropertychange属性时仍然可以查找到该属性,最终导致内存已经释放,但缓存和属性数组中仍然有指向该内存的指针,引起use after free漏洞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.text:74C68B19 ; public: virtual __thiscall CAttrCollectionator::~CAttrCollectionator(void)
.text:74C68B19 ??1CAttrCollectionator@@UAE@XZ proc near
.text:74C68B19                                         ; CODE XREF: CAttrCollectionator::`vector deleting destructor'(uint)+8p
.text:74C68B19                 mov     edi, edi
.text:74C68B1B                 push    esi
.text:74C68B1C                 push    3
.text:74C68B1E                 mov     esi, ecx
.text:74C68B20                 push    8001145Ah
.text:74C68B25                 push    dword ptr [esi+14h]
.text:74C68B28                 mov     dword ptr [esi], offset ??_7CAttrCollectionator@@6B@ ; const CAttrCollectionator::`vftable'
.text:74C68B2E                 call    ?DidFindAAIndexAndDelete@CBase@@QAEHJW4AATYPE@CAttrValue@@@Z ; CBase::DidFindAAIndexAndDelete(long,CAttrValue::AATYPE)
.text:74C68B33                 mov     eax, [esi+14h]
.text:74C68B36                 mov     ecx, [eax]
.text:74C68B38                 push    eax
.text:74C68B39                 call    dword ptr [ecx+0E0h]
.text:74C68B3F                 lea     eax, [esi+1Ch]
.text:74C68B42                 call    ??1CImplAry@@QAE@XZ ; CImplAry::~CImplAry(void)
.text:74C68B47                 mov     ecx, esi
.text:74C68B49                 pop     esi
.text:74C68B4A                 jmp     ??1CBase@@UAE@XZ ; CBase::~CBase(void)
.text:74C68B4A ??1CAttrCollectionator@@UAE@XZ endp

3.2.      信息泄露漏洞分析

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
.text:7503F5D8 ; public: long __stdcall COptionElement::get_index(long *)
.text:7503F5D8 ?get_index@COptionElement@@QAGJPAJ@Z proc near
.text:7503F5D8
.text:7503F5D8 arg_0           = dword ptr  8
.text:7503F5D8 arg_4           = dword ptr  0Ch
.text:7503F5D8
.text:7503F5D8                 mov     edi, edi
.text:7503F5DA                 push    ebp
.text:7503F5DB                 mov     ebp, esp
.text:7503F5DD                 push    esi
.text:7503F5DE                 push    edi
.text:7503F5DF                 mov     edi, [ebp+arg_4]
.text:7503F5E2                 test    edi, edi
.text:7503F5E4                 jnz     short loc_7503F5F0
.text:7503F5E6                 mov     esi, [ebp+arg_0]
.text:7503F5E9                 call    ?SetErrorInfoInvalidArg@CBase@@QAEJXZ ; CBase::SetErrorInfoInvalidArg(void)
.text:7503F5EE                 jmp     short loc_7503F61A
.text:7503F5F0 ; ---------------------------------------------------------------------------
.text:7503F5F0
.text:7503F5F0 loc_7503F5F0:                           ; CODE XREF: COptionElement::get_index(long *)+Cj
.text:7503F5F0                 mov     edx, [ebp+arg_0]
.text:7503F5F3                 test    byte ptr [edx+32h], 2
.text:7503F5F7                 jz      short loc_7503F618
.text:7503F5F9                 mov     ecx, edx
.text:7503F5FB                 call    ?GetParentSelect@COptionElement@@QAEPAVCSelectElement@@XZ ; COptionElement::GetParentSelect(void)
.text:7503F600                 mov     esi, eax
.text:7503F602                 test    esi, esi
.text:7503F604                 jz      short loc_7503F618
.text:7503F606                 push    edx
.text:7503F607                 lea     ecx, [esi+38h]
.text:7503F60A                 call    ?Find@CImplPtrAry@@IAEHPAX@Z ; CImplPtrAry::Find(void *)
.text:7503F60F                 mov     ecx, esi
.text:7503F611                 call    ?RelIdxFromAbs@CSelectElement@@QAEJJ@Z ; CSelectElement::RelIdxFromAbs(long)
.text:7503F616                 mov     [edi], eax
.text:7503F618
.text:7503F618 loc_7503F618:                           ; CODE XREF: COptionElement::get_index(long *)+1Fj
.text:7503F618                                         ; COptionElement::get_index(long *)+2Cj
.text:7503F618                 xor     eax, eax
.text:7503F61A
.text:7503F61A loc_7503F61A:                           ; CODE XREF: COptionElement::get_index(long *)+16j
.text:7503F61A                 pop     edi
.text:7503F61B                 pop     esi
.text:7503F61C                 pop     ebp
.text:7503F61D                 retn    8
.text:7503F61D ?get_index@COptionElement@@QAGJPAJ@Z endp

当执行var table_pointer = document.createElement(‘option’).index;时,会调用到上面的函数,

此处由于该option元素尚未插入select中,COptionElement::GetParentSelect失败,导致未对传入的地址赋值,但是返回值与正常返回时相同,导致信息泄露。

此处泄露的值指向JavaScript堆上的临时变量,其中每个变量占据16个字节空间,0-4字节表示该变量的类型,如果是32位整数,则直接存放在8-12字节,如果为字符串,则8-12字节为指向该字符串的指针。

3.3.      漏洞利用分析

由于TEAROFF_THUNK结构是40字节大小,可以使用40字节大小的字符串占位释放的内存,当调用expvalueclass.style.color = ‘red’;时,会调用到CreateTearoffThunk函数,该函数会获取

一个TEAROFF_THUNK结构,先从缓存中获取,如果为空则直接申请大小为40的内存,此处,释放的内存被字符串占位后同时也在缓存中,CreateTearoffThunk函数对该结构初始化,覆盖写入的字符串内容。

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
unsigned int __userpurge CreateTearOffThunk(void **a1, void *a2, const void *a3, struct IUnknown *a4, void **a5, void *a6, signed int a7, const RECT *a8, const struct _GUID *const *a9, void *a10, unsigned __int8 a11)
{
void *v11; // ebx@1
__int32 v12; // esi@2
const RECT *v13; // eax@3
unsigned int result; // eax@9
v11 = a6;
if ( a1 )
{
v11 = *a1;
a5 = a1;
a7 = 1;
}
v12 = InterlockedExchange(&dword_7515B03C, 0);
if ( v12
|| (v12 = InterlockedExchange(&dword_7515B040, 0)) != 0
|| (v12 = (__int32)HeapAlloc(g_hProcessHeap, 0, 40u)) != 0 )
{
*(_DWORD *)(v12 + 4) = 0;
*(_DWORD *)(v12 + 20) = a5;
v13 = a8;
*(_DWORD *)(v12 + 12) = a2;
*(_DWORD *)(v12 + 16) = a3;
*(_DWORD *)(v12 + 24) = v11;
*(_DWORD *)(v12 + 28 ) = a7;
if ( !a8 )
v13 = &g_Zero;
*(_DWORD *)(v12 + <img src="http://blog.vulnhunt.com/wp-includes/images/smilies/icon_cool.gif" alt="8)"> = v13;
*(_DWORD *)(v12 + 36) = a9;
JUMPOUT((unsigned __int8)a10 & 1, 0, sub_74DF5D80);
*(_DWORD *)v12 = &off_7515CAF0;
//此处0-4字节指向mshtml模块中的虚函数表
*(_BYTE *)(v12 + 34) = 0;
*(_BYTE *)(v12 + 35) = (_BYTE)a10;
if ( a2 && !(a7 & 2) )
(*((void (__stdcall **)(_DWORD))a3 + 1))(a2);
if ( a5 )
(*((void (__stdcall **)(_DWORD))v11 + 1))(a5);
a4->lpVtbl = (struct IUnknownVtbl *)v12;
result = 0;
}
else
{
a4->lpVtbl = 0;
result = 0x8007000Eu;
}
return result;
}

当再次获取title属性时,由于字符串已经被上面的操作覆盖,便可以获取到mshtml模块中虚函数表的地址。

如果被字符串占位后,直接获取onpropertychange属性,则会调用TEAROFF_HUNK的虚函数,触发shellcode执行。

通过控制var table_pointer = document.createElement(‘option’).index;上面执行的语句,我们可以控制泄露的地址指向的内容,放置shellcode。

3.4.      调试分析方法

在JavaScript中获取、设置属性时,会先调用mshtml!plaingetdispid,然后调用mshtml!plaininvokeex,通过对这两个函数下断点,可以对应到执行的JavaScript语句。

首先下断点到第一次为onpropertychange属性赋值的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
0:012> bp mshtml!plaingetdispid "du poi(esp+8);as /mu method poi(esp+8);.block{j($scmp(\"${method}\",\"onpropertychange\")=0) '';'gc'}"
0:012> bl
0 e 6a7cc9d1     0001 (0001)  0:**** mshtml!PlainGetDispID "du poi(esp+8);as /mu method poi(esp+8);.block{j($scmp(\"${method}\",\"onpropertychange\")=0) '';'gc'}"
2 d 6a77bb85     0001 (0001)  0:**** mshtml!PlainInvokeEx
然后F5运行
0175b65c  "createElement"
0175b65c  "createElement"
0175b690  "body"
0175b6a4  "appendChild"
0175b690  "body"
0175b6a4  "appendChild"
0175b6f0  "attributes"
0175b6c4  "onpropertychange"
eax=6a7cc9d1 ebx=10000003 ecx=020ca2a0 edx=0175b6c4 esi=001aba30 edi=0066c6c0
eip=6a7cc9d1 esp=020ca238 ebp=020ca264 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!PlainGetDispID:
6a7cc9d1 8bff            mov     edi,edi
然后打开第二个断点
0:005> be 2
0:005> g
Breakpoint 2 hit
eax=8001179f ebx=0066c6c0 ecx=6a77bb85 edx=0000000c esi=020ca16c edi=00000000
eip=6a77bb85 esp=020ca140 ebp=020ca178 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!PlainInvokeEx:
6a77bb85 8bff            mov     edi,edi
0:005> pc
eax=6a6d0a90 ebx=00001200 ecx=6a7599dc edx=0066c750 esi=0066c6c0 edi=00000001
eip=6a77bc0b esp=020ca0f0 ebp=020ca13c 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!PlainInvokeEx+0xcc:
6a77bc0b ff5038          call    dword ptr [eax+38h]  ds:0023:6a6d0ac8={mshtml!CElement::VersionedInvokeEx (6a7da6d8)}
0:005> t
eax=6a6d0a90 ebx=00001200 ecx=6a7599dc edx=0066c750 esi=0066c6c0 edi=00000001
eip=6a7da6d8 esp=020ca0ec ebp=020ca13c 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!CElement::VersionedInvokeEx:
6a7da6d8 8bff            mov     edi,edi
0:005> dd esp
020ca0ec  6a77bc0e 0066c750 8001179f 00000001
020ca0fc  0000000c 020ca240 00000000 020ca250
020ca10c  0175f858 0066c6c0 00000001 efa18903
020ca11c  6a922a90 00000000 020ca16c 0066c6c0
020ca12c  017ccab0 00000001 efa18903 00000000
020ca13c  020ca178 66cfa26e 0066c6c0 8001179f
020ca14c  00000001 0000000c 020ca240 00000000
020ca15c  020ca250 0175f858 8001179f 001aba30
0:005> dds 0066c750
0066c750  6a6d0a90 mshtml!CDivElement::`vftable'
0066c754  00000004
0066c758  00000008
0066c75c  00663ff8       //指向div对象的属性数组
0066c760  001aefa0
0066c764  005e2af8
0066c768  0000001f
0066c76c  00010200
0:005> dd 00663ff8
00663ff8  6a5aa594 00000004 00000004 005fba58
00664008  00000000 00000000 2d11148b 80000068
00664018  554d00c6 00000000 00000000 00000000
00664028  00000000 00000000 2d11148f 8000006c
00664038  007700ca 00740061 00680063 002d0020
00664048  00380020 00200029 2d111483 80000066
00664058  006800ce 006c0065 006f006c 0065006b
00664068  00280079 00650074 2d111487 8000006b
005fba58指向属性数组,每个属性16个字节大小
0:005> dd 005fba58
005fba58  00001a03 8001145a 00000000 005f4178
此处8001145a为attributes的dispid,005f4178为指向attributes属性的接口指针
005fba68  000000d9 00000018 00000184 00000020
005fba78  00000269 00000020 00000000 00000266
005fba88  000002f6 00000556 00000000 00000556
005fba98  2d2b0aaa 8c000033 75a49854 6c90338c
005fbaa8  00000001 005fcee4 005fcbb0 6c9050a0
0:005> bd 2
//返回到jscript模块
0:005> g 0x`66cfa26e
eax=00000000 ebx=0066c6c0 ecx=0175f858 edx=00000000 esi=020ca16c edi=00000000
eip=66cfa26e esp=020ca164 ebp=020ca178 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript!IDispatchExInvokeEx2+0x104:
66cfa26e 8d75f4          lea     esi,[ebp-0Ch]
//查看div属性数组的内容
0:005> dd 005fba58
005fba58  00001a03 8001145a 00000000 005f4178
005fba68  00200903 8001179f 00000000 0066c830
005fba78  00000d08 800117c4 00000000 00661180
005fba88  000002f6 00000556 00000000 00000556
005fba98  2d2b0aaa 8c000033 75a49854 6c90338c
第二行8001179f为onpropertychange的dispid,0066c830为接口指针,实际上是指向TEAROFF_THUNK结构的指针,此时引用计数为3
0:005> dd 0066c830 l10
0066c830  6aadbdc8 00000003 6a775d74 005f4178
0066c840  6a5e77d0 00000000 00000000 00000000
0066c850  03000013 00000000 2d117bc2 88000000
0066c860  6aadcaf0 00000000 6a757be0 0066c750
下面的循环目的是触发垃圾回收,可以对66c834地址下硬件写入断点,追踪该内存。
0:005> ba w4 0066c834
0:005> g
0175b6f0  "attributes"
0175b6c4  "onpropertychange"
eax=6a7cc9d1 ebx=10000003 ecx=020ca2a0 edx=0175b6c4 esi=001aba30 edi=0066c720
eip=6a7cc9d1 esp=020ca238 ebp=020ca264 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!PlainGetDispID:
6a7cc9d1 8bff            mov     edi,edi
0:005> g
Breakpoint 1 hit
eax=0066c830 ebx=001aef10 ecx=6aadbdc8 edx=6a7578d5 esi=0066c830 edi=01751e60
eip=6a7578e1 esp=020ca144 ebp=020ca148 iopl=0         nv up ei pl nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000203
mshtml!PlainRelease+0xc:
6a7578e1 8b4604          mov     eax,dword ptr [esi+4] ds:0023:0066c834=00000002
0:005> kb
ChildEBP RetAddr  Args to Child
020ca148 66cfa735 0066c830 01751e60 00000001 mshtml!PlainRelease+0xc
020ca158 66d1444c 001ab9a0 001a2e50 01755008 jscript!VAR::Clear+0x5f
020ca180 66d16e46 00000000 00000000 005d1be0 jscript!GcAlloc::ReclaimGarbage+0x94
020ca19c 66d143e9 00000002 020ca210 00000000 jscript!GcContext::Reclaim+0xb6
020ca1b0 66d142e9 020ca210 0176d350 001abd28 jscript!GcContext::CollectCore+0x123
020ca1c4 66d783f0 020ca220 66d0599a 001aba30 jscript!GcContext::Collect+0x3a
020ca1cc 66d0599a 001aba30 020ca270 020ca210 jscript!JsCollectGarbage+0x1d
020ca234 66d0758c 00000000 00000000 0175f090 jscript!NatFncObj::Call+0x106
020ca2b8 66d04f84 001abd28 001aba30 00000001 jscript!NameTbl::InvokeInternal+0x141
中断两次后引用计数变为1
0:005> dd 0066c830 l10
0066c830  6aadbdc8 00000001 6a775d74 005f4178
0066c840  6a5e77d0 00000000 00000000 00000000
0066c850  03000013 00000000 2d117bc2 88000000
0066c860  6aadbdc8 00000001 6a775d74 00628600
当指向onpropertychange=null;时引用计数变为0,因此要释放接口指针,而该接口指针又指向attributes接口的指针,因此也要释放attributes接口的指针,返回后会先释放到TEAROFF_THUNK缓存中,如果大于两个,则会实际释放内存。
mshtml!PlainRelease:
6a7578d5 8bff            mov     edi,edi
6a7578d7 55              push    ebp
6a7578d8 8bec            mov     ebp,esp
6a7578da 56              push    esi
6a7578db 8b7508          mov     esi,dword ptr [ebp+8]
6a7578de ff4e04          dec     dword ptr [esi+4]
6a7578e1 8b4604          mov     eax,dword ptr [esi+4] ds:0023:0066c834=00000000
6a7578e4 749a            je      mshtml!PlainRelease+0x11 (6a757880)
6a7578e6 5e              pop     esi
6a7578e7 5d              pop     ebp
6a7578e8 c20400          ret     4
6a757883 85c0            test    eax,eax
6a757885 740d            je      mshtml!PlainRelease+0x25 (6a757894)
6a757887 f6461c04        test    byte ptr [esi+1Ch],4
6a75788b 7507            jne     mshtml!PlainRelease+0x25 (6a757894)
6a75788d 8b4e10          mov     ecx,dword ptr [esi+10h]
6a757890 50              push    eax
6a757891 ff5108          call    dword ptr [ecx+8]
6a757894 8b4614          mov     eax,dword ptr [esi+14h]
6a757897 85c0            test    eax,eax
6a757899 0f853d870000    jne     mshtml!PlainRelease+0x2c (6a75ffdc)
6a75789f 56              push    esi
6a7578a0 8b3560125a6a    mov     esi,dword ptr [mshtml!_imp__InterlockedExchange (6a5a1260)]
6a7578a6 683cb0ad6a      push    offset mshtml!g_pTimerMan+0x8 (6aadb03c)
6a7578ab ffd6            call    esi
6a7578ad 85c0            test    eax,eax
6a7578af 741b            je      mshtml!PlainRelease+0x60 (6a7578cc)
6a7578b1 50              push    eax
6a7578b2 6840b0ad6a      push    offset mshtml!g_pTimerMan+0xc (6aadb040)
6a7578b7 ffd6            call    esi
6a7578b9 85c0            test    eax,eax
6a7578bb 740f            je      mshtml!PlainRelease+0x60 (6a7578cc)
6a7578bd 50              push    eax
6a7578be 6a00            push    0
6a7578c0 ff351884ad6a    push    dword ptr [mshtml!g_hProcessHeap (6aad8418)]
6a7578c6 ff15fc125a6a    call    dword ptr [mshtml!_imp__HeapFree (6a5a12fc)]
6a7578cc 33c0            xor     eax,eax
6a7578ce eb16            jmp     mshtml!PlainRelease+0x62 (6a7578e6)
attributes属性对象的析构函数会先到属性数组中删除attributes属性,由于attributes属性在onpropertychange属性前面,会导致onpropertychange属性在属性数组中的索引前移。
mshtml!CAttrCollectionator::~CAttrCollectionator:
6a5e8b19 8bff            mov     edi,edi
6a5e8b1b 56              push    esi
6a5e8b1c 6a03            push    3
6a5e8b1e 8bf1            mov     esi,ecx
6a5e8b20 685a140180      push    8001145Ah
6a5e8b25 ff7614          push    dword ptr [esi+14h]
6a5e8b28 c706c83c756a    mov     dword ptr [esi],offset mshtml!CAttrCollectionator::`vftable' (6a753cc8)
6a5e8b2e e80db61500      call    mshtml!CBase::DidFindAAIndexAndDelete (6a744140)
6a5e8b33 8b4614          mov     eax,dword ptr [esi+14h]
6a5e8b36 8b08            mov     ecx,dword ptr [eax]
6a5e8b38 50              push    eax
6a5e8b39 ff91e0000000    call    dword ptr [ecx+0E0h]
6a5e8b3f 8d461c          lea     eax,[esi+1Ch]
6a5e8b42 e8dfef1600      call    mshtml!CImplAry::~CImplAry (6a757b26)
6a5e8b47 8bce            mov     ecx,esi
6a5e8b49 5e              pop     esi
6a5e8b4a e9f18f1700      jmp     mshtml!CBase::~CBase (6a761b40)
返回后onpropertychange属性指向的TEAROFF_THUNK结构释放到缓存中,属性数组中
attributes属性被删除。
0:005> dd 6aadb03c l2
6aadb03c  0066c830 0066c780
0:005> dd 005fba58
005fba58  00200903 8001179f 00000000 0066c830
005fba68  00000d08 800117c4 00000000 00661180
当返回后准备从属性数组中删除onpropertychange属性时由于索引前移,导致无法删除。
mshtml!CImplAry::Delete:
6a757ad5 8bff            mov     edi,edi
6a757ad7 56              push    esi
6a757ad8 8bf0            mov     esi,eax
6a757ada 85ff            test    edi,edi
6a757adc 7c28            jl      mshtml!CImplAry::Delete+0x51 (6a757b06)
6a757ade 8b4a04          mov     ecx,dword ptr [edx+4]
6a757ae1 8bc1            mov     eax,ecx
6a757ae3 c1e802          shr     eax,2
6a757ae6 3bf8            cmp     edi,eax
6a757ae8 7d1c            jge     mshtml!CImplAry::Delete+0x51 (6a757b06)
6a757aea 83e103          and     ecx,3
6a757aed 8d0485fcffffff  lea     eax,[eax*4-4]
6a757af4 0bc1            or      eax,ecx
6a757af6 8bc8            mov     ecx,eax
6a757af8 c1e902          shr     ecx,2
6a757afb 894204          mov     dword ptr [edx+4],eax
6a757afe 3bf9            cmp     edi,ecx
6a757b00 0f8268770600    jb      mshtml!CImplAry::Delete+0x2d (6a7bf26e) [br=0]
6a757b06 5e              pop     esi
6a757b07 c3              ret
当执行到缓存的两个结构体指针都指向原来onpropertychange指向的结构时,如果再释放一个TEAROFF_THUNK结构体,则会导致onpropertychange指向的结构内存释放,但同时又保留在结构体缓存中,下面为div的title属性赋值时由于字符串的长度与结构体的大小相同,因此会正好占位刚释放的内存。
0:005> dd 6aadb03c l2
6aadb03c  0066c830 0066c830
0:005> p
eax=0066c830 ebx=001aba30 ecx=6aadb040 edx=0066c830 esi=76a9bf0a edi=00000001
eip=6a7578bd esp=020ca1c0 ebp=020ca1c4 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!PlainRelease+0x51:
6a7578bd 50              push    eax
0:005> p
eax=0066c830 ebx=001aba30 ecx=6aadb040 edx=0066c830 esi=76a9bf0a edi=00000001
eip=6a7578be esp=020ca1bc ebp=020ca1c4 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!PlainRelease+0x52:
6a7578be 6a00            push    0
0:005> p
eax=0066c830 ebx=001aba30 ecx=6aadb040 edx=0066c830 esi=76a9bf0a edi=00000001
eip=6a7578c0 esp=020ca1b8 ebp=020ca1c4 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!PlainRelease+0x54:
6a7578c0 ff351884ad6a    push    dword ptr [mshtml!g_hProcessHeap (6aad8418)] ds:0023:6aad8418=005a0000
0:005> p
eax=0066c830 ebx=001aba30 ecx=6aadb040 edx=0066c830 esi=76a9bf0a edi=00000001
eip=6a7578c6 esp=020ca1b4 ebp=020ca1c4 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!PlainRelease+0x5a:
6a7578c6 ff15fc125a6a    call    dword ptr [mshtml!_imp__HeapFree (6a5a12fc)] ds:0023:6a5a12fc={kernel32!HeapFree (76a9bbd0)}
0:005> dd 6aadb03c l2
6aadb03c  0062ae30 0066c830
如下释放的内存正好被vtable1的字符串占位。
0175b738  "title"
Breakpoint 3 hit
eax=0062ae30 ebx=00000000 ecx=6aadb03c edx=00000000 esi=6a768eb0 edi=76a9bf0a
eip=76a9bb46 esp=020c9edc ebp=020c9ef4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
kernel32!InterlockedExchange+0xe:
76a9bb46 75fa            jne     kernel32!InterlockedExchange+0xa (76a9bb42) [br=0]
0:005> g
Breakpoint 1 hit
eax=00647364 ebx=0064733c ecx=00000008 edx=00000000 esi=00647344 edi=0066c838
eip=77409b60 esp=020c9e24 ebp=020c9e2c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
msvcrt!memcpy+0x5a:
77409b60 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:005> du esi
00647344  "111110000000000"
当执行style.color=”red”;语句时再次从TEAROFF_THUNK缓存中分配被字符串占位的结构体。
0175b738  "title"
0175b738  "title"
0175b738  "title"
0175b770  "style"
Breakpoint 1 hit
eax=00000000 ebx=00000000 ecx=6aadb040 edx=00000000 esi=0066c830 edi=76a9bf0a
eip=6a75a52d esp=020c8a88 ebp=020c8a94 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!CreateTearOffThunk+0x69:
6a75a52d 8b4d08          mov     ecx,dword ptr [ebp+8] ss:0023:020c8a9c=005f4178
0:005> dd esi
0066c830  00310031 00000000 00310031 00310031
0066c840  00300031 00300030 00300030 00300030
0066c850  00300030 00000030 2d117bc2 88000000
0066c860  6aadbdc8 00000001 6a775d74 00628600
0066c870  6a5e77d0 00000000 00000000 00000000
0066c880  03000047 00000000 2d117bd8 8c000000
0066c890  71d8436c 71d3a4dc 71d8c020 00010001
0066c8a0  00000000 71d4b540 00664058 00000000
0:005> g
Breakpoint 1 hit
eax=0066c830 ebx=00000000 ecx=005f4178 edx=0066c830 esi=6a758264 edi=6a758264
eip=6a75a5e4 esp=020c8ab4 ebp=020c8ab4 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!CDynamicCF::AddRef+0xb:
6a75a5e4 8b4004          mov     eax,dword ptr [eax+4] ds:0023:0066c834=00000001
0066c830被覆盖为指向mshtml中虚表的指针。
0:005> dd 0066c830
0066c830  6aadbdc8 00000001 6a775d74 005f4178
0066c840  6a7597d0 00000000 00000000 00000000
0066c850  03000030 00000000 2d117bc2 88000000
0066c860  6aadbdc8 00000001 6a775d74 00628600
0066c870  6a5e77d0 00000000 00000000 00000000
0066c880  03000047 00000000 2d117bd8 8c000000
0066c890  71d8436c 71d3a4dc 71d8c020 00010001
0066c8a0  00000000 71d4b540 00664058 00000000
0:005> dds poi(0066c830) l5
6aadbdc8  6a78a5c1 mshtml!PlainDispatchQueryInterface
6aadbdcc  6a75a5d9 mshtml!CPeerEnumerator::AddRef
6aadbdd0  6a7578d5 mshtml!PlainRelease
6aadbdd4  6a76863f mshtml!TearoffThunk3
6aadbdd8  6a7905e0 mshtml!TearoffThunk4
当获取index属性时结果的VARIANT结构体的值指向JS堆上我们可以控制的临时对象。
00aab9a4  "index"
eax=6a7cc9d1 ebx=10000001 ecx=0205a310 edx=00aab9a4 esi=005eba30 edi=003f9758
eip=6a7cc9d1 esp=0205a2a8 ebp=0205a2d4 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!PlainGetDispID:
6a7cc9d1 8bff            mov     edi,edi
0:005> be 2
0:005> g
Breakpoint 2 hit
eax=000003ed ebx=003f9758 ecx=6a77bb85 edx=00000002 esi=0205a1dc edi=00000000
eip=6a77bb85 esp=0205a1b0 ebp=0205a1e8 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!PlainInvokeEx:
6a77bb85 8bff            mov     edi,edi
0:005> dd esp
0205a1b0  66cfa26e 003f9758 000003ed 00000001
0205a1c0  00000002 0205a2b0 00aaf068 0205a2c0
0205a1d0  00aaf860 000003ed 005eba30 005eaf38
0205a1e0  00000000 005eb788 0205a224 66cfa1b9
0205a1f0  005eba30 000003ed 00000409 00000002
0205a200  0205a2b0 00aaf068 0205a2c0 00aaf860
0205a210  003f9758 005eba30 00aaf860 003f9758
0205a220  6a75b7e2 0205a2e4 66cfa43a 005eba30
0:005> dd 00aaf068
00aaf068  00000000 00400c48 00aa6fe8 fff80000
00aaf078  00000080 00400c48 00aa6fd8 fff80000
00aaf088  00000000 00000000 00000000 00aaf2a8
JS中函数调用中生成的临时对象会保留在堆上,我们可以通过JS代码控制JS堆。如下:
valuettgot13 = funhellokey(tempkktvalue + 0x0051e7db);
此处tempkktvalue + 0x0051e7db的临时值就会放在堆上。
因此通过该漏洞我们可以定位我们的shellcode,最后一个onpropertychange属性获取则会触发shellcode调用。

4 漏洞利用

按如上分析此exploit不利用heap spray 即可bypass DEP&ASLR,是因为获取了mshtml模块地址和shellcode地址。

5 Crash info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:005> g
(bc4.468): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=a7c7bb98 ebx=00143990 ecx=01b73254 edx=000e1860 esi=01b7e520 edi=80020003
eip=6a742ce6 esp=026a9ed4 ebp=026a9ee0 iopl=0         ov up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010a83
mshtml!`string'+0x6:
6a742ce6 65007200        add     byte ptr gs:[edx],dh            gs:000e1860=03

6 POC

 

http://www.80vul.com/ie8/win7/sc.txt

评论关闭。