
CVE-2024-29943, ma con wasm
Una catena di exploit end-to-end per CVE-2024-29943 che ottiene
l'esecuzione arbitraria di codice nativo contrabbandando shellcode nella
pagina di codice JIT WebAssembly di SpiderMonkey come immediati f64.const
— niente ROP, niente VirtualProtect, niente toolchain esterna.
Verificato funzionante contro la shell SpiderMonkey della
nightly mozilla-central del 2024-03-20 (JavaScript-C126.0a1, linux x86-64,
pre-fix): la catena arriva a completamento e il payload viene eseguito
(write(1, "PWNED by wasm!\n"); exit(0)).
CVE-2024-29943 è un bug sec-critical di range-analysis di IonMonkey usato al Pwn2Own 2024 da Manfred Paul, che colpisce Firefox < 124.0.1 (Bugzilla 1886849, CVSS 9.8).
MObjectKeysLength::computeRange restituiva un intervallo intero errato per
Object.keys(x).length dopo che Object.keys era stato reso elidibile
(regressione introdotta dal bug 1845728). L'analisi dei range di Ion concludeva
che un contatore di ciclo non potesse diventare negativo ed eliminava i
controlli sui limiti che erano ancora raggiungibili, producendo una
lettura/scrittura out-of-bounds su un .
Uint8ArrayObject.keys range-analysis bug -> OOB r/w on Uint8Array
-> corrupt adjacent ArrayBuffer -> addrof / fakeobj / arbitrary R/W
-> instantiate hand-built WASM module (shellcode as f64.const immediates)
-> WasmInstanceObject -> wasm::Instance -> wasm::Code -> CodeTier
-> ModuleSegment.bytes_ (the JIT code page, RX)
-> scan page for marker constant
-> overwrite FuncExport.eagerInterpEntryOffset_ (plain heap)
with the shellcode's offset within the page
-> call the export through the interpreter -> payload runs
Due dettagli ci sono costati un segfault ciascuno per essere appresi, quindi li annotiamo:
eagerInterpEntryOffset_ nel FuncExport residente nell'heap — l'interprete
calcola codeBase + offset e salta lì.La tecnica dello shellcode nella pagina WASM-JIT proviene da WasmBlazeFox; questo repo dimostra che la tecnica si compone con un bug moderno di un browser in produzione al posto del bug di training originale del 2018.
poc.js — trigger minimale per il bug di range-analysis.exploit.js — catena completa: primitive + stadio shellcode WASM JIT.gen_wasm.py — assembla il modulo WASM incorporando lo shellcode e verifica
il round-trip della costante. python3 gen_wasm.py mysc.bin per usare un
payload diverso. Il payload predefinito è una prova puramente a syscall
write(1, "PWNED by wasm!\n"); exit(0) che non richiede risoluzione di
simboli (quindi funziona anche nella jsshell nuda). Per il classico payload
system("gnome-calculator") basato su libxul, vedi WasmBlazeFox ex6.test.gdb — breakpoint e helper ptype /o per derivare gli offset
dell'object-model su una data build.afbdf6822c9e9f9b6d44b9ea6904cb10878126b1 (Firefox ~124, pre-124.0.1),
Linux x86-64 — oppure prendi una nightly jsshell pre-fix, ad es.
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 # trigger only (segfault)
LD_LIBRARY_PATH=<jsshell dir> ./js --no-threads --ion-offthread-compile=off \
--spectre-mitigations=off exploit.js # full chain ("PWNED by wasm!")
--spectre-mitigations=off è richiesto perché l'eliminazione dei controlli sui
limiti si basa sul fatto che il mascheramento degli indici sia disabilitato
(vedi i commenti su Bugzilla).
f64.const
vengono emessi inline nel segmento di codice. La compilazione Ion potrebbe
fare constant-folding su di essi.WASM_INSTANCE_OFF_CODE = 0xa8, MetadataTier.funcExports + 448,
FuncExport + 8, ecc.) sono stati derivati dagli header del commit
vulnerabile e confermati contro la nightly jsshell del 2024-03-20;
ri-derivali con test.gdb per altre build.