Android’s Download Provider is a component of the Android framework and is designed to handle external downloads for other applications, such as web browsers (including Google Chrome), email clients (including Gmail), and the Google Play Store, among many others. In this blog post, I’ll describe three different high-severity vulnerabilities which affected several of the most recent versions of Android.
Android’s Download Provider
Any app can delegate its external downloads through this provider. As a developer, you’ll only need to insert a row with the appropriate parameters (invoking the Download Content Provider, part of the Download Provider, also called Download Manager). The Android Framework will handle the download for you automatically, in a background process which offers different configuration options. The notification with a progress bar that you’ve most likely seen several times (when downloading documents, attachments, or apps, for instance) is related to this provider, as illustrated in the following screenshots.
Overview of Vulnerabilities
By performing a research-driven manual code inspection of the Download Provider, using a very similar approach to the one I took with the Personal Dictionary Provider, I discovered three high-severity vulnerabilities. The following issues were reported to Google, along with their corresponding proof-of-concept tools for exploitation:
CVE-2018-9468: Download Provider Permission Bypass
The Download Provider is secured by different permissions and other protection mechanisms with various levels of access. As a general rule, a regular application should only have access to its own downloads. However, by exploiting this trivial vulnerability, any application (even without any permissions granted at all) can access any download that was requested by any other application or component of the OS itself, through the following content provider URI:
A malicious application would only need the identifier of a targeted download to gain access to it. This identifier is a sequential number, so all downloads are very easy to locate using a simple iteration. Once an existing download is located, most of the information stored in the provider’s database will be directly accessible through the Download Content Provider, including its title, description, size, full URL, etc. This may leak potentially sensitive information, including authentication tokens in the URL, email addresses, confidential document titles, email subjects found in the title or description columns, and so on.
This is only one of the aspects a malicious app can leverage.
Actually, the impact is notably higher, because the
openFile() method of the Content Provider is also affected by the vulnerability, since it relies on the
query() call to check for permissions. That means that the attacker would also have unrestricted read and write access to the downloaded files. By exploiting this flaw, it’s possible to leak any downloaded file, and even worse, to overwrite it with arbitrary content, even before the download is complete.
This would allow a malicious app to read and potentially exfiltrate all your downloads (think about email attachments, electronic bank statements, or any other file you may download while browsing the Internet), which is obviously pretty bad for your confidentiality and the integrity of your data.
The following video demonstrates how all this data, including file contents, is publicly accessible by any other app. The proof-of-concept exploit just iterates through a range of identifiers, dumps some fields from the internal database, and displays the initial chunk of the downloaded file. The results are limited for brevity and demonstration purposes only, but keep in mind that the entire file would be accessible.
Given the ability to write to these files, a malicious app can run a background service which monitors and overwrites any download requested through Android’s Download Provider. Since the Over-The-Air (OTA) updating process and the Google Play Store also use this provider, a malicious app can constantly overwrite any update or new app your smartphone is downloading, preventing a legitimate user from installing new apps or updating existing ones, including the OS itself, as demonstrated in the following videos.
In addition, any other downloaded attachment or file could easily be overwritten with arbitrary content using the very same process. This could be abused to replace files that you or your apps may consider trusted (from your bank, company intranet, HTTPS resources, apps using certificate pinning, etc.) to leverage a wide variety of potential exploits, as the downloads can’t be considered trusted anymore. These videos demonstrate the issue using different attack scenarios.
The source code and compiled APK for the proof-of-concept application used in these videos can be found in the following GitHub repository:
CVE-2018-9493: Download Provider SQL Injection
Some columns in the internal database (such as
CookieData) are considered private and can’t be accessed directly through the Download Content Provider, unless the caller has unrestricted permissions (the URI is protected by the
signatureOrSystem access level).
Specifying any of the restricted columns directly in the
projection parameter won’t give us the results, obviously, but exploiting an SQL injection in the where expression, bypassing the
setStrict filter, will allow us to extract content from the internal database, including restricted columns for any download. This vulnerability was introduced in 2016 in a change to enable search and filtering capabilities.
Note that this injection can also be combined with the
previously described vulnerability (CVE-2018-9468), bypassing the permission’s requirement (by accessing the
public_downloads URI, rather than
my_downloads). Otherwise, it only requires the
INTERNET permission (which isn’t considered dangerous and most apps have) in order to be exploited separately.
The source code and compiled APK for the proof-of-concept application that exploits this vulnerability can be found in the following GitHub repository:
CVE-2018-9546: Download Provider Headers Disclosure
Consider an application that requests a download which, apart from the URL, needs some HTTP headers, such as authentication, cookies, or anti-CSRF tokens, for instance. To support this feature, Android’s Download Provider allows developers to request a download with any standard or custom HTTP headers. These headers will be stored in the database and exposed through the Downloads Content Provider, by simply specifying the identifier of the related download.
Unfortunately, Android never checks if you have permission to access the desired rows belonging to the identifier you’re requesting, so all headers of every single download can be trivially dumped by simply iterating through all existing identifiers.
A malicious app only requires the
INTERNET permission to gain read access to all these headers. For instance, the default Android Browser app (not the latest versions of Google Chrome) in Android 5.1 stores all HTTP cookies in this table. This
could lead to a highly sensitive information leak, allowing an attacker to steal your sessions if you happen to download any file from an authenticated website using that browser, as demonstrated in the following video.
The source code and compiled APK for the proof-of-concept application used in the video can be found in the following GitHub repository:
As an Android user, make sure your device is fully patched and never install untrusted apps. These vulnerabilities were fixed in the AOSP patches released on September and October 2018. For different vendors, check their security bulletins to ensure all three CVEs enumerated here are listed as patched.
As a developer, always apply defense-in-depth best practices and never trust a downloaded file that could have been tampered with in transit or at rest, as demonstrated in the videos in this post. Beware of potential race conditions or TOCTOU (Time-of-Check to Time-of-Use) vulnerabilities in your validation process.
It wasn’t hard to find these high-severity vulnerabilities. I discovered them in a few hours, by simply inspecting some source code fragments and understanding a relatively small component of the Android Framework, such as the Download Content Provider.
Whether you are working from a developer’s or a security auditor’s perspective, make sure to identify all entry points, understand the big picture, and pay attention to every detail that might lead to a vulnerability. Most of the time, the problem isn’t in the code that you can read, but in the code that you can’t see because it isn’t there, even though it should be, such as missing validations, permission checks, and so on.
Find more detailed information in our corresponding security advisories:
IOActive Security Advisory – Android’s Download Provider Permission Bypass (CVE-2018-9468)
IOActive Security Advisory – Android’s Download Provider SQL Injection (CVE-2018-9493)
IOActive Security Advisory – Android’s Download Provider Request Headers Disclosure (CVE-2018-9546)