CVE-2010-3962分析

比较老的漏洞,html解析器出了问题,<table style=position:absolute;clip:rect(0)>这个极品代码会导致类的虚函数表被覆盖一位,然后地址就错位了。http://www.exploit-db.com/exploits/15421/ 可以找到POC,经典的heapspray;http://bbs.pediy.com/showthread.php?t=125122 解析过程导致漏洞触发分析。我这里就是用windbg调一下,触发并找到问题所在。winxp sp3 + IE6 。

首先把POC的shellcode开头改成CCCC,windbg载入IE,这里可以设置利用页面为首页,方便.restart。直接跑起来,执行到shellcode自动断下。

(c34.854): Break instruction exception - code 80000003 (first chance)
eax=ffeffffd ebx=0012e1ec ecx=01769420 edx=3fffffff esi=00000000 edi=01769420
eip=0d81b641 esp=0012e1a0 ebp=0012e1b0 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000282
0d81b641 cc              int     3

u可以看到这里确实是走到shellcode了。

0:000> u
0d81b641 cc              int     3
0d81b642 cc              int     3
0d81b643 cc              int     3
0d81b644 cc              int     3
0d81b645 cc              int     3
0d81b646 0000            add     byte ptr [eax],al
0d81b648 60              pushad
0d81b649 89e5            mov     ebp,esp

查看此时堆栈:

0:000> k
ChildEBP RetAddr  
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012e19c 7e291a8d 0xd81b641
0012e1b0 7e2c6104 mshtml!CLayout::EnsureDispNodeBackground+0x97
0012e274 7e2c5365 mshtml!CTableLayoutBlock::EnsureTableDispNode+0x388
0012e454 7e2c5b4a mshtml!CTableLayout::CalculateLayout+0x295
0012e5a4 7e28b788 mshtml!CTableLayout::CalcSizeVirtual+0x665
0012e6b8 7e2d203b mshtml!CLayout::CalcSize+0x224
mshtml!CLayout::EnsureDispNodeBackground+0x97发起某个调用之后就进入了shellcode,反汇编这个函数看看发生了什么。
0:000> x mshtml!CLayout::EnsureDispNodeBackground
7e291a3f mshtml!CLayout::EnsureDispNodeBackground = 
7e3fd9ba mshtml!CLayout::EnsureDispNodeBackground = 

C++类往往会有好多重载函数,所以这里需要查找符号,然后判断出问题的是哪个函数,这里明显是第一个。

0:000> uf 7e291a3f
......
mshtml!CLayout::EnsureDispNodeBackground+0x88:
7e291a7e 56              push    esi
7e291a7f 8bcf            mov     ecx,edi
7e291a81 e80be2ffff      call    mshtml!CDispNode::SetBackground (7e28fc91)
7e291a86 8b07            mov     eax,dword ptr [edi]
7e291a88 8bcf            mov     ecx,edi
7e291a8a ff5030          call    dword ptr [eax+30h]
7e291a8d 85c0            test    eax,eax
7e291a8f 7587            jne     mshtml!CLayout::EnsureDispNodeBackground+0x9b (7e291a18)

可以看7e291a8a处调用 [eax + 30h] 时进入了shellcode。这里很明显ecx是类基址,eax指向虚地址表。所以我们需要查找虚表地址以及它如何被修改。

0:007> bp 7E291A88 ".printf \"\n======================Object: 0x%08x, VirtualTable: 0x%08x, Address of [eax+30]: 0x%08x====================\n\",@edi, @eax, poi(@eax+30);.echo;g"
0:007> g
ModLoad: 75bc0000 75c3d000   C:\WINDOWS\system32\jscript.dll
 ======================Object: 0x01768cb4, VirtualTable: 0x7e239178, Address of [eax+30]: 0x7e27cbee==================== 
 ======================Object: 0x01768cb4, VirtualTable: 0x7e239178, Address of [eax+30]: 0x7e27cbee==================== 
 ======================Object: 0x01769420, VirtualTable: 0x7e2233f1, Address of [eax+30]: 0x0d7e27c9==================== 
(7fc.630): Break instruction exception - code 80000003 (first chance)
eax=ffeffffd ebx=0012e1ec ecx=01769420 edx=3fffffff esi=00000000 edi=01769420
eip=0d81b641 esp=0012e1a0 ebp=0012e1b0 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000282
0d81b641 cc              int     3
0:000> dd 01769420
01769420  7e2233f1 01000000 00000000 00000000

