您的位置:首页 > 其它

CVE-2010-3962逆向分析过程

2011-01-31 18:42 274 查看
这个漏洞已经发布有一段时间了,现在假期有空,分析一下当作练手。

 
运行环境:
Windows XP SP3
IE 6.0.2900.5512
 
以下将从逆向的角度,通过对汇编代码的分析,找出漏洞产生原因。
 
首先从网上下载CVE-2010-3962利用程序。在此附上一份下载地址:
http://www.exploit-db.com/exploits/15421/
 
获得漏洞利用网页之后,做了简单的测试,发现该程序无法正确执行,但可以正常出发漏洞,如果shellcode能正确执行的话,只需在shellcode开始处加入0xcc,略作调整,就能让程序断下来了。
下面开始分析用WinDbg加载IE,打开利用程序网页,当程序因出错停下来后查看寄存器和调用堆栈。
 
eax=7e2233f1 ebx=0012e1ec ecx=0176ae50 edx=3fffffff esi=00000000 edi=0176ae50
eip=ed7e27c8 esp=0012e1a0 ebp=0012e1b0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00010206
ed7e27c8 ??              ???

0:000> k
ChildEBP RetAddr
0012e19c 7e291a6d 0xed7e27c8
0012e1b0 7e2c60e4 mshtml!CLayout::EnsureDispNodeBackground+0x97
0012e274 7e2c5345 mshtml!CTableLayoutBlock::EnsureTableDispNode+0x388

可以看到,是在函数mshtml!CLayout::EnsureDispNodeBackground中出现了问题。
 
查看mshtml!CLayout::EnsureDispNodeBackground函数的反汇编
mshtml!CLayout::EnsureDispNodeBackground:
……
7e291a66 8b07            mov     eax,dword ptr [edi]         //edi为函数第二个参数,可推测出为一类指针,则eax指向类的虚函数表
7e291a68 8bcf            mov     ecx,edi                                 //__thiscall,ecx传递this指针
7e291a6a ff5030          call    dword ptr [eax+30h]            //根据偏移调用虚函数
7e291a6d 85c0            test    eax,eax
……
 
 
可以看出是因为虚函数表被修改而造成的错误,重新运行,在mshtml!CLayout::EnsureDispNodeBackground处下断点,确定一下,发现,进入EnsureDispNodeBackground函数时,虚函数表中内容都是非法的。
 
下面就要想办法找到在什么地方修改了对象的虚函数表,继续根据调用堆栈向前查找,通过对mshtml!CTableLayoutBlock::EnsureTableDispNode的分析可以发现,mshtml!CLayout::EnsureDispNodeBackground中第二个参数是在EnsureTableDispNode中生成的,这样就节省了很多力气,只要跟踪EnsureTableDispNode中出错对象的改变即可。
经过测试,可以发现在第二次调用mshtml!CDispNode::SetUserClip之后,esi指向类的前四个字节,即虚函数表地址由0x7e2233f0变为0x7e2233f1,那么问题就出在mshtml!CDispNode::SetUserClip里面了。
mshtml!CDispNode::SetUserClip的调用过程如下:
7e32a11e 33c0            xor     eax,eax
7e32a120 898564ffffff    mov     dword ptr [ebp-9Ch],eax
7e32a126 898560ffffff    mov     dword ptr [ebp-0A0h],eax
7e32a12c 89855cffffff    mov     dword ptr [ebp-0A4h],eax
7e32a132 898558ffffff    mov     dword ptr [ebp-0A8h],eax
7e32a138 8d8558ffffff    lea     eax,[ebp-0A8h]
7e32a13e 50              push    eax
7e32a13f 8bce            mov     ecx,esi
7e32a141 e8d7410e00      call    mshtml!CDispNode::SetUserClip (7e40e31d)
 
 
 
