
PoC-Exploit-Kette für CVE-2026-2796: SpiderMonkey-WebAssembly-Sandbox-Escape (Signatur-Typkonfusion -> beliebiges R/W -> RCE)
Proof-of-Concept-Exploit-Kette für CVE-2026-2796, eine JIT-Fehlkompilierung / Typverwechslung in Mozilla SpiderMonkeys WebAssembly-Import-Optimierung (Komponente „JavaScript: WebAssembly“). Ein präpariertes Wasm-Modul erlangt beliebiges Lesen/Schreiben im gesamten Host-Prozess und beliebige native Codeausführung und entkommt damit der WebAssembly-Sandbox.
e2acef67 („Bug 2013165 - Fix import optimization“)Wenn ein Wasm-Modul eine JS-Funktion importiert, wendet SpiderMonkey eine Optimierung in MaybeOptimizeFunctionCallBind (js/src/wasm/WasmInstance.cpp) an, die Importe der Form Function.prototype.call.bind(fn) entpackt und direkt als aufrufbares Objekt des Imports speichert. Dabei wurde nicht geprüft, ob der gebundene Wert selbst eine ist:
fn+ if (boundThis.toObject().is<JSFunction>() &&
+ boundThis.toObject().as<JSFunction>().isWasm()) {
+ return nullptr;
+ }
Fehlt diese Prüfung, wird der Import als eine ursprünglich als Wasm exportierte Funktion behandelt: Der JS-Wrapper – und mit ihm die Signaturprüfung – wird übersprungen. Eine Wasm-Funktion kann daher über einen deklarierten Importtyp aufgerufen werden, der nicht ihrem tatsächlichen Typ entspricht. Werte werden unverändert in Registern durchgereicht; nur ihre Interpretation ändert sich (z. B. wird eine angreiferkontrollierte i64 als GC-Zeiger (ref $t) verwendet und umgekehrt).
| Datei | Stufe | Ergebnis |
|---|---|---|
poc-crash.js | Signaturverwechslung | i64.const 0xDEADBEEF als Funcref-Zeiger dereferenziert → SIGSEGV bei 0xdeadbf2f |
poc-addrof.js | addrOf + fakeobj | Verwechslung in beide Richtungen (i64 ↔ (ref $t)) → gefälschtes WasmArrayObject (numElements_ @+16, data_ @+24, Inline-Elemente @+40) → beliebiges Lesen/Schreiben überall im Prozess |
poc-recon.js | Layout-Aufklärung | JSFunction-Native-Zeiger @+0x20 → Leak der Binärbasis; WasmFuncRef typeDef-Zeiger @+0x40 |
poc-forge.js | Kontrollfluss | Gefälschter Funcref besteht die call_ref-Typprüfung; Aufrufziel aus [funcref+0x38] geladen |
poc-rce.js | Codeausführung | Gefälschter Funcref → system("touch /tmp/CVE-2026-2796-PWNED") über geleaktes system() (Binärbasis + GOT-Eintrag @ base+0x11d47b0) |
Die Verwechslungs-Primitive wird exakt wie in Mozillas eigenem Regressionstest (js/src/jit-test/tests/wasm/regress/bug2013165.js) erzielt: Import von Function.prototype.call.bind(wasmExport) in ein zweites Modul, dessen Importdeklaration eine andere Signatur trägt, dann 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()
Auf einem gepatchten Build (Firefox ≥ 148) wirft poc-crash.js stattdessen TypeError: bad type — die Signaturprüfung ist wiederhergestellt.
Die Offsets gelten für macOS arm64 (js-Shell, exakt diese Revision/Build-Flags): WasmArrayObject { +16 numElements, +24 data_, +40 Inline-Daten }, JSFunction native @ +0x20, WasmFuncRef { +0x40 typeDef, +0x38 Aufrufziel }. Sie werden zur Laufzeit durch die Selbsttests der PoCs empirisch validiert; andere Builds/Architekturen müssen sie neu herleiten (der Recon-PoC automatisiert den Großteil davon). Kein PAC bei arm64-Binaries (nicht arm64e); JIT-Bereiche sind zum Aufrufzeitpunkt nicht beschreibbar, daher kapert die Kette ein vorhandenes Aufrufziel, anstatt Code einzuschleusen.
Siehe docs/full-escape.md für die Analyse der zweiten Stufe: Escape aus der OS-Sandbox aus der Codeausführung im Renderer heraus über CVE-2026-2768 (Bug 2014101, OOB-Write in IndexedDB des Elternprozesses) — der „zweite Bug“ einer vollständigen Firefox-Kompromittierung. Der hier verwendete verwundbare Quellbaum stammt ebenfalls aus der Zeit vor diesem Fix.
Dies entkommt der Sandbox der Wasm-Engine (Eindämmung von linearem Speicher/GC) und ermöglicht native Codeausführung im aktuellen Prozess. Bei einem realen Browser-Angriff landet dies im Content-Prozess von Firefox; das Entkommen aus der OS-Sandbox (der „zweite Bug“: IPC-Verwechslung oder Kernel-Exploit) ist ein separates Problem und nicht Teil dieses PoC.
javascript.options.wasm=false blockiert den Auslösevektor.Nur für Sicherheitsforschung, Bildung und defensive Tests. Die Schwachstelle ist in aktuellen Firefox-/Thunderbird-Versionen behoben. Nicht gegen Systeme verwenden, die Sie nicht besitzen oder für die Sie keine ausdrückliche Testberechtigung haben.