
Exploit para CVE-2019-9810 Firefox no Windows 64-bit.
CVE-2019-9810 é uma vulnerabilidade que foi encontrada e explorada no Pwn2Own 2019 por Richard Zhu e Amat Cama. Ela afeta o mecanismo JavaScript da Mozilla, Spidermonkey, e foi usada para comprometer o renderizador.
O problema foi corrigido em mfsa2019-09 há cerca de dois meses.
Em resumo, o bug permite que uma verificação de limites seja considerada redundante e otimizada, permitindo que o código acesse memória fora dos limites. O problema em si está na passagem de Alias Analysis do pipeline do Ion. A imagem abaixo destaca a consequência do bug na otimização GVN (verificação de limites sendo otimizada) e serve como um bom resumo se é isso que você está procurando:

Se você quiser saber mais sobre isso, recomendo dar uma olhada em A journey into IonMonkey: root-causing CVE-2019-9810.
O repositório contém o código do exploit bem como um conjunto de ferramentas que eu desenvolvi anteriormente para meus exploits do blazefox. Eu apenas as atualizei e as fiz funcionar com BigInt. Como resultado, o exploit assume que o suporte para BigInt está ativado no Firefox, o que pode ser feito alternando javascript.options.bigint em about:config.

O exploit foi testado no Windows RS5 de 64 bits e tem como alvo uma compilação personalizada do Firefox, então não se surpreenda se for necessário algum trabalho para fazê-lo funcionar em outro lugar :). No entanto, se você quiser apenas executar o exploit sem compilar nada, preparei um navegador empacotado que enviei em release/firefox-68.0a1.en-US.win64.7z. Ele também inclui o shell js.exe bem como informações de símbolos privados para js.exe, firefox.exe e xul.dll.
O processo de exploração funciona de forma muito semelhante ao meu exploit anterior kaizen.js como mencionado acima. Ele despacha a execução para o ReflectiveLoader de uma dll reflexiva que implementa o payload:
js.exe, ele simplesmente envia PWN para stdout, abre uma calculadora e sai.Firefox.exe. Para conseguir isso, o exploit em Javascript passa um ponteiro para a cópia da dll reflexiva, e a dll reflexiva a mapeia nos outros processos. Uma vez feito isso, ele cria uma thread remota no carregador reflexivo e tira uma soneca. A razão para isso é que o exploit está bastante sujo em seu estado atual e não implementa continuidade de processo. Embora, a essa altura, eu não ache que seria muito trabalho. Talvez eu consiga fazer isso :-).Firefox.exe, ele faz inline-hook da função xul!nsJSUtils::ExecutionContext::Compile. Esta função é executada quando scripts precisam ser avaliados pelo mecanismo JavaScript; então isso pareceu um candidato bom o suficiente para o que eu queria fazer. A versão com hook simplesmente prefixa um payload JavaScript arbitrário de nossa escolha.Na realidade, há uma série de detalhes mais sutis que não são descritos acima e, se você estiver interessado, é convidado a encontrar a verdade e ler as fontes :).
Para compilar o payload, basta executar nmake a partir de um prompt do 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
Isso cria um arquivo payload.dll / payload.pdb dentro do diretório payload\bin. Além disso, um arquivo JavaScript chamado payload.js que incorpora a dll dentro de um Uint8Array com o offset para o carregador.
Escrevi este exploit contra uma compilação local do Windows sincronizada com o seguinte id de revisão: 2abb636ad481768b7c88619080cf224b2c266b2d (se você não quiser compilar por conta própria, fiz upload da minha compilação aqui: release/firefox-68.0a1.en-US.win64.7z):
$ hg --debug id -i
2abb636ad481768b7c88619080cf224b2c266b2d
E usei o seguinte arquivo 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