
Exploit para CVE-2019-9810 Firefox en Windows 64-bit.
CVE-2019-9810 es una vulnerabilidad que fue encontrada y explotada en Pwn2Own 2019 por Richard Zhu y Amat Cama. Afecta al motor JavaScript de Mozilla, SpiderMonkey, y fue utilizada para comprometer el renderizador.
El problema fue solucionado en mfsa2019-09 hace aproximadamente dos meses.
En pocas palabras, el error permite que una comprobación de límites sea considerada redundante y optimizada, permitiendo que el código acceda a memoria fuera de los límites. El problema en sí reside en el pase de Análisis de Alias (Alias Analysis) del pipeline de Ion. La siguiente imagen resalta la consecuencia del error en el pase de optimización GVN (la comprobación de límites se optimiza) y sirve como un buen resumen si es lo que estás buscando:

Si quieres saber más al respecto, te recomiendo echar un vistazo a Un viaje a IonMonkey: causa raíz de CVE-2019-9810.
El repositorio contiene el código del exploit así como un montón de herramientas que había desarrollado previamente para mis exploits de blazefox. Las he actualizado y las he hecho funcionar con BigInt. Como resultado, el exploit asume que el soporte para BigInt está activado en Firefox, lo cual se puede hacer alternando javascript.options.bigint en about:config.

El exploit se ha probado en Windows RS5 de 64 bits y está dirigido a una compilación personalizada de Firefox, así que no te sorprendas si se requiere un poco de trabajo para hacerlo funcionar en otro lugar :). Sin embargo, si solo quieres ejecutar el exploit sin compilar nada, he preparado un navegador empaquetado que subí en release/firefox-68.0a1.en-US.win64.7z. También incluye el shell js.exe así como información de símbolos privados para js.exe, firefox.exe y xul.dll.
El proceso de explotación funciona de manera muy similar al de mi exploit anterior kaizen.js como se mencionó anteriormente. Despacha la ejecución hacia el ReflectiveLoader de una dll reflectante que implementa el payload:
js.exe, simplemente inunda stdout con PWN, abre una calculadora y termina.Firefox.exe. Para lograrlo, el exploit de Javascript pasa un puntero a la copia de la dll reflectante, y la dll reflectante la mapea en los otros procesos. Una vez hecho esto, crea un hilo remoto en el cargador reflectante y toma una siesta. La razón es que el exploit está bastante sucio en su estado actual y no implementa la continuación del proceso. Aunque, en este punto no creo que sea mucho trabajo. Tal vez algún día me ponga a hacerlo :-).Firefox.exe, realiza un inline-hook de la función xul!nsJSUtils::ExecutionContext::Compile. Esta función se ejecuta cuando los scripts necesitan ser evaluados por el motor JavaScript; por lo que parecía un candidato suficientemente bueno para lo que quería hacer. La versión con hook simplemente antepone un payload JavaScript arbitrario de nuestra elección.En realidad, hay un montón de detalles más sutiles que no se describen arriba, así que si estás interesado, estás invitado a buscar la verdad y leer las fuentes :).
Para compilar el payload, solo tienes que ejecutar nmake desde un símbolo del sistema de VS 2017 x64.
CVE-2019-9810\payload>nmake
Microsoft (R) Program Maintenance Utility Version 14.16.27027.1
Copyright (C) Microsoft Corporation. All rights reserved.
ml64 /c src\trampoline.asm
Microsoft (R) Macro Assembler (x64) Version 14.16.27027.1
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: src\trampoline.asm
if not exist .\bin mkdir bin
type injected-script.js > src\injected-script.h
cl /O1 /nologo /W3 /D_AMD64_ /DWIN_X64 /DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN /Febin\payload.dll src\ReflectiveLoader.c src\ReflectiveDll.cc trampoline.obj /link /DLL /nologo /debug:full /PDBALTPATH:%_PDB%
ReflectiveLoader.c
Generating Code...
Compiling...
ReflectiveDll.cc
Generating Code...
Creating library bin\payload.lib and object bin\payload.exp
python jsify_payload.py bin\payload.dll
move payload.js ..
1 file(s) moved.
del *.obj
del src\injected-script.h
if exist .\bin del bin\*.exp bin\*.ilk bin\*.lib
Esto crea un archivo payload.dll / payload.pdb dentro del directorio payload\bin. Así como un archivo JavaScript llamado payload.js que incrusta la dll dentro de un Uint8Array con el offset al cargador.
Escribí este exploit contra una compilación local de Windows sincronizada con el siguiente id de revisión: 2abb636ad481768b7c88619080cf224b2c266b2d (si no quieres compilarlo tú mismo, he subido mi compilación aquí: release/firefox-68.0a1.en-US.win64.7z):
$ hg --debug id -i
2abb636ad481768b7c88619080cf224b2c266b2d
Y he usado el siguiente archivo mozconfig:
. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
ac_add_options --disable-crashreporter
ac_add_options --enable-debug-symbols
. "$topsrcdir/build/mozconfig.clang-cl"
. "$topsrcdir/build/mozconfig.lld-link"
# Use the clang version in .mozbuild
CLANG_LIB_DIR="$(cd ~/.mozbuild/clang/lib/clang/*/lib/windows && pwd)"
export LIB=$LIB:$CLANG_LIB_DIR
ac_add_options --enable-js-shell
ac_add_options --enable-jitspew
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-ff64
Aunque fue suficiente para mi propósito, no estoy seguro de que xul!nsJSUtils::ExecutionContext::Compile sea la función perfecta para insertar scripts arbitrarios. Estoy seguro de que dedicando más tiempo a entender un poco cómo funciona el front-end de xul, se podría encontrar un mejor punto de hook.
Otro par de vías que descubrí después de escribir el exploit se discuten en esta entrada de bugzilla: 982974 (Principal del sistema para el intérprete de JavaScript y security.turn_off_all_security_so_that_viruses_can_take_over_this_computer). Sería interesante ver cuánto de eso sigue siendo relevante para Firefox hoy.
Quizás alguien ya investigó este tema y yo lo perdí por completo. En cualquier caso, ¡no dudes en contactarme con cualquier comentario!
Otra cosa interesante sería explorar si existe alguna forma de tener un mecanismo de persistencia dentro del navegador. No he investigado esta área en absoluto, pero sería bastante genial :).