Thursday, March 9, 2017

0patching another 0-day: Internet Explorer 11 Type Confusion (CVE-2017-0037)


By Luka Treiber, 0patch Team.

[Update 3/27/2017: After Microsoft has patched this issue, security researcher Alisa Esage posted a proof of its exploitability on Twitter. It is therefore clear that it was possible to both (1) set rax to a attacker-controlled address, and (2) bypass the Control Flow Guard check.]

A week has passed since my last post so it seems about time to release another 0patch into the vacuum between regular Microsoft Update Tuesdays. It's been an interesting week because our 0patch platform (with open beta in progress) got an infusion of new users providing a lot of useful feedback.

This time I present you with a patch for IE11, providing protection for a vulnerability more severe than the previous one. One that is said to potentially allow for remote code execution. Again I based my analysis on a bug report provided by Google Project Zero, who automatically derestricted it after 90 days deadline. This time Ivan Fratric holds the credit.

The PoC (which can be extracted from the top of Ivan's report) is a short HTML file in which - upon opening in IE11- JavaScript dynamically reformats StyleSheet properties of an HTML table in a way that causes type confusion, ending in a crash. Inspecting the crash with Application Verifier enabled and WinDbg attached I got the same results as reported:

(430.1a4c): Access violation - code c0000005 (!!! second chance !!!)
MSHTML!Layout::MultiColumnBoxBuilder::HandleColumnBreakOnColumnSpanningElement+0xa4:
000007fe`ddeeba17 48833800        cmp     qword ptr [rax],0 ds:00000078`00000070=????????????????


I executed !heap -p -a @rbp to acquire the call-stack of corrupt object's creation. It showed that the illegal rax address originated in 

Array<int>::Create

There was no indication of a typical memory corruption such as a buffer overflow or a use-after-free directly related to the crash which could be analyzed and patched in an almost standard way (see our previous blog posts). I therefore concluded that a less deterministic and more tedious analysis was necessary to crack this bug. What was needed was a set of probes derived from the PoC that separate a correct execution flow from an illegal one. Those probes could then be traced in WinDbg and trace-dumps compared. What I found was that
  • the boom()call causes a crash only if triggered by an event separate from page load, e.g., a click or a timer event,
  • instead of "aaaaaaaaaaaaaaa", mediaText can be set to a legitimate value such as print, handheld, projection, etc. and the browser will still crash and
  • statically defined media (inside a css definition) does not produce a crash.
Attaching to the probes I traced the life-cycle of the said Array<int> down to the crash as well as the differences between various situations where mediaText and th1.align are set. In my limited time I could compare several combinations of execution flow traces of said probes, but ended up with no solid understanding of where the illegal parsing behavior kicks in. Time was not on my side so I chose to resort to an easier solution: functionality amputation. If your fingernail causes you to stumble, cut it off ...

Based on my findings above this means disablement of mediaText setter. But first let's see what mediaText is about. According to W3C it is responsible for getting and setting a collection of media queries. By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself. So basically we're about to interfere with web page layout. If you look at the examples given by W3C, all of them use static media definitions which the patch I'm about to propose does not affect because it will disable only functions exposed to JavaScript that the published PoC relies on. Whether it is worth protecting against a potential remote execution threat in exchange for possible page styling errors is for you to choose (0patch Agent allows disabling of the patch if you cannot live with it). Now let's see how the patch works.

Below is the content of my 0patch source file.  It defines two patchlets for module mshtml.dll enclosed between patchlet_start - patchlet_end directives. Patchlet locations were obtained by tracking every possible setter on a CSSMediaList object accessible from JavaScript. I found two such locations:
  • media.mediaText setter that maps to CFastDOM::CMediaList::Trampoline_Set_mediaText 
  • media.appendMedium method that maps to CFastDOM::CMediaList::Trampoline_appendMedium
I patched both setters so that their function bodies are skipped entirely (using the JUMPOVERBYTES directive) and their result is set to SUCCESS via xor rax,rax.

;target OS: Windows 7 64bit
;

RUN_CMD C:\Program Files\Internet Explorer\iexplore.exe C:\0patch\Patches\CVE-2017-0037\poc.html
MODULE_PATH "C:\Windows\System32\mshtml.dll"
PATCH_ID 265
PATCH_FORMAT_VER 2
VULN_ID 2140
PLATFORM win64


patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2

 PATCHLET_OFFSET 0x00f79cc0
 JUMPOVERBYTES 211;
 
 code_start
   xor rax,rax
; return success
 code_end
patchlet_end

patchlet_start
 PATCHLET_ID 2
 PATCHLET_TYPE 2

 PATCHLET_OFFSET 0x00fa3f80
 JUMPOVERBYTES 197
 
 code_start
   xor rax,rax ; return success
 code_end
patchlet_end

After compiling this .0pp file with 0patch Builder, the patch gets applied and IE11 browser survives the PoC without a crash.

If you have 0patch Agent installed, patches ZP-265 through ZP-268 should already be present on your machine. If not, you can download a free copy of 0patch Agent to protect yourself from exploits against the presented issue while waiting for Microsoft's official fix. Note that when Microsoft’s update fixes this issue, it will replace the vulnerable mshtml.dll and our patch will automatically stop getting applied as it is strictly tied to the vulnerable version of the DLL. We have deployed this patch for the following platforms: Windows 10 64bit, Windows 8.1 64bit, Windows 7 64bit and Windows 7 32bit.

Patching this 0day was a good opportunity to demonstrate how patching process in our 0patch Team works. We rarely release patches that would replace official vendor fixes. In general we aim to bridge the gap between a release of vendor update and the time this update gets installed on vulnerable machines. Note that in case of the presented patch we're not talking only about 5 days until the next Patch Tuesday -  for many companies the gap is caused by weeks or months of testing before official update batch can be applied to their networks.

So we rather release a simple temporary patch that blocks an attacker than try to create a perfect patch. A much thorougher and better analysis of this bug can and will be done by Microsoft. Browsers are certainly among the most complex applications so with my black box analysis tools and a limited time-frame I don't fool myself that I could get to the bottom of all the weird things an HTML apparatus does. On the other hand Microsoft developers have the source code, the right tools and knowledge to properly fix this bug and probably wont even blink while getting it done.

Feel free to use 0patch Agent with this patch to protect yourself from attacks against CVE-2017-0037 until Microsoft provides an official fix (which we absolutely recommend you apply). Just remember that we're still in beta ;-)

1 comment: