Syncing out of the Firefox sandbox
December 16, 2019 | Hossein LotfiThis is the first in our series of Top 5 interesting cases from 2019. Each of these bugs has some element that sets them apart from the more than 1,000 advisories released by the program this year. We begin with a Firefox web browser logical sandbox escape vulnerability.
In modern browser exploitation, compromising the renderer process is just half the story. To achieve full compromise, the sandbox must also be bypassed. In Pwn2Own 2019, Niklas Baumstark used a type confusion vulnerability in the IonMonkey optimizer to compromise the renderer process of Mozilla Firefox and then a logic bug identified as CVE-2019-9811 to escape the sandbox. The vulnerability which is going to be covered in this blog is another variant of CVE-2019-9811 identified as CVE-2019-9812 and is fixed in MFSA 2019-25.
A quick look at the Firefox architecture
You may already noticed that Firefox has a multi-process design with codename “Electrolysis” or “e10s”. This design separates and hosts different browser parts in several isolated and standalone processes. It allows to achieve a better performance as multiple processes can better leverage available resources on the computer. It further allows putting extra restrictions on some processes if desired. Why? Because we simply do not fully trust these processes, as they are processing untrusted data coming from the web and are prone to be compromised. These untrusted processes are called “renderer process”. They are children of a stronger parent process which is trusted and has regular access to the system resources. However, a renderer process may need access to a certain resource to fulfill its tasks, and this access is prohibited due to the restrictions on the process. In this case, it communicates with the parent process and asks for access to that needed resource. The parent can then decide whether to give the renderer process that access or not. In this way it is possible to greatly reduce the damage of a compromised renderer process by putting strict policy checks on the resources it is allowed to access.
You can see the process tree of a freshly run Firefox instance below:
The process with PID 6972 is the parent process, also known as the chrome process (not to be confused with Google’s Chrome browser). The first child process with PID 4012 is the GPU process, which enables the browser to display GPU-accelerated content. Note that these two are running at the “Medium” integrity level. Following them, there are three renderer processes with the “Low” integrity level. These integrity levels define the object access levels. The “Low” integrity level processes have less access to resources when compared to processes with “Medium” integrity level. Processes with “Low” integrity must ask the parent process to receive access to needed restricted resources.
Firefox Sync
Firefox Sync lets you share your bookmarks, browsing history, passwords, and other browser data between different devices and even send tabs from one device to another. To use Firefox Sync, you need to have a Mozilla account. Then when you are logged in to your account on a device and using Firefox, the browser data is synced to your account. When you log in to your Mozilla account from any other device, the latest browser data is fetched from your account and you can continue from where you left off.
Using Firefox Sync maliciously
The basic idea here is that an attacker can set up a Mozilla account with malicious browser data, e.g., weak browser configuration. If the attacker can lure or force a Firefox user to log in to this malicious account, then this weak configuration will be applied to the browser, and then the attacker can take advantage of this weakened Firefox. You might be able to do social engineering on a victim and ask him to log in to your malicious Mozilla account, but such a scenario is not acceptable in a serious attack demonstration, e.g., Pwn2Own. How about simulating this after compromising a renderer process? After all, in the end it is the renderer process which navigates to the Mozilla account login page and processes its data. In our case, we are dealing with a renderer process that is already compromised using a vulnerability in IonMonkey. It is now time to break out of the jail!
Sandbox escape through Firefox Sync
With the ability to execute arbitrary code in the compromised renderer the attacker moves on to escape the sandbox. Within the compromised renderer, the exploit first patches out some checks related to add-ons, principal, domain, and so forth, effectively disabling preventing renderer-side security checks:
By disabling these checks the renderer process can now log in to the attacker-controlled Mozilla account. This is started using the following JavaScript code:
Upon appending el
iframe element, the onload
handler is fired, which has the following body:
As you can see in the above code, it first waits for the login page and then logs in to the malicious account using the following JavaScript code:
Upon a successful login to the attacker-controlled Mozilla account, the victim browser data is synced, which permits various primitives that can be used for executing privileged code and escaping the sandbox:
1 - Privilege escalation by installing web extensions.
2 - Browser preference manipulation by setting services.sync.prefs.sync.<pref>
to true, which allows tampering of the security.sandbox.content.level
field. This could be used to disable the sandbox or make it weaker.
3 - Setting browser.tabs.remote.autostart
to false
, which would disable the multi-process design and make Firefox run as a single process (this setting is disabled in the most recent version of Firefox).
4 - Changing of browser.download.
, possibly leading to file overwrite.
Final notes
This particular vulnerability showed us once again how an attacker can (ab)use a legitimate feature in a product to achieve further gains. It is a good idea to isolate features as much as possible, and this is what the vendor did as a hardening among other changes: isolating these two sites and not allowing them to be loaded in a standard content process.
You can find me on Twitter at @hosselot and follow the team for the latest in exploit techniques and security patches. Stay tuned for the next Top 5 bug blog, which will be released tomorrow.