Kuboid
Open Luck·Kuboid.in
Black Hat2023
Open in YouTube ↗

The Hat Trick: Exploit Chrome Twice from Runtime to JIT

Black Hat1,743 views35:21over 2 years ago

This talk demonstrates two distinct remote code execution (RCE) vulnerabilities in the Google Chrome V8 JavaScript engine, specifically targeting the Promise.any implementation and the Maglev compiler. The researchers detail how a 'TheHole' value leakage in Promise.any can be exploited to achieve arbitrary memory read/write, and how a missing write barrier in the Maglev compiler leads to a use-after-free condition. These techniques are combined with heap spraying and JIT spraying to bypass V8 sandbox protections and achieve full code execution. The presentation provides a deep dive into V8 internals, including garbage collection, object layout, and JIT compilation.

Exploiting V8: From Promise.any Leaks to Maglev Use-After-Free

TLDR: This research details two critical RCE vulnerabilities in the V8 JavaScript engine that allow attackers to bypass sandbox protections. By exploiting a value leakage in Promise.any and a missing write barrier in the new Maglev compiler, researchers achieved arbitrary memory read/write primitives. These findings highlight the ongoing security challenges posed by rapid feature implementation in modern browser engines.

Modern browser security relies heavily on the isolation provided by the V8 sandbox, but as engine complexity grows, the attack surface expands in ways that often bypass traditional mitigations. The recent research presented at Black Hat 2023 on V8 internals proves that even well-understood components like Promise.any and newer JIT compilers like Maglev harbor subtle, high-impact flaws. For researchers and bug bounty hunters, these vulnerabilities represent the current frontier of browser exploitation, where the focus has shifted from simple memory corruption to sophisticated logic bugs that manipulate engine state.

The Promise.any Value Leakage

The first vulnerability centers on the implementation of Promise.any in V8. At its core, Promise.any acts as an OR gate for promises, resolving as soon as any input promise fulfills. The researchers identified that the internal state management of this function could be manipulated to leak the "TheHole" value, an internal sentinel used by V8 to represent the absence of a value.

When Promise.any iterates through input promises, it uses an internal array to track results. If an attacker can trigger a state change—specifically by forcing a promise to reject during the iteration process—they can cause the engine to store an uninitialized or incorrect value in the results array. Because V8 does not use undefined as a placeholder during this process, it inadvertently exposes the internal sentinel. By leaking this value, an attacker gains a powerful primitive: the ability to distinguish between different object types and memory states, which is a prerequisite for building a reliable exploit chain.

This technique is particularly dangerous because it does not rely on a traditional buffer overflow. Instead, it exploits the gap between the ECMAScript specification and the engine's internal representation of promise states. Once the sentinel is leaked, the attacker can use it to construct a fake JSArray object, effectively tricking the engine into treating arbitrary memory as a structured array. This leads directly to out-of-bounds read and write capabilities.

Maglev and the Missing Write Barrier

The second vulnerability targets the Maglev compiler, a mid-tier JIT compiler introduced to bridge the performance gap between the baseline Sparkplug compiler and the highly optimized TurboFan. Maglev is designed for speed, but its implementation of garbage collection (GC) write barriers proved to be its Achilles' heel.

Write barriers are essential in generational garbage collection. They ensure that the GC can track references from the old generation to the young generation. If a write barrier is omitted, the GC might incorrectly assume an object is unreachable and free it, leading to a classic use-after-free (UAF) condition. The researchers found that Maglev failed to emit the necessary write barrier when storing specific object types into a variable property.

The exploit flow here is elegant in its simplicity. By creating a Float64Array object and manipulating it without the protection of a write barrier, an attacker can force the GC to reclaim the underlying memory while the JavaScript code still holds a reference to it. This creates a dangling pointer. By then performing a heap spray to fill the reclaimed memory with controlled data, the attacker can overwrite the object's internal structure. In the demo, this was used to modify the entry_point of a function object, redirecting execution flow to attacker-controlled shellcode or JIT-compiled gadgets.

Real-World Impact and Testing

For a pentester, these vulnerabilities are rarely found in isolation. They are the building blocks of a full sandbox escape. In a typical engagement, you would first need to achieve code execution within the renderer process—perhaps through a separate memory corruption bug—and then use these V8-specific techniques to escalate privileges and break out of the sandbox.

The impact of such an exploit is total system compromise within the context of the browser. Once the sandbox is bypassed, the attacker can interact directly with the operating system, potentially leading to full machine takeover. If you are hunting for these bugs, focus your efforts on the newer, less-tested components of the engine. The introduction of new ECMAScript features, such as those tracked by TC39, often forces engine developers to write complex, high-performance code that is prone to these exact types of logic errors.

Defensive Considerations

Defending against these exploits is difficult because they target the fundamental logic of the engine rather than simple coding mistakes. However, the most effective defense remains the hardening of the V8 sandbox. Projects like V8 Sandbox aim to make it impossible for an attacker to gain arbitrary read/write access even if they find a memory corruption bug. Organizations should ensure they are running the latest versions of Chromium-based browsers, as these updates frequently include patches for the specific compiler and promise-handling bugs discussed here.

As we look ahead, the complexity of JIT compilers will only increase. The shift toward more aggressive optimizations means that the window for finding these bugs is wide open. Researchers should continue to audit the interaction between the GC and the JIT-generated code, as this remains the most fertile ground for finding high-severity vulnerabilities. Keep your focus on the edge cases where the engine's performance optimizations conflict with its memory safety guarantees.

Talk Type
research presentation
Difficulty
expert
Category
exploit dev
Has Demo Has Code Tool Released


Black Hat USA 2023

118 talks · 2023
Browse conference →
Premium Security Audit

We break your app before they do.

Professional penetration testing and vulnerability assessments by the Kuboid Secure Layer team. Securing your infrastructure at every layer.

Get in Touch
Official Security Partner
kuboid.in