CVE-2019-9810 is a vulnerability that has been found and exploited at Pwn2Own 2019 by Richard Zhu and Amat Cama. It affects Mozilla's JavaScript engine, Spidermonkey and was used to achieve renderer compromise.
The issue has been fixed in mfsa2019-09 about two months ago.
TODO.
The repository contains the exploit code as well as a bunch of tools that I had previously developed for my blazefox exploits. I have just brushed them up and made them work with BigInt. As a result, the exploit assumes that the support for BigInt is turned on in Firefox which you can do by toggling javascript.options.bigint
in about:config
.
The exploit has been tested against Windows RS5 64-bit and it targets a custom build of Firefox so don't be surprised if a bit of work is required to make it work elsewhere :).
The exploitation process works very similarly than in my previous kaizen.js exploit as mentioned above. It dispatches execution on the ReflectiveLoader of a reflective dll that implements the payload:
- If the payload detects that it is invoked by
js.exe
, it simply spamsstdout
withPWN
, spawns a calculator and exits. - If it is run from the browser, it starts by injecting itself into other
Firefox.exe
processes. To achieve that, the Javascript exploit passes a pointer to the reflective dll copy, and the reflective dll maps it in the other processes. Once this is accomplished, it creates a remote thread on the reflective loader and takes a nap. The reason for that is that the exploit is pretty dirty in its current state and doesn't implement process continuation. Altough, at this point I don't think it would be a lot of work. Maybe I'll get around of do it :-). - When the payload gets executed from other
Firefox.exe
's, it inline-hooks the xul!nsJSUtils::ExecutionContext::Compile function. This function gets executed when scripts need to be evaluated by the JavaScript engine; so this sounded like a good enough candidate for what I wanted to do. The hooked version simply prepends an arbitrary JavaScript payload of our choice. - When the hook is placed, it simply returns. At this point, the other origins have had arbitrary JavaScript injected in them. The payload I use is simply to change the background image of those origins by the Diary of a reverse-engineer theme picture, as well as redirecting every links to the blog :).
In reality, there are a bunch of more subtle details that are not described by the above and so if you are interested you are invited to go find the truth and read the sources :).
To build the payload, you just have to run nmake
from a VS 2017 x64 prompt.
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
This creates a payload.dll
/ payload.pdb
file inside the payload\bin
directory. As well as a JavaScript file called payload.js
which embeds the dll inside an Uint8Array with the offset to the loader.
Although it was fine for my purpose, I am unsure xul!nsJSUtils::ExecutionContext::Compile
is the perfect function for inserting arbitrary scripts. I am sure spending more time understanding a bit how works the xul front-end one could come up with a better hooking point. Maybe somebody already researched this subject and I completely missed it. In any case, feel free to ping me with any feedback!
Another interesting thing would be to explore if there any way to have a persistence mechanism with in the browser. I haven't researched this area at all but that would be pretty cool :).