Firefox: How a website could steal all your cookies

Pedro Oliveira
Nov 16 · 6 min read
Image for post
Image for post

This is a write up for CVE-2020–15647, explaining how webpages are capable of stealing files from your Android device, including but not limited to cookies from any visited website.

Introduction

In mid-2020, I started checking Android browsers for multiple types of vulnerabilities; while reviewing v68.9.0 of Firefox for Android, I noticed it displaying strange behaviour when browsing content:// URIs.

For context, Content URIs in Android identify data in a ; they can represent multiple forms of information, such as files or database information.

Most browsers support the parsing and processing of both file:// and content:// URI schemes. If you try to open a local HTML file in your browser, it will most likely use a content:// URI created by the file browser you used when opening the file.

Testing the content:// URI

When I tested Firefox’s use of content URIs, I noticed the address bar was changing while rendering the URI, redirecting me to a file:// URI. It appeared that Firefox was saving the content to a file, and then redirecting me to that created file - the file was being saved in the internal temporary folder /data/data/org.mozilla/firefox/cache/contentUri/.

Firefox file download/redirect routine
Firefox file download/redirect routine
Firefox file download/redirect routine

I also noticed the file that was created had the same name as the display name (_display_name) returned by the provider, with Firefox not changing the name (and therefore overwriting the file) if it already existed.

Permissions

The thing with content providers is that generally, applications require specific URI permissions in order to fetch contents from other applications and providers. This prevents applications from accessing files from other providers unless they have been explicitly granted permission (which is the case when tapping “Open with” or “Share with” and choosing an application to access a file). However, an application does not need to go down this route when accessing URIs from their own content providers.

Firefox had a whose authority was org.mozilla.firefox.fileprovider, and had the following configuration:

<paths xmlns:android="">
<root-path name="root" path="."/>
</paths>

This is an issue, due to the use of the root-path configuration; I could open virtually any file in Firefox, provided it had access.

Showing contents of a private Firefox file
Showing contents of a private Firefox file
Showing contents of a private Firefox file

Now that we knew we could open any file, let’s try to expose file contents to the outside. ​

Taking advantage of SOP for file://

The way Firefox deals with cross-domain requests for file:// is pretty . For the purpose of this exploit, the only thing you need to know is that a file can access its own contents (i.e. via new XMLHttpRequest().open("GET", window.location, true)) because the origin is the same.

Now, if a file can request its own contents, and these contents can be replaced, I might be able to spoof the contents of a file with another file using the same name, right?

I started off with simple testing — I needed to retrieve the contents of a private file by opening a file from the external directory. In this case I chose /data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini; this file contains information on where the cookie database is stored in the device.

To retrieve this file, I need to create a file with the same name, saving it in /sdcard/Download/profiles.ini. Like in the first paragraph, I'll be using XMLHttpRequest to retrieve window.location.

/sdcard/Download/profiles.ini

To load this script, we’ll also create an iframe in the same file which loads a content:// URI pointing to the file we are actually trying to read; by opening with a content:// URI, we will leverage Firefox's copying of the file to another location and accessing it via file://. ​

/sdcard/Download/profiles.ini

Printing contents of /data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini
Printing contents of /data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini
Showing contents of /data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini

To summarise the above, by opening the file we’ve created:

  1. Firefox opens content://org.mozilla.firefox.fileprovider/root/sdcard/Download/profiles.ini, which is the content URI representation of the file /sdcard/Download/profiles.ini
  2. Firefox fetches the content given by its provider and saves it in /data/data/org.mozilla.firefox/cache/contentUri/profiles.ini
  3. Firefox redirects the user to the file in step 2, prefixing it with the file:// URI
  4. The HTML page, once rendered, has the iframe request the content:// URI in its src field, which has the same name as the currently opened file (albeit in a different location), content://org.mozilla.firefox.fileprovider/root/data/user/0/org.mozilla.firefox/files/mozilla/profiles.ini
  5. Firefox replaces the contents of the file opened in step 3 with the contents of the file in step 4
  6. After a short delay, the page alerts its own contents (which has now been changed to the contents of the other file in step 4

We now have a cross-domain issue, as a file:// URI can access contents from another file:// URI if the files share the same names. Furthermore, because we are using Firefox's provider; that provider's root-path configuration means we could exploit this to access any file on the device. ​

Escalating to remote

The next question was checking if it was possible to convert this vulnerability into a remotely-executable proof of concept, using android-app Intent URIs.

Intent URIs are commonly used by deep linking features; you can read more about them and .

I’ll setup a Python server to allocate this next exploit. The first thing we need is a file with the same name that we need to steal. In that case, our remote webpage should be able to trigger a download of the profiles.ini file we created.

Once the file has been downloaded we need to open it; we’ll use a deep linking content URI to continue making use of Firefox moving the downloaded file to its internal directory:

This should do as before; it will request Firefox (org.mozilla.firefox part of the android-app URI) to open the content URI content://org.mozilla.firefox.fileprovider/root/sdcard/Download/profiles.ini with action android.intent.action.VIEW, downloading its contents to /data/data/org.mozilla.firefox/cache/contentUri/profiles.ini and opening it with the file:// URI.

Remotely accessing contents of profiles.ini
Remotely accessing contents of profiles.ini
Remotely accessing contents of profiles.ini

It works — the sensitive file’s contents have been printed. You can check out the full code .

Conclusion and final thoughts

As demonstrated, it was possible to steal files from the device solely by having the victim visit a webpage. In a real attack scenario, the malicious file would send the contents read to an attacker-controlled server, rather than outputting the contents in an alert modal.

When I submitted the vulnerability, the proof of concept I presented highlighted the ability to steal Firefox’s cookie database, which was an sqlite database containing all cookies from visited domains.

Below is an example of the PoC:

Remotely accessing contents of internal cookie database
Remotely accessing contents of internal cookie database
Remotely accessing contents of cookies.sql

shows how the exploit works:

Diagram of full PoC, sending user’s cookies to a malicious server
Diagram of full PoC, sending user’s cookies to a malicious server
Diagram of full PoC, sending user’s cookies to a malicious server

At the time of reporting, Firefox Fennec (v68.9.0) was nearing “end-of-life” and would have been replaced with Fenix which wasn’t vulnerable. Even so, Firefox considered this a critical issue and patched the vulnerability in a short timespan, pushing the version to (v68.10.1). This just shows how seriously these guys take security issues in their platforms. They were also very professional and easy to communicate with.

This writeup is a part of series of writeups I found in 2020 on Android browsers. Stay tuned for future writeups on other browsers (such as Brave and Samsung Browser)!

Timeline

2020–06–20 — Issue reported to Mozilla

2020–06–22 — Internal investigation started

2020–06–25 — Issue confirmed and addressed (on the same day 👏🏼)

2020–07–06 — Fixed version released on Play Store (v68.10.1)

2020–07–07 — Bounty assigned ($5000)

Twitter:

LinkedIn:

HackerOne:

Special thanks to for reviewing this writeup and to for the help with the full PoC diagram.

InfoSec Write-ups

A collection of write-ups from the best hackers in the…

Sign up for Infosec Writeups

By InfoSec Write-ups

Newsletter from Infosec Writeups 

By signing up, you will create a Medium account if you don’t already have one. Review our for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Pedro Oliveira

Written by

Android Developer and Security Enthusiast

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. Maintained by Hackrew

Pedro Oliveira

Written by

Android Developer and Security Enthusiast

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. Maintained by Hackrew

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface.

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox.

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store