The Story of Two Winning Pwn2Own JIT Vulnerabilities in Mozilla Firefox
April 18, 2019 | Hossein LotfiEvery year some of the greatest security researchers around the globe gather together for the Pwn2Own event to demonstrate their skills by compromising widely used applications. This year’s event recently completed and did not disappoint. On the second day of the competition, the Fluoroacetate team and Niklas Baumstark successfully demonstrated attacks against Mozilla Firefox, earning themselves $50,000 USD and $40,000 USD respectively. Now that Mozilla has patched the underlying bugs, I will provide you with details of the two vulnerabilities used by these two teams to compromise the renderer process of Mozilla Firefox.
CVE-2019-9810/ZDI-19-364: IonMonkey MArraySlice incorrect alias information:
The Fluoroacetate team of Richard Zhu and Amat Cama used this vulnerability to compromise Mozilla Firefox renderer process.
Here is the JIT implementation of Array.slice
within js/src/jit/MIR.h
:
The override of getAliasSet
makes a claim that Array.slice
can have only limited side effects. In reality, arbitrary side effects can be triggered via Symbol.species
. The contestants were able to demonstrate this via the following proof of concept:
Running it against an affected version of Mozilla Firefox will give you following alert on success:
After clicking OK following crash is triggered:
As you can see, several registers have controlled values. Thus, it is a very good crash that can give an attacker arbitrary read/write primitives. From here it is not that hard to perform a ROP exploit and execute shellcode. The demonstration used during the competition included a further sandbox escape, enabling the attacker to take over an affected system.
CVE-2019-9813/ZDI-19-365: A Type Confusion Vulnerability in Mozilla Firefox
This is the vulnerability used by Niklas Baumstark to compromise the Mozilla Firefox renderer process.
The attack chain starts with a type confusion vulnerability in the IonMonkey optimizer. The vulnerability was introduced via commit 1c43dd975e76c0aa7e5a84af36844d247baf671a in 2017, which disabled copy of the unknown-properties flag in the js::AddPropertyTypesAfterProtoChange()
function. This causes a lack of the shape/group check on an object, which can then be exploited to produce a compiled JS function that treats an object as if it had a different type and possibly resulting in a type confusion. This condition can be triggered using the following proof of concept:
Running the PoC file against an affected version of Mozilla Firefox will result in a very promising (write-what-where) crash:
This is a very strong primitive to start an attack with. The exploit triggers the vulnerability twice. The first time it is triggered, it is used as a pointer-to-double type confusion, leaking an object address. The second time it is triggered in the reverse fashion, as a double-to-pointer type confusion, yielding an arbitrary read/write primitive. This is followed by mapping of a RWX region to execute shellcode. With the ability to execute arbitrary code, the attacker moves to a second stage to bypass the sandbox. We will cover the sandbox escape in a separate blog post.
Conclusion
There have been many efforts by vendors to introduce mitigations and harden applications against crafted attacks in the past few years. However, Pwn2Own results prove it is still possible to develop functional exploits with enough time and skill. It also shows JIT bugs can provide strong enough primitives for an attacker to successfully compromise a vulnerable target, and thus it appears we will continue to see these types of vulnerabilities in the future.
You can find me on Twitter at @hosselot and follow the team for the latest in exploit techniques and security patches.