我们看看mshtml!CDispNode::SetUserClip都做了些什么:
mshtml!CDispNode::SetUserClip:
7e40e31d 8bff            mov     edi,edi
7e40e31f 55              push    ebp
7e40e320 8bec            mov     ebp,esp
7e40e322 83ec10          sub     esp,10h
7e40e325 56              push    esi
7e40e326 57              push    edi
7e40e327 8bf9            mov     edi,ecx    //edi指向类对象指针
7e40e329 8b4704          mov     eax,dword ptr [edi+4]    // 将CDispNode类的第一个成员变量值赋给eax
7e40e32c 2500108800      and     eax,881000h
7e40e331 3d00108000      cmp     eax,801000h
7e40e336 6a0f            push    0Fh
7e40e338 5e              pop     esi            //esi = 0x0f
7e40e339 7548            jne     mshtml!CDispNode::SetUserClip+0x66 (7e40e383)        //jne跳转实现
……
mshtml!CDispNode::SetUserClip+0x66:
7e40e383 804f0704        or      byte ptr [edi+7],4
7e40e387 6800000008      push    8000000h
7e40e38c 8bcf            mov     ecx,edi
7e40e38e e8dae5e7ff      call    mshtml!CDispNode::SetFlagsToRoot (7e28c96d)       //调用成员函数
7e40e393 ff7508          push    dword ptr [ebp+8]     // SetUserClip的参数
7e40e396 8d4df0          lea     ecx,[ebp-10h]
7e40e399 e8c9bce7ff      call    mshtml!CRect::CRect (7e28a067)
7e40e39e 8d4df0          lea     ecx,[ebp-10h]
7e40e3a1 e8a4e8ffff      cal
4000
l    mshtml!CRect::RestrictRange (7e40cc4a)
7e40e3a6 8b4704          mov     eax,dword ptr [edi+4]
7e40e3a9 23c6            and     eax,esi              //esi == 0x0f
7e40e3ab 0fb688101c217e  movzx   ecx,byte ptr mshtml!CDispNode::_extraSizeTable (7e211c10)[eax] ds:0023:7e211c10=00
//关键!将mshtml!CDispNode::_extraSizeTable值赋给ecx,其值为0
7e40e3b2 8bc7            mov     eax,edi
7e40e3b4 c1e102          shl     ecx,2                   //ecx = ecx * 4 = 0
7e40e3b7 2bc1            sub     eax,ecx             //eax = eax – ecx = eax = edi = this指针
7e40e3b9 830801          or      dword ptr [eax],1    //虚函数表被悲剧了~~
7e40e3bc 8b4704          mov     eax,dword ptr [edi+4]
7e40e3bf 23c6            and     eax,esi
7e40e3c1 0fb688101c217e  movzx   ecx,byte ptr mshtml!CDispNode::_extraSizeTable (7e211c10)[eax]
7e40e3c8 8bc7            mov     eax,edi
7e40e3ca c1e102          shl     ecx,2
7e40e3cd 2bc1            sub     eax,ecx
7e40e3cf 8320fd          and     dword ptr [eax],0FFFFFFFDh     //这里本应该也会影响到虚函数表,但因为[eax]第二位恰好为0,故没造成影响
7e40e3d2 8b4704          mov     eax,dword ptr [edi+4]
7e40e3d5 23c6            and     eax,esi
7e40e3d7 0fb680101c217e  movzx   eax,byte ptr mshtml!CDispNode::_extraSizeTable (7e211c10)[eax]
7e40e3de c1e002          shl     eax,2
7e40e3e1 2bf8            sub     edi,eax
7e40e3e3 83c704          add     edi,4
7e40e3e6 8d75f0          lea     esi,[ebp-10h]
7e40e3e9 a5              movs    dword ptr es:[edi],dword ptr [esi]
7e40e3ea a5              movs    dword ptr es:[edi],dword ptr [esi]
7e40e3eb a5              movs    dword ptr es:[edi],dword ptr [esi]
7e40e3ec a5              movs    dword ptr es:[edi],dword ptr [esi]
7e40e3ed 5f              pop     edi
7e40e3ee 5e              pop     esi
7e40e3ef c9              leave
7e40e3f0 c20400          ret     4
 
 
通过以上的分析,可以发现,造成错误的关键在于mshtml!CDispNode::_extraSizeTable值为0,这个值是在对象实例化的时候进行赋值的,我们在看看对象创建时的情况。
 
7e2c604a 33c0            xor     eax,eax
……
7e2c607a 50              push    eax
7e2c607b 8d430c          lea     eax,[ebx+0Ch]
7e2c607e 50              push    eax
7e2c607f e8a9fcfeff      call    mshtml!CDispContainer::New (7e2b5d2d)

