来源: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
评论关闭。