Since November I have been releasing details on all vulnerabilities I
found in web-browsers that I had not released before. I will try to
continue to publish all my old vulnerabilities, including those not in
web-browser, as long as I can find some time to do so. If you find this
information useful, you can help me make some time available by donating
bitcoin to 183yyxa9s1s1f7JBpAPHPmzAQ346y91Rx5DX.
This is the twenty-fifth entry in the series. This information is
available in more detail on my blog at
http://blog.skylined.nl/20161205001.html. There you can find repros
that triggered this issue in addition to the information below.
Today's release is interesting, as I accidentally published a repro for
this as part of #DailyBug on twitter in May of this year, believing at
the time that it was a simple NULL pointer:
https://twitter.com/berendjanwever/status/729957166447218688
I found out not to long after that, that it was actually a security
vulnerability. Details on how this happened are below.
Follow me on http://twitter.com/berendjanwever for daily browser bugs.
MS Edge CBaseScriptable::PrivateQueryInterface memory corruption
================================================================
(MS16-068, CVE-2016-3222)
Synopsis
--------
A specially crafted web-page can trigger a memory corruption
vulnerability in Microsoft Edge. I did not investigate this
vulnerability thoroughly, so I cannot speculate on the potential impact
or exploitability.
Known affected software and attack vectors
------------------------------------------
* Microsoft Edge
An attacker would need to get a target user to open a specially
crafted web-page. Disabling JavaScript does not prevent an attacker
from triggering the vulnerable code path.
Discovery
---------
This issue was found through fuzzing in the 64-bit version of Microsoft
Edge, in which the original repro triggered what appeared to be a NULL
pointer dereference in `CBaseScriptable::PrivateQueryInterface`. So,
after a very brief look at the repro, I filed a bug in the public Edge
bug tracker and published it on twitter as part of #DailyBug.
Soon after, I found another repro that trigger a slightly different NULL
pointer dereference in `CBaseScriptable::PrivateQueryInterface` in a
64-bit version of Edge.
I never tested the these two repros in a 32-bit version of Edge before
publishing them, which I immediately regretted after finding that the
second repro triggered an access violation using the obviously non-NULL
address 0x1BF37D8 in a 32-bit version of Edge!
Around this time, I started finding many variations of this bug: getting
the type of various properties or objects associated with another window
was triggering all kinds of access violations. Many of these were not
using NULL pointers on 32-bit Edge.
I looked again at the original `crypto` repro and noticed that although
it triggered an access violation using a NULL pointer on both 32-bit and
64-bit versions of Edge, the two addresses (3 and 8 respectively) had
different alignment. This is rather odd: true NULL pointer dereferences
can cause an access violation at a different offset from NULL on these
two architectures because property values and pointers stored before the
one being read/written can have different sizes on 32-bit and 64-bit
systems, but one usually expects them to have similar alignment: the
last two bits of the address should be the same.
Report
------
If only I had tested the original repro in a 32-bit version of Edge when
I first analyzed the issue, I might have realized it was more than a
simple NULL pointer and not published it before doing additional research.
I contacted ZDI and asked if they would be interested in buying the
vulnerability at this point, given that I publicly released the repro
that triggered a NULL pointer and filed it with Microsoft. I was hoping
they would decide that this did not disclose the underlying
vulnerability and that it as such would still be a 0-day. Unfortunately
for me, they were not interested in acquiring details in this situation.
At that point I decided to contact the Microsoft Security Response
Center and report the additional information I had found. I also
contacted a few people working on the Edge team at Microsoft directly to
let them know they might want to escalate this bug from a simple NULL
pointer to a security vulnerability. Unfortunately, this let them to
decided to mark the bug I had filed in the Edge bug tracker as hidden. I
warned them that this did little good, as the details were still public
in my twitter and even if I deleted that, in general
what goes on the internet stays on the internet.
Analysis
--------
Since I had publicly released the repro, I was not going to be seeing
any kind of reward for this bug, so analyzing the issue was not a
priority for me. Unfortunately that meant I did not analyze it at all,
other than to speculate that this bug was likely to have been a
type-confusion or bad cast, where assembled code was used as data,
leading to most of these repros triggering an access violation at a
static address that depended on the code they were using as data. It may
therefore be possible to find a variation that uses code that represents
an address in the address space of Edge where an attacker might store
data under his/her control. This is especially true for 32-bit Edge, as
the address space is a lot smaller. Depending on what the code does with
the address, it might be possible to execute arbitrary code under
perfect circumstances.
On Hiding bugs in public bug trackers
-------------------------------------
Hiding a publicly reported bug after the fact is a very bad idea IMHO,
as it paints an easy to detect target on the bug. Every smart attacker
should have a system that makes regular copies of all publicly reported
bugs in target applications and reports to their owner all bugs that
become hidden, with a copy of all the information it scraped from the
bug before it was hidden. Since hiding a public bug only ever happens
for one of two reasons: the bug was found to be a security issue, or the
report accidentally contains personal information that the owner wants
hidden. It should be quite easy to distinguish between the two to filter
out the vulnerabilities, giving an attacker a nearly free stream of
nearly 0-day bugs. If you work on a team that has a public bug-tracker,
you may want to discuss this with your team and decided how to handle
such situations.
Conclusion
----------
As useful as BugId is in automating a lot of the analysis I do on every
bug I find, and in helping me prioritize the issues that are most
likely to be vulnerabilities, it is not perfect and cannot always detect
a vulnerability for what it is. BugId is not a perfect replacement for
full manual analysis of bugs.
In this case I relied to heavily on its ability to distinguish
vulnerabilities from other bugs. Because of the nature of this issue,
the repros caused access violations at static addresses, many of which
near enough to NULL to be interpreted as NULL pointer dereferences,
especially for the first repro I found. BugId can not actually determine
the root cause of a crash, but attempts to deduce the root cause based
on the details of the crash it causes. In this case, the crash looked
too similar to a regular NULL pointer dereference for BugId to detect it
as anything else.
However, in my current situation, where I am finding *way* more bugs
than I can analyze manually, BugId does a very good job at helping me
prioritize and analyze issues. I have used BugId on hundreds of bugs
and, as far as I know, this is the first time I mistook a security
vulnerability for a regular bug based on the BugId report. As such, the
false-negative rate I have experienced is a fraction of a percent, which
IMHO is remarkably low and entirely acceptable. At the same time, the
false-positive rate I have seen so far is exactly zero.
In order to prevent this from happening in the future, I now test each
repro in both the 32-bit and 64-bit version of Edge, do more manual
analysis on bugs that get reported as a NULL pointer with a
non-DWORD-aligned address (e.g. 3 in this case), and wait slightly
longer for my fuzzers to find variations of a bug before I start my
analysis and report the issue as a non-security bug.
Time-line
---------
* 29 April 2016: This vulnerability was first found through fuzzing.
* 10 May 2016: This issue was published on Twitter and reported to
Microsoft through the Edge bug tracker.
* 13 May 2016: This vulnerability was submitted to ZDI.
* 18 May 2016: This vulnerability was declined by ZDI.
* 18 May 2016: This vulnerability was reported to MSRC and I informed
Edge developers directly on the seriousness of the bug.
* 18 May 2016: The issue was hidden in public bug tracker.
* 14 June 2016: Microsoft addresses this vulnerability in MS16-068.
* December 2016: Details of this vulnerability are released.
Cheers,
SkyLined