
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 . Eu apenas as atualizei e as fiz funcionar com . Como resultado, o exploit assume que o suporte para está ativado no Firefox, o que pode ser feito alternando em .
javascript.options.bigintabout: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
Embora tenha sido suficiente para o meu propósito, não tenho certeza se xul!nsJSUtils::ExecutionContext::Compile é a função perfeita para inserir scripts arbitrários. Tenho certeza de que gastar mais tempo entendendo um pouco como funciona o front-end do xul poderia levar a um ponto de hook melhor.
Alguns outros caminhos que descobri após escrever o exploit são discutidos nesta entrada do bugzilla: 982974 (System principal for the JavaScript interpreter and security.turn_off_all_security_so_that_viruses_can_take_over_this_computer). Seria interessante ver o quanto disso ainda é relevante para o Firefox hoje.
Talvez alguém já tenha pesquisado este assunto e eu tenha perdido completamente. De qualquer forma, fique à vontade para me contatar com qualquer feedback!
Outra coisa interessante seria explorar se há alguma maneira de ter um mecanismo de persistência no navegador. Não pesquisei essa área ainda, mas seria muito legal :).