0xsha/CVE-2026-6307
GitHub: 0xsha/CVE-2026-6307
针对 Chrome V8 JS-to-Wasm 类型混淆漏洞(CVE-2026-6307)的本地复现与武器化 PoC,提供无需 flag 即可触发的 addrof/fakeobj 原语及关闭 ASLR 环境下的渲染器 RCE 验证。
Stars: 48 | Forks: 13
# CVE-2026-6307:V8 JS-to-Wasm 类型混淆 → Chrome 146 RCE
对 [Nebula](https://nebusec.ai/research/v8-cve-2026-6307-writeup) 描述的 V8 JS-to-Wasm 去优化类型混淆的本地复现与武器化,最终在 Chrome for Testing `146.0.7680.165` 的渲染器中成功弹出了一个 **`xcalc`**
(该漏洞已在 `147.0.7727.101` 中修复)。
所有 payload 都是无害的(计算器 / `exit(0x42)` / `jmp $`)。
一切操作均在本地实验室中针对故意过时的浏览器运行
请勿将其用于针对任何其他目标。
## 演示
https://github.com/user-attachments/assets/d450f064-ba52-4f39-a88b-367f31217143
## 漏洞原理
`JSToWasmFrameStateFunctionInfo` 的相等运算符忽略了 Wasm 签名
比较,因此 CSE/GVN 会合并仅在签名上有差异的 frame state。随后的
延迟去优化(lazy deopt)会将 Wasm `i64` 物化为 tagged `externref`(反之亦然),
从而提供完整的 64 位 `addrof`/`fakeobj`,且其指针*未经过* cage 压缩
(Wasm 引用使用 tagged 寄存器表示,通过 `kReturnRegister0` 返回)。
以下所有内容均已在 `146.0.7680.165` 上**实地验证**。每次加载的命中率是
在重复运行中测得的(该混淆对 GC 敏感;每次页面刷新都会在脏构建上重新启动)。从未有过误报(false positive)。
## 无需 flag 的原语 — 不使用 `--allow-natives-syntax`
大多数 V8 漏洞 PoC 会使用 `%OptimizeFunctionOnNextCall` 强制优化,这是一个仅用于测试的内部函数,由 `--allow-natives-syntax` 控制,而真实的受害者不会启用它。本项目的 payload **完全不需要任何 flag** 即可触发该漏洞,通过调整预热反馈(warmup feedback),使去优化混淆自然发生。每个地址都是在运行时泄露的 —— 没有任何硬编码。
在无 flag 的 headless 模式下运行它们。
| 文件 | 验证内容 | 验证情况 |
|------|--------|----------|
| [`flag-free/00-reachability-flagfree.html`](flag-free/00-reachability-flagfree.html) | 触发混淆状态;在存在漏洞的 146 版本上触发,但在已修复的 147 上**不触发** | 每次加载 6/15 |
| [`flag-free/01-primitives-flagfree.html`](flag-free/01-primitives-flagfree.html) | `addrof` / `fakeobj` (`fakeobj(addrof(o))===o`) | 8/12 |
| [`flag-free/02-store-flagfree.html`](flag-free/02-store-flagfree.html) | cage 外写入将选定值存入选定对象中 | 12/12 |
| [`flag-free/03-arw-flagfree.html`](flag-free/03-arw-flagfree.html) | cage 内 `read64` / `write64`(伪造的 `PACKED_DOUBLE` 数组) | 2/12(不稳定,需重试) |
## 可见 RCE — 关闭 ASLR 的实验构建
`rce-no-aslr/` 将其提升至代码执行:一个经过优化的 JS 函数 `g` 将
`execve` shellcode 暂存为 JIT 双精度字面量(`movabs` 常量,每个都以
`eb rel8` 结尾以进行链接),混淆后的写入操作将 `nop; jmp` 打补丁进 `g` 的代码中,
随后调用 `g()` 即可使 RIP 滑入 shellcode。
| 文件 | 验证内容 | 验证情况 |
|------|--------|----------|
| [`rce-no-aslr/exploit-calc.html`](rce-no-aslr/exploit-calc.html) | 通过渲染器中的 `execve` 弹出一个真实的 `xcalc` 窗口 | 在纯净状态下约 1 秒内弹出 |
| [`rce-no-aslr/exploit-exit.html`](rce-no-aslr/exploit-exit.html) | 渲染器运行注入的 shellcode 执行 `exit(66)`;`#jmp` 使 RIP 在其内部旋转 | **exit(66) 8/8** (strace) |
此构建使用了 `--allow-natives-syntax`(`%Optimize` 固定 `g` 的 JIT payload,以防
被去优化 GC 冲刷掉)和 `--no-memory-protection-keys`(以便混淆后的写入操作可以
修改 JIT 页面 —— 否则 V8 的 PKU 会将其标记为只读)。ASLR 已关闭
(`randomize_va_space=0`),因此地址是确定性的
(`A_MAP = 0x5555bbc0128a`)。渲染器还需要 `--disable-seccomp-filter-sandbox
--no-zygote`,因为否则 seccomp 会阻止 shellcode 的 `execve`。
## 运行说明
原生 x86_64 Linux,**关闭 ASLR**,PATH 中存在 Chrome 146,并在 `:0` 上有 X display(Xvfb
或真实 X)。`rce-no-aslr/run.sh` 会设置所有 flag 并通过 http 提供服务。
```
cd rce-no-aslr
./run.sh calc # pop a real xcalc over http://127.0.0.1:8080, on :0
./run.sh exit # strace-confirms the renderer's exit(66)
./run.sh jmp # gdb-confirms RIP inside the injected shellcode
./demo.sh calc # clean-slate + auto-retry, full-size headful browser (for recording)
./demo.sh msgbox # same, but the pop is a branded "0xSha :: pwned" box
```
`pocmode.sh calc|msgbox` 可切换 RCE 的 `execve("/usr/bin/xcalc")` 启动的程序(真实的计算器或定制弹窗)。无需 flag 的原语只需要一个浏览器:
```
chrome --headless=new --no-sandbox http://127.0.0.1:8080/flag-free/01-primitives-flagfree.html
```
## 布局
```
flag-free/ the no-flags contribution (NO --allow-natives-syntax)
00-reachability trigger + patch differential (vuln 146 vs patched 147)
01-primitives addrof / fakeobj
02-store out-of-cage store
03-arw in-cage read64 / write64
rce-no-aslr/ the visible RCE (deterministic, no-ASLR lab build)
exploit-calc.html / exploit-exit.html
run.sh, demo.sh, pocmode.sh, xcalc-msgbox.sh
```
漏洞及根本原因分析:Nebula Security(链接如上)。无 flag 的触发器、
原语以及本仓库中的可见结果均是在本地实验室中验证过的复现/扩展。
标签:AI工具, Chrome, Cutter, Go语言工具, PoC, V8引擎, 后端开发, 多模态安全, 数据可视化, 暴力破解, 编程工具, 远程代码执行