CVE-2010-3962逆向分析过程

    技术2024-07-24  26

    这个漏洞已经发布有一段时间了,现在假期有空,分析一下当作练手。

     

    运行环境:

    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 call 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,其值为0x8c800000esi0x0000000f,经过

    7e40e3a9 23c6 and eax,esi 

    运算之后,eax值才为0,事实上,由esi的值应该可以确定,_extraSizeTable的数据大小只有四位。

     

     

    最新回复(0)