Internet Explorer Script Interjection Code Execution
Derek Soeder
ds.adv.pub@gmail.com
Reported: January 26, 2012, to SecuriTeam Secure Disclosure
http://www.beyondsecurity.com/ssd.html
Published: August 16, 2012
AFFECTED VENDOR
---------------
Microsoft Corporation
AFFECTED ENVIRONMENTS
---------------------
Internet Explorer 7.0 on Windows XP and Windows Vista
Internet Explorer 8.0 on Windows XP, Windows Vista, and Windows 7
Internet Explorer 9.0.0 through 9.0.8 (MS12-044) on Windows Vista and Windows 7
Other versions of Internet Explorer have not been tested.
UNAFFECTED ENVIRONMENTS
-----------------------
Internet Explorer with MS12-052 hotfix applied
IMPACT
------
The vulnerability described in this document can be exploited by a
malicious Web page to execute arbitrary code with low integrity.
Active scripting must be enabled, and the present exploitation
techniques require that font downloading be set to "Enable" or
"Prompt" and that the "mailto:" protocol be present. (These
requirements are satisfied by default on Windows XP, Windows Vista,
and Windows 7.) The user is presented with a message box which must
be dismissed before code execution can occur.
VULNERABILITY DETAILS
---------------------
Processing of events in Internet Explorer is typically driven by
window messages originating both externally (for instance, due to user
input or paint requests) and internally. As with all window messages,
these messages are retrieved from the current thread's message queue
by a message loop, which dispatches each message to a window
procedure. The window procedure, in turn, invokes code to handle the
associated event based on the type of window message. If the event
handling code can be made to display a message box or dialog, or
otherwise enter a message loop, then another window message relating
to a separate, second event may be dispatched during this "stacked,"
second message loop, meaning the second event will be processed before
the original event has been fully handled. Processing of the original
event continues only after the second message loop has ended (i.e.,
when the displayed message box or dialog closes). If the second event
handling code can cause the program's state to become inconsistent
with the first event handling code's expectations--for instance, by
destroying objects referenced in variables local to the first event
handling code--then it should be possible to cause memory corruption
which can be exploited to achieve arbitrary code execution.
A variety of events can result in script running during the event
handler code. Although it's simple for script to display a message
box or dialog and thereby enter a message loop (e.g., using
window.alert, window.prompt, or window.clipboardData.getData under
default security settings), so far it does not appear that an
interrupting, second event handler can then do anything to disrupt
program state in a way that the first event handler will not
accommodate. This is understandable, since script must be able to
handle other script running at any time and having arbitrary effects
on program state. Objects accessible to script should be properly
reference-counted and garbage-collected, and any exception would
constitute a separate vulnerability that could likely be exploited
without use of the flaw described in this document.
In some cases, it's also possible to make MSHTML.DLL enter a message
loop while handling a page rendering event (as opposed to an event
intended to run script). For one, MSHTML!CMarkup::ProcessURLAction*
is used to check a variety of security settings during page
downloading and rendering; this function calls
URLMON!ProcessUrlAction*, which may display a dialog if the queried
setting's action is set to "Prompt". Unfortunately, most of the
security settings which default to prompting are now handled through
the yellow security band or notification bar rather than a dialog.
Other avenues for reaching a message loop may be discovered by
backtracking from functions such as DispatchMessageW, MessageBoxW, and
DialogBoxParamW. One function call of particular interest is a call
to MessageBoxW found in
MSHTML!CMailtoProtocol::DisplayMailClientNotFoundError. It was
discovered that, if Internet Explorer attempts to download a very long
(approximately 2,030-character) "mailto:" URL, then
CMailtoProtocol::RunMailClient will fail and call
CMailtoProtocol::DisplayMailClientNotFoundError to display a message
box, thereby entering a message loop. (The message reads, "Could not
perform this operation because the default mail client is not properly
installed.") Furthermore, it was found that displaying this message
box while downloading an embedded font (by specifying a long "mailto:"
URL for the font's "src" property) will result in references to
targetable objects remaining on the stack until the message box is
closed. Thus, a Web page can exploit this vulnerability by declaring
an embedded font with a long "mailto:" source URL and ensuring that an
event which destroys and replaces targetable objects occurs while the
message box is open. Although the particulars of the targetable
objects are Internet Explorer version-dependent, exploitation should
generally proceed as typical for an Internet Explorer use-after-free
vulnerability.
Events
The most significant complexity of this vulnerability is understanding
Internet Explorer's event handling. As mentioned above, event
handling is based on the processing of window messages. Some window
messages may arise from user input (such as keyboard and mouse
messages), while others may be generated by the operating system (such
as paint and resize messages), but most messages signaling events are
generated interally by Internet Explorer. These messages use a
message identifier value of 0x8002 and are generated when a "method
call" is added to a queue maintained in Thread Local Storage (TLS), if
the queue is empty. A method call is simply a function pointer and
associated data representing a callback to be invoked by the event
handling message loop (or any other message loop). Method calls are
queued using MSHTML!_GWPostMethodCallEx and handled by
MSHTML!GlobalWndOnMethodCall, which the MSHTML!GlobalWndProc window
procedure calls in response to a message 0x8002.
It is important to note that a message 0x8002 will only be posted if
the method call queue is empty and if a message 0x8002 is not
outstanding (being processed or waiting to be processed). Therefore,
with possibly one minor exception, a second message 0x8002 cannot be
pending while a first message 0x8002 is being processed, meaning a
second method call-based event cannot be handled while a first method
call-based event is being handled, even if the first enters a message
loop. When exploiting the vulnerability, one event may be based on a
method call, but the other must correspond to user input or some other
type of message.
Although designing a Web page to provoke a user input message without
user interaction is not difficult, Internet Explorer 9 offers another
possibility by introducing asynchronous events. If a Web page is
viewed in IE9 standards mode, certain events (for example,
body.onfocus) will instead be mediated by messages with an identifier
value of 0x8003, which are generated via
MSHTML!CEventMgr::QueueAsyncEvent ->
MSHTML!CAsyncEventQueue::QueueEvent and processed when GlobalWndProc
calls MSHTML!CAsyncEventQueue::DispatchAllEvents. If the asynchronous
event handling code enters a message loop, a message 0x8002 could then
be dispatched and cause any queued method calls to be processed.
Example (Internet Explorer 7 and 8)
A simple example of how to reproduce this vulnerability in Internet
Explorer versions 7 and 8 follows. A Web page contains an empty style
sheet link, a body with an "onmouseover" event handler, and a script
element which creates a new script element and assigns it an
"onreadystatechange" event handler. The body also has a style which
specifies a large height value, so that the body area will occupy the
full height as well as width of the browser window. The following
HTML illustrates:
[redacted for now]
When the Web page loads, the presence of the mouse cursor over the
window causes MSHTML!CServer::WndProc to receive a mouse window
message, which it passes to MSHTML!CDoc::OnWindowMessage ->
MSHTML!CDoc::OnMouseMessage. Further up the call stack, the script of
the body's "onmouseover" event handler runs, setting the empty style
sheet link's "href" attribute to load "MyFont.css". When the CSS
defining the "MyFont" embedded font is parsed, the long "mailto:" URL
will ultimately result in
CMailtoProtocol::DisplayMailClientNotFoundError displaying an error
message box, pausing execution of that thread except to process window
messages. Using the "onmouseover" event handler for this purpose
ensures that the message box will appear during processing of a user
input window message, rather than during processing of a method call
(0x8002) window message, which leaves the method call avenue available
for the second event.
While the message box is showing, our attack server completes its
intentionally delayed response to the request for "slow.js", causing
the client to queue a method call which will run the new script
element's "onreadystatechange" event handler. Because a method call
(message 0x8002) is not currently being processed--the event being
processed originated instead as a mouse window message--this means the
thread responsible for downloading "slow.js" is free to post a message
0x8002 after it queues the method call. The window message will then
be dispatched by the message loop that drives the error message box,
causing the "onreadystatechange" event handler to run. In this
example, the event handler tampers with the object representing the
style sheet, which was still being interpreted at the time the message
box was displayed. The tampering provokes a crash once the message
box closes and interpretation of the style sheet is allowed to
continue.
Example (Internet Explorer 9)
Now a simple example specific to Internet Explorer 9 is presented. A
Web page contains a body with an "onfocus" event handler, a style
sheet defining an embedded font and a class which uses it, a "div"
element of the defined class, and a script element which creates a new
script element and assigns it an "onreadystatechange" event handler.
The document begins with a "DOCTYPE" declaration which ensures that
the page will be rendered in IE9 standards mode. The following HTML
illustrates:
[redacted for now]
In IE9 standards mode, embedded fonts are not downloaded until they're
needed to render the page, meaning that the embedded font's long
"mailto:" URL is interpreted--and therefore the error message box is
displayed--when the body's "onfocus" event fires. Because
body.onfocus is handled in IE9 standards mode as an asynchronous event
(message 0x8003), method calls (message 0x8002) remain free to be
dispatched while the message box message loop is on the call stack.
In this example, we expect "slow.js" to finish downloading after
body.onfocus fires and causes the error message box to appear. The
code in IE that manages the download will queue an
"onreadystatechange" method call for the script, which will be
dispatched by the message box message loop, allowing our Javascript to
execute. Since IE9 accesses embedded fonts on demand, there will be
references to various object on the stack below the message box
message loop, so if our Javascript tampers with these objects, a crash
will result once the message box is closed.
Walkthrough
To help provide a visual understanding of the vulnerability, a
chronological walkthrough of the Internet Explorer 9 example crash is
presented here. Following along in the example is recommended. The
symbols shown correspond to Internet Explorer 9.0.3 on Windows 7 SP1
x86, with MSHTML.DLL version 9.0.8112.16437 loaded at 6D1C0000 and
page heap enabled.
When the example page is loading, a 0x54-byte CTreePos class instance
is allocated on the heap: (This CTreePos instance will be freed and
its memory reused later.)
77365ae0 ntdll!RtlAllocateHeap+0x0000023a
6d423fe1 MSHTML!CHtmRootParseCtx::BeginElement+0x00000035
6d51b14b MSHTML!CHtmTextParseCtx::BeginElement+0x000000a1
6d4245a0 MSHTML!CHtmParse::BeginElement+0x00000151
6d4269aa MSHTML!CHtmParse::ParseBeginTag+0x00000199
6d422422 MSHTML!CHtmParse::ParseToken+0x00000100
6d42292a MSHTML!CHtmPost::Exec+0x00000233
6d427a10 MSHTML!CHtmPost::Run+0x00000041
6d42793c MSHTML!PostManExecute+0x000001a3
6d4278a1 MSHTML!PostManResume+0x000000dd
6d427801 MSHTML!CHtmPost::OnDwnChanCallback+0x00000010
6d40b4d5 MSHTML!CDwnChan::OnMethodCall+0x0000001f
6d5a9d09 MSHTML!GlobalWndOnMethodCall+0x00000115
6d5c9368 MSHTML!GlobalWndProc+0x00000302
7748c4e7 USER32!InternalCallWinProc+0x00000023
7748c5e7 USER32!UserCallWinProcCheckWow+0x0000014b
7748cc19 USER32!DispatchMessageWorker+0x0000035e
7748cc70 USER32!DispatchMessageW+0x0000000f
6e8e1b44 IEFRAME!CTabWindow::_TabWindowThreadProc+0x00000722
6e901a16 IEFRAME!LCIETab_ThreadProc+0x00000317
759315b0 iertutil!CIsoScope::RegisterThread+0x000000ab
6e8efd5b IEFRAME!Detour_DefWindowProcA+0x0000006c
75c4ed6c kernel32!BaseThreadInitThunk+0x0000000e
773737f5 ntdll!__RtlUserThreadStart+0x00000070
773737c8 ntdll!_RtlUserThreadStart+0x0000001b
Next, the page's Javascript executes, creating a new script element
with a source of "slow.js". The idea is that the Web server will
intentionally postpone serving this file for a second or two. This
arranges for an "onreadystatechange" event to fire after the delay
elapses.
Once the page finishes loading (but before the delay has elapsed), the
"body.onfocus" event fires. Because the document is in IE9 standards
mode, "body.onfocus" will be queued as an asynchronous event, meaning
it will be mediated by window message 0x8003. The "body.onfocus"
event handler changes a "div" element's class to a class that uses an
embedded font. This forces Internet Explorer to attempt to download
the font, which fails due to the long "mailto:" URL. Crucially, the
failure triggers a "mailto"-specific message box to be displayed; this
enters a new, top message loop during the original, bottom message
loop's handling of the 0x8003 window message associated with the
"body.onfocus" event. The call stack, from top to bottom, now looks
like this:
774a382a USER32!NtUserWaitMessage+0xc
774a3b27 USER32!DialogBox2+0x207
774ce0d5 USER32!InternalDialogBox+0xcb
774ce659 USER32!SoftModalMessageBox+0x68a
774ce78c USER32!MessageBoxWorker+0x2ca
774cea08 USER32!MessageBoxTimeoutW+0x7f
6ea15e86 USER32!MessageBoxExW+0x1b
774ceaa4 IEFRAME!Detour_MessageBoxExW+0x47
6db3ac94 USER32!MessageBoxW+0x45
6db3aaf1 MSHTML!CMailtoProtocol::DisplayMailClientNotFoundError+0x10b
6db3a2cc MSHTML!CMailtoProtocol::RunMailClient+0x12e
6db39def MSHTML!CMailtoProtocol::ParseAndBind+0x8b
76ab1c0b MSHTML!CMailtoProtocol::Start+0xcd
76a98fb3 URLMON!COInetProt::StartEx+0xf0
76a9a31f URLMON!CTransaction::StartEx+0x40b
76a8386c URLMON!CBinding::StartBinding+0x883
6d438507 URLMON!operator new+0x20
6d4383ed MSHTML!CTridentFilterHost::BindToMoniker+0xe4
6d4216f3 MSHTML!CDwnBindData::Bind+0x722
6d42153b MSHTML!NewDwnBindData+0x189
6d20c107 MSHTML!CDwnLoad::Init+0x25c
6d5c1f27 MSHTML!CBitsLoad::Init+0x52
6d421279 MSHTML!CDwnInfo::SetLoad+0x11e
6d451257 MSHTML!CDwnInfo::AddDwnCtx+0x67
6d42c695 MSHTML!CDoc::NewDwnCtx2+0x30a
6d953c33 MSHTML!CDoc::NewDwnCtx+0x5b
6d956222 MSHTML!CEmbeddedFontFace::EnsureStartDownload+0x120
6d955aee MSHTML!CFontFace::CFontFaceSrc::EnsureStartDownload+0x8a
6d682c20 MSHTML!CFontFace::AddToFamily+0x18c
6d52ceb2 MSHTML!CStyleSheetArray::BuildFontFaceRuleFamily+0x58
6d52cd28 MSHTML!ApplyClear+0x113
6d51bc41 MSHTML!ApplyFontFace+0x1d4
6d40e103 MSHTML!ApplyFormatInfoProperty+0x33bf
6d40e424 MSHTML!ApplyAttrArrayValues+0x2bd
6d5b5344 MSHTML!CStyleSheetArray::Apply+0x34a
6d47bad8 MSHTML!CMarkup::ApplyStyleSheets+0x6a
6d47b89e MSHTML!CElement::ApplyStyleSheets+0x4a2
6d4cddff MSHTML!CElement::ApplyDefaultFormat+0x8b
6d47b5a0 MSHTML!CBlockElement::ApplyDefaultFormat+0x379
6d47a5a3 MSHTML!CElement::ComputeFormatsVirtual+0x1a1e
6d47a4d6 MSHTML!CElement::ComputeFormats+0xe1
6d47bd39 MSHTML!CTreeNode::ComputeFormats+0xba
6d482d33 MSHTML!CTreeNode::ComputeFormatsHelper+0x40
6d360862 MSHTML!CTreeNode::GetFancyFormat+0x32
6d2d910f MSHTML!CElement::UpdateFormats+0x426
6d4ce10f MSHTML!CControlledFormatter::Init+0xcc
6d47fa14 MSHTML!CElement::OnPropertyChangeInternal+0x3fa
6d49b76b MSHTML!CElement::OnPropertyChange+0x1b
6d2da8db MSHTML!BASICPROPPARAMS::SetStringProperty+0x36a
6d0084d6 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_className+0x61
6d0cc04d JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4
6d0cc968 JSCRIPT9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117
6d009a85 JSCRIPT9!Js::JavascriptOperators::SetProperty+0x8c
6d009a2c JSCRIPT9!Js::JavascriptOperators::OP_SetProperty+0x59
039507b8 JSCRIPT9!Js::JavascriptOperators::PatchPutValueNoLocalFastPath+0xbc
6d0084d6 0x39507b8
6d0083fb JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4
6d008332 JSCRIPT9!Js::JavascriptFunction::CallRootFunction+0xb6
6d0082be JSCRIPT9!ScriptSite::CallRootFunction+0x4f
6d0cf12c JSCRIPT9!ScriptSite::Execute+0x63
6d4f24d1 JSCRIPT9!ScriptEngine::Execute+0x11a
6d4f23fb MSHTML!CListenerDispatch::InvokeVar+0x12a
6d54ce40 MSHTML!CListenerDispatch::Invoke+0x40
6d44e624 MSHTML!CEventMgr::_InvokeListeners+0x187
6d54cf37 MSHTML!CEventMgr::_InvokeListenersOnWindow+0xcc
6d5db67d MSHTML!CEventMgr::Dispatch+0x3cc
6d53ba32 MSHTML!CEventMgr::DispatchFocusEvent+0x7d
6d5e6f74 MSHTML!COmWindowProxy::Fire_onfocus+0x84
6d5e6ff1 MSHTML!CAsyncEventQueue::DispatchAllEvents+0x7c
7748c4e7 MSHTML!GlobalWndProc+0x2ed
7748c5e7 USER32!InternalCallWinProc+0x23
7748cc19 USER32!UserCallWinProcCheckWow+0x14b
7748cc70 USER32!DispatchMessageWorker+0x35e
6e8e1b44 USER32!DispatchMessageW+0xf
6e901a16 IEFRAME!CTabWindow::_TabWindowThreadProc+0x722
759315b0 IEFRAME!LCIETab_ThreadProc+0x317
6e8efd5b IERTUTIL!CIsoScope::RegisterThread+0xab
75c4ed6c IEFRAME!Detour_DefWindowProcA+0x6c
773737f5 KERNEL32!BaseThreadInitThunk+0xe
773737c8 NTDLL!__RtlUserThreadStart+0x70
00000000 NTDLL!_RtlUserThreadStart+0x1b
As long as the message box remains open, its message loop will
dispatch new window message-mediated events, and control won't return
to Internet Explorer's original message loop. It doesn't matter which
message loop is dispatching messages, because the same window
procedure is executed in either case. The only problem is that the
code lower on the call stack was operating on various heap objects
(such as the CTreePos allocated earlier) before control entered the
MessageBox call and became stuck. Now, if a window message-mediated
event results in the execution of Javascript that modifies or destroys
those heap objects, corruption manifesting as a use-after-free, for
instance, may result.
As belabored in the Vulnerability Details section, not every type of
event can be "stacked" in every situation like this, but certain
different events can. An 0x8003 window message (for "body.onfocus")
was being processed during the bottom message loop, so if an 0x8002
window message is posted, it will be processed during the top message
loop--and this is exactly what the example has arranged to happen.
Once the delay in serving "slow.js" elapses, an 0x8002 window
message-mediated event (referred to as a "method call") corresponding
to the concluded download will be posted and subsequently processed
during the top message loop. This method call executes the created
script element's "onreadystatechange" event handler, which destroys
the very "div" element that was in the process of being rendered when
Internet Explorer attempted to download the font and became stuck at
the message box. The following partial call stack shows "removeChild"
being called from the "onreadystatechange" event handler:
6d2eb4e3 MSHTML!CElement::ie9_removeChild
6d0084d6 MSHTML!CFastDOM::CNode::Trampoline_removeChild+0x7b
6d0cc04d JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4
039501af JSCRIPT9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117
6d0084d6 0x39501af
6d0083fb JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4
6d008332 JSCRIPT9!Js::JavascriptFunction::CallRootFunction+0xb6
6d0082be JSCRIPT9!ScriptSite::CallRootFunction+0x4f
6d0cf12c JSCRIPT9!ScriptSite::Execute+0x63
6d4f24d1 JSCRIPT9!ScriptEngine::Execute+0x11a
6d4f23fb MSHTML!CListenerDispatch::InvokeVar+0x12a
6d35a726 MSHTML!CListenerDispatch::Invoke+0x40
6d5db834 MSHTML!CEventMgr::Dispatch+0x537
6d4a5607 MSHTML!CEventMgr::DispatchEvent+0xc9
6d4a02ff MSHTML!CElement::Fire_onreadystatechange+0x99
6d5a9d09 MSHTML!CScriptElement::FireOnReadyStateChange+0x3e
6d5c9368 MSHTML!GlobalWndOnMethodCall+0x115
7748c4e7 MSHTML!GlobalWndProc+0x302
7748c5e7 USER32!InternalCallWinProc+0x23
7748cc19 USER32!UserCallWinProcCheckWow+0x14b
7748cc70 USER32!DispatchMessageWorker+0x35e
774a38d7 USER32!DispatchMessageW+0xf
774a3b27 USER32!DialogBox2+0x15a
774ce0d5 USER32!InternalDialogBox+0xcb
774ce659 USER32!SoftModalMessageBox+0x68a
774ce78c USER32!MessageBoxWorker+0x2ca
774cea08 USER32!MessageBoxTimeoutW+0x7f
6ea15e86 USER32!MessageBoxExW+0x1b
774ceaa4 IEFRAME!Detour_MessageBoxExW+0x47
6db3ac94 USER32!MessageBoxW+0x45
6db3aaf1 MSHTML!CMailtoProtocol::DisplayMailClientNotFoundError+0x10b
6db3a2cc MSHTML!CMailtoProtocol::RunMailClient+0x12e
6db39def MSHTML!CMailtoProtocol::ParseAndBind+0x8b
76ab1c0b MSHTML!CMailtoProtocol::Start+0xcd
...
The free actually happens in a subsequent method call, which is also
processing during the MessageBox message loop, as shown in the
following partial call stack:
75c4c3d4 kernel32!HeapFree+0x00000014
6d5eebed MSHTML!CTreePos::Release+0x00000046
6d5fdc69 MSHTML!CLayoutBlock::~CLayoutBlock+0x000000ba
6d5ff5da MSHTML!CFlexBoxBlock::`scalar deleting destructor'+0x00000013
6d559ee9 MSHTML!TSmartPointer<CPtsPelParaclient>::~TSmartPointer<CPtsPelParaclient>+0x00000014
6d5da773 MSHTML!HtmlLayout::SmartDispClient::Release+0x00000023
6d5da5fb MSHTML!HtmlLayout::FlowBox::ImplicitDestructor+0x0000001d
6d490144 MSHTML!HtmlLayout::CIE9DocumentLayout::FormatPage+0x00000065
6d48c517 MSHTML!CCssDocumentLayout::FindOrFormatPage+0x00000272
6d4872fb MSHTML!CCssDocumentLayout::GetPage+0x00000964
6d48e06f MSHTML!CMarkupPageLayout::CalcSize+0x0000028c
6d48de82 MSHTML!CMarkupPageLayout::CalcTopLayoutSize+0x00000101
6d48fba1 MSHTML!CMarkupPageLayout::DoLayout+0x00000056
6d47e65a MSHTML!CView::ExecuteLayoutTasks+0x00000034
6d476a85 MSHTML!CView::EnsureView+0x000003bf
6d498701 MSHTML!CView::EnsureViewCallback+0x000000b8
6d5a9d09 MSHTML!GlobalWndOnMethodCall+0x00000115
6d5c9368 MSHTML!GlobalWndProc+0x00000302
7748c4e7 USER32!InternalCallWinProc+0x00000023
7748c5e7 USER32!UserCallWinProcCheckWow+0x0000014b
7748cc19 USER32!DispatchMessageWorker+0x0000035e
7748cc70 USER32!DispatchMessageW+0x0000000f
774a38d7 USER32!DialogBox2+0x0000015a
774a3b27 USER32!InternalDialogBox+0x000000cb
774ce0d5 USER32!SoftModalMessageBox+0x0000068a
774ce659 USER32!MessageBoxWorker+0x000002ca
774ce78c USER32!MessageBoxTimeoutW+0x0000007f
...
At this point, a fully developed exploit might use Javascript to
reallocate and overwrite the memory formerly belonging to the
now-freed CTreePos. For the sake of this walkthrough, it suffices to
let page heap wipe the freed memory of the CTreePos with 0xF0.
Finally, once the user closes the message box, execution of the
interrupt font downloading and page rendering code continues, but the
code fails to anticipate that the program state has changed during the
MessageBox call. A pointer on the stack to the destroyed CTreePos is
dereferenced, resulting in an access violation. The following
register dump, disassembly, and call stack illustrate; notice that EBX
points to stack memory from which a pointer to the destroyed CTreePos
is taken:
Access violation - code c0000005 (first chance)
eax=005ba430 ebx=03b5c5c8 ecx=f0f0f0f0 edx=03b5c540 esi=00000000 edi=00557840
eip=6d47b5d7 esp=03b5c450 ebp=03b5c510 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
MSHTML!CElement::ComputeFormatsVirtual+0x1a64:
6d47b5d7 0fbf4120 movsx eax,word ptr [ecx+20h]
ds:0023:f0f0f110=????
6d47b5c5 8b03 mov eax,dword ptr [ebx]
6d47b5c7 8b8bd4000000 mov ecx,dword ptr [ebx+0D4h]
6d47b5cd 89442420 mov dword ptr [esp+20h],eax
6d47b5d1 894c242c mov dword ptr [esp+2Ch],ecx
6d47b5d5 8b08 mov ecx,dword ptr [eax]
6d47b5d7 0fbf4120 movsx eax,word ptr [ecx+20h]
6d47a5a3 MSHTML!CElement::ComputeFormatsVirtual+0x1a64
6d47a4d6 MSHTML!CElement::ComputeFormats+0xe1
6d47bd39 MSHTML!CTreeNode::ComputeFormats+0xba
6d482d33 MSHTML!CTreeNode::ComputeFormatsHelper+0x40
6d360862 MSHTML!CTreeNode::GetFancyFormat+0x32
6d2d910f MSHTML!CElement::UpdateFormats+0x426
6d4ce10f MSHTML!CControlledFormatter::Init+0xcc
6d47fa14 MSHTML!CElement::OnPropertyChangeInternal+0x3fa
6d49b76b MSHTML!CElement::OnPropertyChange+0x1b
6d2da8db MSHTML!BASICPROPPARAMS::SetStringProperty+0x36a
6d0084d6 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_className+0x61
6d0cc04d JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4
6d0cc968 JSCRIPT9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117
6d009a85 JSCRIPT9!Js::JavascriptOperators::SetProperty+0x8c
6d009a2c JSCRIPT9!Js::JavascriptOperators::OP_SetProperty+0x59
039507b8 JSCRIPT9!Js::JavascriptOperators::PatchPutValueNoLocalFastPath+0xbc
6d0084d6 0x39507b8
6d0083fb JSCRIPT9!Js::JavascriptFunction::CallFunction+0xc4
6d008332 JSCRIPT9!Js::JavascriptFunction::CallRootFunction+0xb6
6d0082be JSCRIPT9!ScriptSite::CallRootFunction+0x4f
6d0cf12c JSCRIPT9!ScriptSite::Execute+0x63
6d4f24d1 JSCRIPT9!ScriptEngine::Execute+0x11a
6d4f23fb MSHTML!CListenerDispatch::InvokeVar+0x12a
6d54ce40 MSHTML!CListenerDispatch::Invoke+0x40
6d44e624 MSHTML!CEventMgr::_InvokeListeners+0x187
6d54cf37 MSHTML!CEventMgr::_InvokeListenersOnWindow+0xcc
6d5db67d MSHTML!CEventMgr::Dispatch+0x3cc
6d53ba32 MSHTML!CEventMgr::DispatchFocusEvent+0x7d
6d5e6f74 MSHTML!COmWindowProxy::Fire_onfocus+0x84
6d5e6ff1 MSHTML!CAsyncEventQueue::DispatchAllEvents+0x7c
7748c4e7 MSHTML!GlobalWndProc+0x2ed
7748c5e7 USER32!InternalCallWinProc+0x23
7748cc19 USER32!UserCallWinProcCheckWow+0x14b
7748cc70 USER32!DispatchMessageWorker+0x35e
6e8e1b44 USER32!DispatchMessageW+0xf
6e901a16 IEFRAME!CTabWindow::_TabWindowThreadProc+0x722
759315b0 IEFRAME!LCIETab_ThreadProc+0x317
6e8efd5b IERTUTIL!CIsoScope::RegisterThread+0xab
75c4ed6c IEFRAME!Detour_DefWindowProcA+0x6c
773737f5 KERNEL32!BaseThreadInitThunk+0xe
773737c8 NTDLL!__RtlUserThreadStart+0x70
00000000 NTDLL!_RtlUserThreadStart+0x1b
EXPLOITATION
------------
Exploitation of this vulnerability is typical for a basic
use-after-free condition in Internet Explorer, in that the exploit:
(1) creates an object on the heap, (2) causes the object to be freed
while references to it persist elsewhere, (3) replaces the contents of
the heap memory formerly occupied by the object with arbitrary data,
and (4) causes Internet Explorer to access a stale reference to the
freed object. In a prepared proof-of-concept EIP control exploit
targeting Internet Explorer 9 (32-bit), these steps were accomplished
by: including two nested, named "div" elements in the HTML; modifying
the outer "div" element to destroy the inner "div" (while the mail
client error message is on the screen); performing a typical heap
spray to store known data at a known address; and creating a large
number of CTreePos-size heap blocks containing specially crafted data
to fill the hole left by the freed inner "div" element. The specially
crafted data includes a substitute vtable pointer which references
heap-sprayed data at a hard-coded address, another feature typical of
such exploits. The only step that this exploit cannot accomplish
entirely on its own is triggering Internet Explorer to access the
stale inner "div" element reference--this access occurs only after the
user dismisses the mail client error message.
MITIGATION
----------
Setting the "Downloads" -> "Font download" security setting to
"Disable" ("HKEY_CURRENT_USER\Software\Microsoft\CurrentVersion\Internet
Settings\Zones\<zone-identifier>" -> "1604": REG_DWORD = "3") prevents
exploitation of this vulnerability using the present technique.
Deleting, renaming, or denying read access to the
"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PROTOCOLS\Handler\mailto"
registry key (and
"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\PROTOCOLS\Handler\mailto"
as appropriate) also prevents exploitation using the present
technique; however, after implementing the workaround, confirm that
clicking a "mailto:" link in any zone does not display a message box.
CONCLUSION
----------
This document presents a long-lived vulnerability in Internet Explorer
which permits arbitrary code execution given default security
settings. Although current exploitation involves a modest amount of
user interaction and user notification in the form of a mail client
error message, the message is not security-related, and the message
box does not present the user with an option of aborting exploitation.
Further research into the vulnerability might reveal other means of
exploitation which may change the presented message or reduce or
eliminate the need for user interaction.
GREETINGS
---------
www.thetomatopizza.com
^ The best pizza anywhere near DFW; required eating for locals and remotes.