Pwning the Facebook Portal
Overview
Back in November, 2021, my friend and I were trying to make an attempt to participate Pwn2Own. Unfortunately, due to some rules of exploitation. Our submission was not accepted. Today, as the vulnerability has now been fixed by the vendor, we decide to publish this blog post regarding a vulnerability that was found on Facebook Portal.
Vulnerability Summary
The attack was conducted relying on the usage of vulnerable browser version (Chrome/92.0.4515.131). This Chromium-based webview is related to the Out-of-bounds write in V8 (CVE-2021-30632
) leading a Remote Code Execution on Facebook Portal @ latest version @1.29.1
Generally, whenever a device try to connect to a Wireless router that has Captive Portal Auth Mechanism, the wireless router, as part of Auth Mechanism, will send the request to a login form. Users would have to have a valid set of credential to be granted access to the Internet. This HTML login form is parsed and run by an obsolete chromium-based webview (Chrome/92.0.4515.131).
By exploiting this behavior via the above attack surface, we leveraged a 1-Day exploitation on Out-of-bounds in V8 (CVE-2021-30632) to get code execution on sandboxed webview process.
Vulnerability Detail
Optimized code that stores global properties does not get de-optimized when the property map gets changed, leading to type confusion vulnerability. Prior to the patch, when Turbofan compiles code for storing global properties that has the kConstantType
attribute (i.e. the storage type has not changed), it inserts DependOnGlobalProperty
(1. below) and CheckMaps
(2. below) to ensure that the property store does not change the map of the property cell:
However, when the map of the global property (property_cell_value_map
) is changed in place after the code is compiled, the optimized code generated by the above only de-optimizes when property_cell_value_map
is stable. So for example, if a function store is optimized when the map of the global property x
is unstable:
Then an in-place change to the map of x will not de-optimize the compiled store
:
This causes the map for x
in the optimized store
function to be inaccurate. Another function load
can now be compiled to access newProp
from x
:
The optimized load
will assume x
to have a new map with newProp
as a property. If the optimized store
is now used to store an object with the old map back to x
, the next time load
is called, a type confusion will occur because load still assumes x
has the new map.
Vulnerability Exploitation
Using this bug, we can create a type confusion
between 2 kinds of Javascript array. Because Javascript arrays have differently sized backing stores for different element kinds, a confusion between an SMI
array (element size 4
) and a double
array (element size 8
) will lead to out-of-bounds read and write in a Javascript array.
Below is the Proof of Concept (PoC) that triggers OOB read and write:
When oobRead
and oobWrite
are optimized, x
now has MapB
, which is a stable map with HOLEY_DOUBLE_ELEMENTS
. This means that, for example, when writing to the 24th element (x[24]
) in oobWrite
, the offset used by the optimized code to access elements will be calculated with double element width, which is 8, so an offset of 8 * 24
is used. However, when foo(arr)
is used to set x
back to arr
, the element store for arr is of type HOLEY_SMI_ELEMENTS
, which has a width of 4, meaning that the backing store is only 4 * 30
bytes long, which is way smaller than 8 * 24
. A write to the offset 8 * 24
thus causes an out-of-bounds write in the backing store.
Using this OOB
read/write on JS array, we can get an arbitrary read/write primitive. The final step in obtaining code execution is to make use of the fact that wasm
(WebAssembly) stores its compiled code in an RWX region and the address of the compiled code is stored as a compressed pointer in the WebAssembly.Instance
object. Then, by using the arbitrary absolute address write primitive, we were able write shell code to this region and have it executed when we kicked off the compiled wasm
code.
Timeline
10/29/2021: Exploit submitted to Pwn2Own Competition
11/01/2021: Submission got rejected due to the usage of n-day