可以发现第三个输出的VirtualTable很奇怪,根本没有对齐,进一步分析发现果然有猫腻。

0:007> ba w 4 0x01769420 ".printf \"\n======================Dangerous EIP: 0x%08x, Virtual Table: 0x%08x====================\n\", @eip, poi(0x01769420);.echo;g"
0:007> g
ModLoad: 75bc0000 75c3d000   C:\WINDOWS\system32\jscript.dll
 ======================Dangerous EIP: 0x7e277f35, Virtual Table: 0x00000000==================== 
 ======================Dangerous EIP: 0x7e2b5d74, Virtual Table: 0x7e2233f0==================== 
 ======================Dangerous EIP: 0x7e40e3bc, Virtual Table: 0x7e2233f1==================== 
 ======================Dangerous EIP: 0x7e40e3d2, Virtual Table: 0x7e2233f1==================== 

可以发现在第三个地方0x7e40e3bc VirtualTable地址被增加了1。看一下增加1的恶果:

0:000> dd 0x7e2233f1+30
7e223421  0d7e27c9 0d7e27c9 d97e27c9 9a7e28fa
7e223431  4e7e2919 d17e2b40 687e28a7 607e2cfe
7e223441  6f7e28b8 fe7e2e94 1a7e28af c67e2d2e
7e223451  537e2b99 61007400 6b006300 6f002000
7e223461  65007600 66007200 6f006c00 00007700
7e223471  27909000 cb332c44 b411d026 4fc00083
7e223481  7f1901d9 d17e2a7c 0d7e27a2 417e27a3
7e223491  e07e2ecb e87e2a7f c67e3ab2 4ad48a6e
0:000> dd 0x7e2233f0+30
7e223420  7e27c90d 7e27c90d 7e27c90d 7e28fad9
7e223430  7e29199a 7e2b404e 7e28a7d1 7e2cfe68
7e223440  7e28b860 7e2e946f 7e28affe 7e2d2e1a
7e223450  7e2b99c6 00740053 00630061 0020006b
7e223460  0076006f 00720065 006c0066 0077006f
7e223470  90900000 332c4427 11d026cb c00083b4
7e223480  1901d94f 7e2a7c7f 7e27a2d1 7e27a30d
7e223490  7e2ecb41 7e2a7fe0 7e3ab2e8 d48a6ec6
0:000> u 7e27c90d
mshtml!CLayout::IsDirty:
7e27c90d 33c0            xor     eax,eax
7e27c90f c3              ret
7e27c910 8b5508          mov     edx,dword ptr [ebp+8]
7e27c913 889c3710040000  mov     byte ptr [edi+esi+410h],bl
7e27c91a e977b6ffff      jmp     mshtml!__sbh_alloc_block+0x7f (7e277f96)
7e27c91f 83f809          cmp     eax,9
7e27c922 0f84ea240000    je      mshtml!VariantClear+0x38 (7e27ee12)
7e27c928 83f80b          cmp     eax,0Bh
0:000> u 0d7e27c9
0d7e27c9 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27ce 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27d3 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27d8 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27dd 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27e2 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27e7 0d0d0d0d0d      or      eax,0D0D0D0Dh
0d7e27ec 0d0d0d0d0d      or      eax,0D0D0D0Dh

果然,修改之后全错位了,导致大量申请内存可以hit。看一下导致变化的那个邪恶EIP归属何处,进而就可以找到出问题的地方了。

0:000> u 0x7e40e3bc
mshtml!CDispNode::SetUserClip+0x9f:
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
7e40e3d2 8b4704          mov     eax,dword ptr [edi+4]
0:000> u 0x7e40e3d2
mshtml!CDispNode::SetUserClip+0xb5:
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]

原来是在mshtml!CDispNode::SetUserClip,网上好多对这个漏洞的分析,使用了很多其他的方法,最终都定位到了这个函数。

