一条针对 CVE-2024-29943 的端到端漏洞利用链,通过将 shellcode 以 f64.const 立即数的形式偷运进 SpiderMonkey 的 WebAssembly JIT 代码页,实现任意原生代码执行——无需 ROP,无需 VirtualProtect,无需外部工具链。
已验证可用,针对 2024-03-20 mozilla-central nightly 的 SpiderMonkey shell(JavaScript-C126.0a1,linux x86-64,修复前版本):利用链完整运行,payload 成功执行(write(1, "PWNED by wasm!\n"); exit(0))。
CVE-2024-29943 是一个 sec-critical 级别的 IonMonkey 范围分析漏洞,由 Manfred Paul 在 Pwn2Own 2024 上使用,影响 Firefox < 124.0.1(Bugzilla 1886849,CVSS 9.8)。
在 Object.keys 被改为可省略(由 bug 1845728 引入回归)之后,MObjectKeysLength::computeRange 为 Object.keys(x).length 返回了错误的整数范围。Ion 范围分析据此断定某个循环计数器不可能为负,从而消除了仍然可达的边界检查,导致对 Uint8Array 的越界读/写。
Object.keys 范围分析漏洞 -> 对 Uint8Array 的越界读/写
-> 破坏相邻的 ArrayBuffer -> addrof / fakeobj / 任意读/写
-> 实例化手工构造的 WASM 模块(shellcode 以 f64.const 立即数形式嵌入)
-> WasmInstanceObject -> wasm::Instance -> wasm::Code -> CodeTier
-> ModuleSegment.bytes_(JIT 代码页,RX)
-> 扫描页面寻找标记常量
-> 覆写 FuncExport.eagerInterpEntryOffset_(普通堆内存)
为 shellcode 在页面内的偏移
-> 通过解释器调用该导出函数 -> payload 执行
有两个细节,每一个都让我们付出了一次段错误的代价才搞明白,所以记录下来:
FuncExport 中的 eagerInterpEntryOffset_ 来实现——解释器会计算 codeBase + offset 并跳转过去。WASM-JIT-页 shellcode 技术来自 WasmBlazeFox;本仓库演示了该技术可以与一个现代、实际发布的浏览器漏洞组合使用,以替代最初的 2018 年训练漏洞。
poc.js — 范围分析漏洞的最小触发器。exploit.js — 完整利用链:原语 + WASM JIT shellcode 阶段。gen_wasm.py — 组装嵌入 shellcode 的 WASM 模块,并验证常量往返。使用 python3 gen_wasm.py mysc.bin 可换用不同的 payload。默认 payload 是一个纯系统调用的 write(1, "PWNED by wasm!\n"); exit(0) 验证程序,无需符号解析(因此也能在裸 jsshell 中工作)。若需要经典的基于 libxul 的 system("gnome-calculator") payload,请参见 WasmBlazeFox ex6。test.gdb — 断点和 ptype /o 辅助工具,用于在给定构建上推导对象模型偏移。afbdf6822c9e9f9b6d44b9ea6904cb10878126b1(Firefox ~124,124.0.1 之前),Linux x86-64——或者获取一个修复前的 nightly jsshell,例如 archive.mozilla.org/pub/firefox/nightly/2024/03/2024-03-20-21-16-35-mozilla-central/jsshell-linux-x86_64.zip。LD_LIBRARY_PATH=<jsshell dir> ./js --no-threads --ion-offthread-compile=off \
--spectre-mitigations=off poc.js # 仅触发(段错误)
LD_LIBRARY_PATH=<jsshell dir> ./js --no-threads --ion-offthread-compile=off \
--spectre-mitigations=off exploit.js # 完整利用链("PWNED by wasm!")
--spectre-mitigations=off 是必需的,因为边界检查消除依赖于索引掩码被禁用(参见 Bugzilla 评论)。
f64.const 立即数会内联生成在代码段中。Ion 编译可能会将它们常量折叠。WASM_INSTANCE_OFF_CODE = 0xa8、MetadataTier.funcExports + 448、FuncExport + 8 等)是从漏洞所在提交的头文件中推导出来的,并针对 2024-03-20 nightly jsshell 进行了确认;对于其他构建,请使用 test.gdb 重新推导。