
CVE-2024-29943, pero con wasm
Una cadena de explotación de extremo a extremo para CVE-2024-29943 que logra
ejecución de código nativo arbitrario introduciendo shellcode en la página de
código JIT de WebAssembly de SpiderMonkey como inmediatos f64.const — sin ROP,
sin VirtualProtect, sin toolchain externo.
Verificado funcionando contra el shell de SpiderMonkey del nightly de
mozilla-central del 2024-03-20 (JavaScript-C126.0a1, linux x86-64, pre-fix):
la cadena se ejecuta hasta completarse y el payload se ejecuta
(write(1, "PWNED by wasm!\n"); exit(0)).
CVE-2024-29943 es un bug sec-critical de análisis de rangos de IonMonkey usado en Pwn2Own 2024 por Manfred Paul, que afecta a Firefox < 124.0.1 (Bugzilla 1886849, CVSS 9.8).
MObjectKeysLength::computeRange devolvía un rango entero incorrecto para
Object.keys(x).length después de que Object.keys se hiciera elidible
(regresión introducida por el bug 1845728). El análisis de rangos de Ion
concluyó que un contador de bucle no podía volverse negativo y eliminó
comprobaciones de límites que seguían siendo alcanzables, produciendo una
lectura/escritura fuera de límites sobre 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
Dos detalles nos costaron un segfault cada uno para aprenderlos, así que quedan escritos:
eagerInterpEntryOffset_ en el FuncExport residente en el heap — el
intérprete calcula codeBase + offset y salta allí.La técnica de shellcode en la página JIT de WASM proviene de WasmBlazeFox; este repositorio demuestra que la técnica se compone con un bug moderno de un navegador en producción en lugar del bug de entrenamiento original de 2018.
poc.js — disparador mínimo para el bug de análisis de rangos.exploit.js — cadena completa: primitivas + etapa de shellcode en el JIT de WASM.gen_wasm.py — ensambla el módulo WASM incrustando el shellcode y verifica
el round-trip de la constante. python3 gen_wasm.py mysc.bin para usar un
payload diferente. El payload por defecto es una prueba de syscall pura
write(1, "PWNED by wasm!\n"); exit(0) que no necesita resolución de
símbolos (por lo que también funciona en el jsshell desnudo). Para el payload
clásico basado en libxul system("gnome-calculator"), véase WasmBlazeFox ex6.test.gdb — puntos de interrupción y ayudantes ptype /o para derivar
offsets del modelo de objetos en una build dada.afbdf6822c9e9f9b6d44b9ea6904cb10878126b1 (Firefox ~124, pre-124.0.1),
Linux x86-64 — o toma un jsshell nightly pre-fix, por ejemplo
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 es necesario porque la eliminación de comprobaciones
de límites depende de que el enmascaramiento de índices esté deshabilitado
(véanse los comentarios de Bugzilla).
f64.const
se emiten en línea en el segmento de código. La compilación de Ion podría
plegarlos como constantes.WASM_INSTANCE_OFF_CODE = 0xa8, MetadataTier.funcExports + 448,
FuncExport + 8, etc.) se derivaron de las cabeceras del commit vulnerable
y se confirmaron contra el jsshell nightly del 2024-03-20; vuelve a derivarlos
con test.gdb para otras builds.