0:000> uf 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
7e40e329 8b4704          mov     eax,dword ptr [edi+4]
7e40e32c 2500108800      and     eax,881000h
7e40e331 3d00108000      cmp     eax,801000h
7e40e336 6a0f            push    0Fh
7e40e338 5e              pop     esi
7e40e339 7548            jne     mshtml!CDispNode::SetUserClip+0x66 (7e40e383)
......
mshtml!CDispNode::SetUserClip+0x66:
7e40e383 804f0704        or      byte ptr [edi+7],4
7e40e387 6800000008      push    8000000h
7e40e38c 8bcf            mov     ecx,edi
7e40e38e e8fae5e7ff      call    mshtml!CDispNode::SetFlagsToRoot (7e28c98d)
7e40e393 ff7508          push    dword ptr [ebp+8]
7e40e396 8d4df0          lea     ecx,[ebp-10h]
7e40e399 e8e9bce7ff      call    mshtml!CRect::CRect (7e28a087)
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
7e40e3ab 0fb688101c217e  movzx   ecx,byte ptr mshtml!CDispNode::_extraSizeTable (7e211c10)[eax]
7e40e3b2 8bc7            mov     eax,edi
7e40e3b4 c1e102          shl     ecx,2
7e40e3b7 2bc1            sub     eax,ecx
7e40e3b9 830801          or      dword ptr [eax],1
......

注意这个反汇编代码的最后一行,往前推eax的变化过程:eax=dword ptr [edi+4],edi是类基址,eax指向某个成员变量;and eax, esi之后eax为0; 之后 eax = edi - 4×ecx,ecx=mshtml!CDispNode::_extraSizeTable;也就是说如果ecx=0,那么eax就是edi的值,也就是 类基址。最后一句 or dword ptr [eax],1 恰好让最后一位0变成了1,虚表地址被修改,悲剧发生。mshtml!CDispNode::_extraSizeTable作为成员变量,肯定是构造函 数产生的,这里看一下CDispNode的 New函数。

0:000> x mshtml!CDispContainer::New
7e2b5d4d mshtml!CDispContainer::New = 
7e2d5e03 mshtml!CDispContainer::New = 

同样是重载函数,都看了看之后感觉出事的是第一个。

