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.
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.
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::
. So, after a very brief
look at the repro, I filed a bug in the public bug tracker
and published it on twitter.
The original repro was:
<body onload=typeof(open().crypto)>
Soon after, I found another repro that trigger a slightly different NULL
pointer dereference in CBaseScriptable::
in a 64-bit
version of Edge. The second repro was:
<body onload=typeof(open().msCredentials)>
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 collected all the variations my fuzzers had found and come up with these additional repros:
<body onload=typeof(open().document. createElement("canvas").getContext("2d"))>
This triggered an access violation in edgehtml.
while attempting to read from address 0x4C261 in the 32-bit version of Edge.
<body onload=typeof(open().navigator. mediaDevices)>
This triggered an access violation in charkra.
while attempting to read from address 0xFF80A90F in the 32-bit version of Edge.
<body onload=typeof(open().toString)>
This triggered an assertion failure because it was calling a deprecated API in the 32-bit version of 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.
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.
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.
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.
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.
Id: | AVR:Unallocated e2d. |
Description: | Access violation while reading unallocated memory at 0x4C261 |
Location: | microsoftedgecp. |
Security impact: | Potentially exploitable security issue |
Id: | AVR:Unallocated 02f. |
Description: | Access violation while reading unallocated memory at 0xFF80A90F |
Location: | microsoftedgecp. |
Security impact: | Potentially exploitable security issue |
Id: | AVR:Unallocated 02f. |
Description: | Access violation while reading unallocated memory at 0xFF80A90F |
Location: | microsoftedgecp. |
Security impact: | Potentially exploitable security issue |
Id: | AVR:NULL+N e2d. |
Description: | Access violation while reading memory at 0x3 using a NULL ptr |
Location: | microsoftedgecp. |
Security impact: | Denial of Service |
Id: | AVR:NULL+4*N e2d. |
Description: | Access violation while reading memory at 0x8 using a NULL ptr |
Location: | microsoftedgecp. |
Security impact: | Denial of Service |
Id: | AVR:Reserved e2d. |
Description: | Access violation while reading reversed but unallocated memory at 0x1BF37D8 |
Location: | microsoftedgecp. |
Security impact: | Denial of Service |
Id: | Assert 368. |
Description: | A breakpoint was triggered because an assertion failed |
Location: | microsoftedgecp. |
Security impact: | Denial of Service |