mshtml!CDispContainer::New:
7e2b5d2d 8bff            mov     edi,edi
7e2b5d2f 55              push    ebp
7e2b5d30 8bec            mov     ebp,esp
7e2b5d32 ff750c          push    dword ptr [ebp+0Ch]         //值为0
7e2b5d35 6a00            push    0
7e2b5d37 6a48            push    48h
7e2b5d39 e8d1bdfdff      call    mshtml!CDispNode::operator new (7e291b0f)            //调用基类的构造函数,在此跟进
7e2b5d3e 85c0            test    eax,eax
7e2b5d40 7416            je      mshtml!CDispContainer::New+0x29 (7e2b5d58)   //创建不成功则跳转
7e2b5d42 8b4d08          mov     ecx,dword ptr [ebp+8]
7e2b5d45 668148068080    or      word ptr [eax+6],8080h  //注意此处,稍后会加以说明

mshtml!CDispNode::operator new:        //三个参数的值依次为0x48 , 0x00 , 0x00
7e291b0f 8bff            mov     edi,edi
7e291b11 55              push    ebp
7e291b12 8bec            mov     ebp,esp
7e291b14 51              push    ecx
7e291b15 51              push    ecx
7e291b16 8b4508          mov     eax,dword ptr [ebp+8]            //eax为0x48
7e291b19 53              push    ebx
7e291b1a 8b5d10          mov     ebx,dword ptr [ebp+10h]       //ebx为0x00
7e291b1d 56              push    esi
7e291b1e 0fb6b3101c217e  movzx   esi,byte ptr mshtml!CDispNode::_extraSizeTable (7e211c10)[ebx]       //关键!esi为0
7e291b25 c1e602          shl     esi,2           //esi = esi * 4 = 0
7e291b28 57              push    edi
7e291b29 03c6            add     eax,esi     //eax = eax + esi = eax = 0x48
7e291b2b 50              push    eax
7e291b2c e87563feff      call    mshtml!_MemAllocClear (7e277ea6)          //分配内存
7e291b31 8bf8            mov     edi,eax    //分配内存首地址
7e291b33 85ff            test    edi,edi
7e291b35 740e            je      mshtml!CDispNode::operator new+0x47 (7e291b45)    //分配不成功则跳转

mshtml!CDispNode::operator new+0x28:
7e291b37 03fe            add     edi,esi      //edi = edi + esi = edi
7e291b39 f6c340          test    bl,40h
7e291b3c 895f04          mov     dword ptr [edi+4],ebx     //将_extraSizeTable值赋给[edi+4]
7e291b3f 0f85391b0a00    jne     mshtml!CDispNode::operator new+0x32 (7e33367e)
……
 
由以上代码可以看到,在构造函数中,默认地使用了0x00作为_extraSizeTable的大小,并将其值放入[edi+4]处,及类首地址便宜为0x04处,此时再看
7e2b5d45 668148068080    or      word ptr [eax+6],8080h       //注意此处,稍后会加以说明
 
[eax+4]处为__extraSizeTable的大小,而[eax+6]处为0x8080,可以猜测_extraSizeTable的数据大小应该为2字节,但事实是否如此,在最后还有一个说法。
 
通过以上的分析,可以看到,在创建CdispContainer的时候,因为使用默认的0作为_extraSizeTable的大小,从而未分配内存,在其后的mshtml!CDispNode::SetUserClip函数中,需要对_extraSizeTable进行修改,而没有进行严格的检验,从而造成了漏洞的产生。
 
以上就是从逆向的角度分析的该漏洞的成因,至于原理方面,在看雪已经有大牛发过该漏洞的分析贴,在此附上链接,不再赘述:
http://bbs.pediy.com/showthread.php?t=125122
 
 
可能因为环境测试环境不同,造成分析结果会有一些差异,根据个人的调试过程,在此对llydd大大的分析提出一点质疑:
.text:7E36B4C4 CDispNode::SetUserClip
...............................
.text:7E36B54D                 mov     eax, [edi+4] <-------当这里为0时,虚函数表就被悲剧了.
.text:7E36B550                 and     eax, esi
.text:7E36B552       movzx   ecx, ds:uchar const * const CDispNode::_extraSizeTable[eax]
.text:7E36B559                 mov     eax, edi
.text:7E36B55B                 shl     ecx, 2
.text:7E36B55E                 sub     eax, ecx
.text:7E36B560                 or      dword ptr [eax], 1   <-----------------------虚函数表被改了
 
 
由前面的分析可以发现[edi+4]本身不为0,其值为0x8c800000,esi为0x0000000f,经过
7e40e3a9 23c6            and     eax,esi
 
运算之后,eax值才为0,事实上,由esi的值应该可以确定,_extraSizeTable的数据大小只有四位。
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2010 c byte 汇编 测试 windows