CVE-2019-1367: Internet Explorer JScript use-after-free
Maddie Stone & Ivan Fratric, Project Zero & Clément Lecigne, Google's Threat Analysis Group (Originally posted on Project Zero blog 2020-07-27)
The Basics
Disclosure or Patch Date: 23 September 2019
Product: Microsoft Internet Explorer
Advisory: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1367
Affected Versions: For Windows 10 1903, KB4515384 and previous
First Patched Version: For Windows 10 1903, KB4524147
Issue/Bug Report: N/A
Patch CL: N/A
Bug-Introducing CL: N/A
Reporter(s): Clément Lecigne of Google’s Threat Analysis Group (TAG)
The Code
Proof-of-concept:
<!-- saved from url=(0014)about:internet -->
<meta http-equiv="X-UA-Compatible" content="IE=8"></meta>
<script language="Jscript.Encode">
var spray = new Array();
function F() {
// 2. Create a bunch of objects
for (var i = 0; i < 20000; i++) spray[i] = new Object();
// 3. Store a reference to one of them in the arguments array
// The arguments array isn't tracked by garbage collector
arguments[0] = spray[5000];
// 4. Delete the objects and call the garbage collector
// All JSCript variables get reclaimed...
for (var i = 0; i < 20000; i++) spray[i] = 1;
CollectGarbage();
// 5. But we still have reference to one of them in the
// arguments array
alert(arguments[0]);
}
// 1. Call sort with a custom callback
[1,2].sort(F);
</script>
Exploit sample: be8fdfce55ea701e19ab5dd90ce4104ff11ee3b4890b292c46567d9670b63b82
Did you have access to the exploit sample when doing the analysis? Yes
The Vulnerability
Bug class: JScript VAR object not tracked by garbage collector, use-after-free
Vulnerability details:
The vulnerability is a member of the use-after-free bug class in JScript where variables (represented by the VAR structure) aren’t properly tracked by the garbage collector. In this case, the arguments object is not tracked by the garbage collector during the Array.sort
callback. Thus, during the Array.sort
callback, it is possible to assign a variable to the arguments object, have it garbage-collected (as long as it is not referenced anywhere else) and still access it later, causing the use-after-free.
Patch analysis: N/A
Thoughts on how this vuln might have been found (fuzzing, code auditing, variant analysis, etc.): Variant analysis
Based on the blogpost from Google TAG, this bug was exploited by the same actor who exploited CVE-2018-8653. CVE-2018-8653 is a use-after-free in isPrototypeOf
callback when the this
variable is not tracked by the garbage collector. Therefore it’s likely that the actor found this bug by performing variant analysis on CVE-2018-8653, looking for vulnerabilities in the same bug class.
(Historical/present/future) context of bug:
- Jan 2018 - P0 researcher identifies bug class: JScript variables (in VAR structure) not tracked by garbage collector. Finds numerous bugs (P0 1504, P0 1505, P0 1506, P0 1587) through fuzzer, which is open-sourced.
- Dec 2018 - First use of an exploit exploiting this bug class is found by Google’s Threat Analysis Group (TAG): CVE-2018-8653. Bug couldn’t be found by the open-sourced fuzzer because the vulnerability uses features not supported by fuzzer at the time.
- Sept 2019 - CVE-2019-1367 (this bug) is discovered by Google TAG.
- Oct 2019 - Google TAG discovers fix for CVE-2019-1367 is incomplete. Project Zero discovers trivial variant.
- Nov 2019 - The incomplete patch and the variant are patched as CVE-2020-1429.
- Jan 2020 - TAG discovers another in-the-wild exploit sample (CVE-2020-0674) using a trivial variant of CVE-2019-1367/CVE-2019-1429. Microsoft issues advisory. It is used as the sandbox escape with CVE-2019-17026 on Firefox.
- Feb 2020 - Microsoft patches the exploited 0-day as CVE-2020-0674.
CVE-2018-8653, CVE-2019-1367, CVE-2019-1429, and CVE-2020-0674 all used the sample exploitation method.
The Exploit
Is the exploit method known? Yes
Exploit method:
Given the UAF bug described above, the exploit frees the VAR structures (always allocated as a block of 100 VARs) and replaces the freed memory with a controllable object property name, which is a technique first demonstrated in P0 1587 and also used in CVE-2018-8653. This gives an attacker a powerful primitive: the ability to fake JScript variables.
From there, the exploit constructs a fake RegExp object, which is used to achieve arbitrary memory read-write. The exploit directly replaces regexp.code with their custom compiled RegExp bytecode giving them a write-what-where primitive. The exploit uses regexp.source (unused bSTR) for the read primitive.
The same exploit is used twice: Once to achieve code execution inside the browser, and the second time to escape the browser sandbox using the WPAD service (which runs as a privileged process). This is also a publicly known exploitation technique described here.
The Next Steps
Variant analysis
Areas/approach for variant analysis (and why):
We took two approaches to this variant analysis: manual analysis and a fuzzer. In the manual analysis approach, we manually attempted to free function arguments in every JScript callback that we knew. In the fuzzer approach, we ran another fuzzing sessions with a modified JScript.dll to more easily check this bug class. The modifications included:
- Freed VARs are modified so that accessing them would cause an immediate crash, and
- Freed VARs are never allocated again
Found variants:
- P0 1947 (CVE-2019-1429): Use-after-free where members of the arguments object aren’t tracked by the garbage collector during the toJSON callback.
Structural improvements
- Bug classes should be fixed comprehensively, not just fixing each vulnerability individually. For this bug classes, that likely would include re-writing the garbage collector.
- Quality and complete patches need to be prioritized. CVE-2019-1367 was not fixed the first time and the trivial variant also wasn’t patched. This gave the attackers another opportunity to exploit the bug against the users, which they did. Sharing proposed patches with the reporter could help identify these issues earlier.
- JScript and Internet Explorer are now considered “legacy” software. Remove them from being accessible by default in the Windows operating system to reduce the attack surface.
0-day detection methods
- Look for any scripts that want to use JScript as their JS engine outside of a local intranet.
- Look for scripts that use the Enumerator object due to that being Microsoft specific and one of the known methods for exploiting the UAF to get remote code execution.
- Look for scripts that attempt to trigger CollectGarbage.
Other References
- Jan 2019: “IE Scripting Flaw Still a Threat to Unpatched Systems: Analyzing CVE-2018-8653” by McAfee
- Jan 2020: This vulnerability is included as a case-study in “Where’s Waldo…’s Brothers and Sisters?: Variant Analysis on Recent 0-days” presented at Bluehat IL 2020. [slides, video]
- Mar 2020: “Identifying vulnerabilities and protecting you from phishing” by Google Threat Analysis Group states that TAG found CVE-2018-8653, CVE-2019-1367, and CVE-2019-1429 all in use by the same actor.
- May 2020: “Internet Exploiter: Understanding vulnerabilities in Internet Explorer” by F-Secure Labs
- July 2020: Multi-part blog series analyzing CVE-2019-1367 vulnerability & exploit by Taha Karim