0:000> uf 7e2b5d4d 
mshtml!CDispContainer::New:
7e2b5d4d 8bff            mov     edi,edi
7e2b5d4f 55              push    ebp
7e2b5d50 8bec            mov     ebp,esp
7e2b5d52 ff750c          push    dword ptr [ebp+0Ch]
7e2b5d55 6a00            push    0
7e2b5d57 6a48            push    48h
7e2b5d59 e8d1bdfdff      call    mshtml!CDispNode::operator new (7e291b2f)
7e2b5d5e 85c0            test    eax,eax
7e2b5d60 7416            je      mshtml!CDispContainer::New+0x29 (7e2b5d78)
mshtml!CDispContainer::New+0x15:
7e2b5d62 8b4d08          mov     ecx,dword ptr [ebp+8]
7e2b5d65 668148068080    or      word ptr [eax+6],8080h
7e2b5d6b 894824          mov     dword ptr [eax+24h],ecx
7e2b5d6e c700f033227e    mov     dword ptr [eax],offset mshtml!CDispContainer::`vftable' (7e2233f0)
mshtml!CDispContainer::New+0x2b:
7e2b5d74 5d              pop     ebp
7e2b5d75 c20800          ret     8
mshtml!CDispContainer::New+0x29:
7e2b5d78 33c0            xor     eax,eax
7e2b5d7a ebf8            jmp     mshtml!CDispContainer::New+0x2b (7e2b5d74)
0:000> uf 7e291b2f
mshtml!CDispNode::operator new:
7e291b2f 8bff            mov     edi,edi
7e291b31 55              push    ebp
7e291b32 8bec            mov     ebp,esp
7e291b34 51              push    ecx
7e291b35 51              push    ecx
7e291b36 8b4508          mov     eax,dword ptr [ebp+8]
7e291b39 53              push    ebx
7e291b3a 8b5d10          mov     ebx,dword ptr [ebp+10h]
7e291b3d 56              push    esi
7e291b3e 0fb6b3101c217e  movzx   esi,byte ptr mshtml!CDispNode::_extraSizeTable (7e211c10)[ebx]
7e291b45 c1e602          shl     esi,2
7e291b48 57              push    edi
7e291b49 03c6            add     eax,esi
7e291b4b 50              push    eax
7e291b4c e87563feff      call    mshtml!_MemAllocClear (7e277ec6)
7e291b51 8bf8            mov     edi,eax
7e291b53 85ff            test    edi,edi
7e291b55 740e            je      mshtml!CDispNode::operator new+0x47 (7e291b65)
mshtml!CDispNode::operator new+0x28:
7e291b57 03fe            add     edi,esi
7e291b59 f6c340          test    bl,40h
7e291b5c 895f04          mov     dword ptr [edi+4],ebx
7e291b5f 0f85391b0a00    jne     mshtml!CDispNode::operator new+0x32 (7e33369e)
mshtml!CDispNode::operator new+0x47:
7e291b65 8bc7            mov     eax,edi
7e291b67 5f              pop     edi
7e291b68 5e              pop     esi
7e291b69 5b              pop     ebx
7e291b6a c9              leave
7e291b6b c20c00          ret     0Ch
mshtml!CDispNode::operator new+0x32:
7e33369e 8365f800        and     dword ptr [ebp-8],0
7e3336a2 8365fc00        and     dword ptr [ebp-4],0
7e3336a6 6aff            push    0FFFFFFFFh
7e3336a8 8d45f8          lea     eax,[ebp-8]
7e3336ab 50              push    eax
7e3336ac 8bcf            mov     ecx,edi
7e3336ae e8de9b0d00      call    mshtml!CDispNode::SetContentOriginNoInval (7e40d291)
7e3336b3 e9ade4f5ff      jmp     mshtml!CDispNode::operator new+0x47 (7e291b65)

注意到三个参数,如果不管的话第二个参数默认是0,所以会导致mshtml!CDispNode::_extraSizeTable是0,这就是后面悲剧发生的罪魁祸首。看一下NEW何时被调用:

0:007> bp 7e2b5d4d ".printf \"\n======================EIP And KV====================\n\";.echo; kb 3; g"
0:007> g
ModLoad: 75bc0000 75c3d000   C:\WINDOWS\system32\jscript.dll
 ======================EIP And KV==================== 
ChildEBP RetAddr  Args to Child              
0012e1b0 7e329f51 017687ac 00000008 0012e578 mshtml!CDispContainer::New
0012e274 7e2c5365 0012e4e8 00000000 00000000 mshtml!CTableLayoutBlock::EnsureTableDispNode+0xf8
0012e454 7e2c5b4a 00000000 ffffffff ffffffff mshtml!CTableLayout::CalculateLayout+0x295
 ======================EIP And KV==================== 
ChildEBP RetAddr  Args to Child              
0012e1b0 7e2c60a4 017687ac 00000000 0012e578 mshtml!CDispContainer::New
0012e274 7e2c5365 0012e4e8 00000000 00000000 mshtml!CTableLayoutBlock::EnsureTableDispNode+0x2d9
0012e454 7e2c5b4a 00000000 ffffffff ffffffff mshtml!CTableLayout::CalculateLayout+0x295
(55c.f54): Break instruction exception - code 80000003 (first chance)
eax=ffeffffd ebx=0012e1ec ecx=01769420 edx=3fffffff esi=00000000 edi=01769420
eip=0d81b641 esp=0012e1a0 ebp=0012e1b0 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000282
0d81b641 cc              int     3

回忆一下此时堆栈:

0:000> k
ChildEBP RetAddr  
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012e19c 7e291a8d 0xd81b641
0012e1b0 7e2c6104 mshtml!CLayout::EnsureDispNodeBackground+0x97
0012e274 7e2c5365 mshtml!CTableLayoutBlock::EnsureTableDispNode+0x388
0012e454 7e2c5b4a mshtml!CTableLayout::CalculateLayout+0x295
0012e5a4 7e28b788 mshtml!CTableLayout::CalcSizeVirtual+0x665
0012e6b8 7e2d203b mshtml!CLayout::CalcSize+0x224

无缝结合,这个洞算是搞清楚了。

总结:

<table style=position:absolute;clip:rect(0)>一句话触发漏洞。一个table,裁剪时参数为0,导致mshtml!CTableLayout::CalculateLayout 中创建CDispNode时mshtml!CDispNode::_extraSizeTable 为0,后来覆盖了虚表。然后通过HeapSpray覆盖EIP。

CDispNode要保存动态的裁剪表,就在虚表前面,如果没有裁剪表,修改的时候就会把VT改掉。结合IE渲染的原理能理解得更透彻。另外几个windbg的命令使用的也不错。