Advisory: Crashing Android devices with large Proxy Auto Config (PAC) Files [CVE-2016-6723]

Summary

Android devices can be crashed forcing a halt and then a soft reboot by downloading a large proxy auto config (PAC) file when adjusting the Android networking settings. This can also be exploited by an MITM attacker that can intercept and replace the PAC file. However, the bug is mitigated by multiple factors and the likelihood of exploitation is low.

This issue has been fixed in the November 2016 Android security bulletin.

Background – Proxy Auto Config (PAC) Files

Proxy Auto Config (PAC) files are text files that can be used as part of the network settings configuration to allow a web browser and other software that accesses the web. These files define which proxy servers should be used for which types of requests. They usually contain a Javascript function which can be called by the web browser to determine the type of proxy server to use. An example PAC file appears here:

function FindProxyForURL(url, host) {
  if (isResolvable(host))
    return "DIRECT";
  else
    return "PROXY proxy.mydomain.com:8080";
  }
}

A related standard called Web Proxy Auto-Discovery Protocol (WPAD) allows devices to find the locations of PAC files via DHCP and/or DNS. However, WPAD is not currently supported on Android.

Vulnerability Details

When configuring a network in Android, one of the options available in the “Advanced” section is ability to indicate a Proxy Auto Config (PAC) URL which will point to a PAC file described above. The current code in Android does not check whether the PAC file may be too large to load into memory, which allows an MITM attacker to replace a known PAC file (if served without SSL) with a large one of their own and crash the Android phone.

Example of settings dialog in Android:

pac-screen

The vulnerability is that the Java code does not check how large the data file actually is. If a file is served that is larger than the memory available on the device, this results in all memory being exhausted and the phone halting and then soft rebooting. The soft reboot was sufficient to recover from the crash and no data was lost. While we have not been able to achieve remote code execution, this code path can potentially be exploited for such attacks and would require more research.

The vulnerable code resides here – (PacManager.java, lines 120-127):

private static String get(Uri pacUri) throws IOException {
  URL url = new URL(pacUri.toString());
  URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
  return new String(Streams.readFully(urlConnection.getInputStream()));
}

Specifically, the affected code is using Streams.readFully to read the entire file into memory without any kind of checks on how big the file actually is.

Because this attack require a user to configure a PAC file, and an attacker to be present and know about that file, and the file needs to be served without SSL to make the attack work, the possibility of an attacker pulling this off is low. This is also true because Android, unlike other operating systems does not support the WPAD protocol to retrieve PAC files automatically which can be exploited using a rouge access point or network.

Steps To Replicate (on Ubuntu 16.04)

1. Install NGINX:

sudo apt-get install nginx

2. Use fallocate to create a large PAC file in “/var/www/html/”

sudo fallocate -s 2.5G test.pac

3. Go in to advanced network settings on the Android device and add the following URL as the PAC URL: http://192.168.1.x/test.pac

Save the settings which will trigger the bug. Once the phone starts downloading the files, the screen will go black and it will reboot.

Mitigation Steps

Users should apply the November 2016 Android bulletin.

Bounty Information

This bug has fulfilled the requirements for Google’s Android Security Rewards and a bounty has been paid.

References

Android security bulletin: November 2016
CVE-ID: CVE-2016-6723
Google: Android bug # 215709 / AndroidID-30100884
Netscape PAC file format definition: here (via the Internet Archive)
WPAD Internet Draft: here
WPAD not supported on Android: see bug report here

Credits

Bug discovered by, and advisory written by Yakov Shafranovich.

Timeline

2016-07-11: Android bug report filed with Google
2016-07-19: Android bug confirmed as high
2016-08-18: Bug priority downgraded to moderate
2016-09-15: Coordination with Google on public disclosure
2016-11-07: Android security bulletin released with fix
2016-11-07: Public disclosure

Advisory: Crashing Android devices with large Assisted-GPS Data Files [CVE-2016-5348]

Summary

Android devices can be crashed remotely forcing a halt and then a soft reboot by a MITM attacker manipulating assisted GPS/GNSS data provided by Qualcomm. This issue affects the open source code in AOSP and proprietary code in a Java XTRA downloader provided by Qualcomm.

The Android issue was fixed by in the October 2016 Android bulletin. Additional patches have been issued by Qualcomm to the proprietary client in September of 2016.

This issue may also affect other platforms that use Qualcomm GPS chipsets and consume these files but that has not been tested by us, and requires further research.

Background – GPS and gpsOneXtra

Most mobile devices today include ability to locate themselves on the Earth’s surface by using the Global Positioning System (GPS), a system originally developed and currently maintained by the US military. Similar systems developed and maintained by other countries exist as well including Russia’s GLONASS, Europe’s Galileo, and China’s Beidou.

The GPS signals include an almanac which lists orbit and status information for each of the satellites in the GPS constellation. This allows the receivers to acquire the satellites quicker since the receiver would not need to search blindly for the location of each satellite. Similar functionality exists for other GNSS systems.

In order to solve the problem of almanac acquisition, Qualcomm developed the gpsOneXtra system in 2007 (also known as IZat XTRA Assistance since 2013). This system provides ability to GPS receivers to download the almanac data over the Internet from Qualcomm-operated servers. The format of these XTRA files is proprietary but seems to contain current satellite location data plus estimated locations for the next 7 days, as well as additional information to improve signal acquisition. Most Qualcomm mobile chipsets and GPS chips include support for this technology. A related Qualcomm technology called IZat adds ability to use WiFi and cellular networks for locations in addition to GPS.

Additional diagram of the system as described in Qualcomm’s informational booklet:

gps

Background – Android and gpsOneXtra Data Files

During our network monitoring of traffic originating from an Android test device, we discovered that the device makes periodic calls to the Qualcomm servers to retrieve gpsOneXtra assistance files. These requests were performed almost every time the device connected to a WiFi network. As discovered by our research and confirmed by the Android source code, the following URLs were used:

http://xtra1.gpsonextra.net/xtra.bin
http://xtra2.gpsonextra.net/xtra.bin
http://xtra3.gpsonextra.net/xtra.bin

http://xtrapath1.izatcloud.net/xtra2.bin
http://xtrapath2.izatcloud.net/xtra2.bin
http://xtrapath3.izatcloud.net/xtra2.bin

WHOIS record show that both domains – gpsonextra.net and izatcloud.net are owned by Qualcomm. Further inspection of those URLs indicate that both domains are being hosted and served from Amazon’s Cloudfront CDN service (with the exception of xtra1.gpsonextra.net which is being served directly by Qualcomm).

On the Android platform, our inspection of the Android source code shows that the file is requested by an OS-level Java process (GpsXtraDownloader.java), which passes the data to a C++ JNI class (com_android_server_location_GnssLocationProvider.cpp), which then injects the files into the Qualcomm modem or firmware. We have not inspected other platforms in detail, but suspect that a similar process is used.

Our testing was performed on Android v6.0, patch level of January 2016, on a Motorola Moto G (2nd gen) GSM phone, and confirmed on a Nexus 6P running Android v6.01, with May 2016 security patches.

Qualcomm has additionally performed testing on their proprietary Java XTRA downloader client confirming this vulnerability.

Vulnerability Details

Android platform downloads XTRA data files automatically when connecting to a new network. This originates from a Java class (GpsXtraDownloader.java), which then passes the file to a C++/JNI class (com_android_server_location_GnssLocationProvider.cpp) and then injects it into the Qualcomm modem.

diagram

The vulnerability is that both the Java and the C++ code do not check how large the data file actually is. If a file is served that is larger than the memory available on the device, this results in all memory being exhausted and the phone halting and then soft rebooting. The soft reboot was sufficient to recover from the crash and no data was lost. While we have not been able to achieve remote code execution in either the Qualcomm modem or in the Android OS, this code path can potentially be exploited for such attacks and would require more research.

To attack, an MITM attacker located anywhere on the network between the phone being attacked and Qualcomm’s servers can initiate this attack by intercepting the legitimate requests from the phone, and substituting their own, larger files. Because the default Chrome browser on Android reveals the model and build of the phone (as we have written about earlier), it would be possible to derive the maximum memory size from that information and deliver the appropriately sized attack file. Possible attackers can be hostile hotspots, hacked routers, or anywhere along the backbone. This is somewhat mitigated by the fact that the attack file would need to be as large as the memory on the phone.

The vulnerable code resides here – (GpsXtraDownloader.java, lines 120-127):

connection.connect();

int statusCode = connection.getResponseCode();

if (statusCode != HttpURLConnection.HTTP_OK) {

if (DEBUG) Log.d(TAG, “HTTP error downloading gps XTRA: “

+ statusCode);

return null;

}

return Streams.readFully(connection.getInputStream());

Specifically, the affected code is using Streams.readFully to read the entire file into memory without any kind of checks on how big the file actually is.

Additional vulnerable code is also in the C++ layer – (com_android_server_location_GnssLocationProvider.cpp, lines 856-858):

jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);

sGpsXtraInterface->inject_xtra_data((char *)bytes, length);

env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);

Once again, no size checking is done.

We were able to consistently crash several different Android phones via a local WiFi network with the following error message:

java.lang.OutOfMemoryError: Failed to allocate a 478173740 byte allocation with 16777216 free bytes and 252MB until OOM
at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201)
at libcore.io.Streams.readFullyNoClose(Streams.java:109)
at libcore.io.Streams.readFully(Streams.java:95)
at com.android.server.location.GpsXtraDownloader.doDownload(GpsXtraDownloader.java:124)
at com.android.server.location.GpsXtraDownloader.downloadXtraData(GpsXtraDownloader.java:90)
at com.android.server.location.GpsLocationProvider$10.run(GpsLocationProvider.java:882)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)

(It should be noted that we were not able to consistently and reliable achieve a crash in the C++/JNI layer or the Qualcomm modem itself)

Steps To Replicate (on Ubuntu 16.04)

1. Install DNSMASQ:

sudo apt-get install dnsmasq

2. Install NGINX:

sudo apt-get install nginx

3. Modify the /etc/hosts file to add the following entries to map to the IP of the local computer (varies by vendor of the phone):

192.168.1.x xtra1.gpsonextra.net
192.168.1.x xtra2.gpsonextra.net
192.168.1.x xtra3.gpsonextra.net
192.168.1.x xtrapath1.izatcloud.net
192.168.1.x xtrapath2.izatcloud.net
192.168.1.x xtrapath3.izatcloud.net

4. Configure /etc/dnsmasq.conf file to listed on the IP:

listen-address=192.168.1.x

5. Restart DNSMASQ:

sudo /etc/init.d/dnsmasq restart

6. Use fallocate to create the bin files in “/var/www/html/”

sudo fallocate -s 2.5G xtra.bin
sudo fallocate -s 2.5G xtra2.bin
sudo fallocate -s 2.5G xtra3.bin

7. Modify the settings on the Android test phone to static, set DNS to point to “192.168.1.x”. AT THIS POINT – Android will resolve DNS against the local computer, and serve the GPS files from it.

To trigger the GPS download, disable WiFi and enable Wifi, or enable/disable Airplane mode. Once the phone starts downloading the files, the screen will go black and it will reboot.

PLEASE NOTE: on some models, the XTRA file is cached and not retrieved on every network connect. For those models, you may need to reboot the phone and/or follow the injection commands as described here. You can also use an app like GPS Status and ToolboxGPS Status and Toolbox.

The fix would be to check for file sizes in both Java and native C++ code.

Mitigation Steps

For the Android platform, users should apply the October 2016 Android security bulletin and any patches provided by Qualcomm. Please note that as per Qualcomm, the patches for this bug only include fixes to the Android Open Source Project (AOSP) and the Qualcomm Java XTRA downloader clients.

Apple and Microsoft have indicated to us via email that GPS-capable devices manufactured by them including iPad, iPhones, etc. and Microsoft Surface and Windows Phone devices are not affected by this bug.

Blackberry devices powered by Android are affected but the Blackberry 10 platform is not affected by this bug.

For other platforms, vendors should follow guidance provided by Qualcomm directly via an OEM bulletin.

Bounty Information

This bug has fulfilled the requirements for Google’s Android Security Rewards and a bounty has been paid.

References

Android security bulletin: October 2016
CERT/CC tracking: VR-179
CVE-ID: CVE-2016-5348
GNSS sample almanacs: here
Google: Android bug # 213747 / AndroidID-29555864; Android patch here
gpsOneXTRA information booklet: archived version here

CVE Information

As provided by Qualcomm:

CVE: CVE-2016-5348
Access Vector: Network
Security Risk: High
Vulnerability: CWE-400: Uncontrolled Resource Consumption (‘Resource Exhaustion’)
Description: When downloading a very large assistance data file, the client may crash due to out of memory error.
Change summary:

  1. check download size ContentLength before downloading data
  2. catch OOM exception

Credits

We would like to thank CERT/CC for helping to coordinate this process, and all of the vendors involved for helpful comments and a quick turnaround. This bug was discovered by Yakov Shafranovich, and the advisory was also written by Yakov Shafranovich.

Timeline

2016–06-20: Android bug report filed with Google
2016-06-21: Android bug confirmed
2016-06-21: Bug also reported to Qualcomm and CERT.
2016-09-14: Coordination with Qualcomm on public disclosure
2016-09-15: Coordination with Google on public disclosure
2016-10-03: Android security bulletin released with fix
2016-10-04: Public disclosure

Advisory: Insecure transmission of data in Android applications developed with Adobe AIR [CVE-2016-6936]

Summary

Android applications developed with Adobe AIR send data back to Adobe servers without HTTPS while running. This can allow an attacker to compromise the privacy of the applications’ users. This has been fixed in Adobe AIR SDK release v23.0.0.257.

Details

Adobe AIR is a developer product which allows the same application code to be compiled and run across multiple desktop and mobile platforms. While monitoring network traffic during testing of several Android applications we observed network traffic over HTTP without the use of SSL going to several Adobe servers including the following:

  • airdownload2.adobe.com
  • mobiledl.adobe.com

Because encryption is not used, this would allow a network-level attacker to observe the traffic and compromise the privacy of the applications’ users.

This affects applications compiled with the Adobe AIR SDK versions 22.0.0.153 and earlier.

Vendor Response

Adobe has released a fix for this issue on September 13th, 2016 in Adobe AIR SDK v23.0.0.257. Developers should update and rebuild their application using the latest SDK.

References

Adobe Security Bulletin: ASPB16-31
CVE: CVE-2016-6936

Credits

Bug discovered and advisory written by Yakov Shafranovich.

Timeline

2016-06-15: Report submitted to Adobe’s HackerOne program
2016-06-16: Report out of scope for this program, directed to Adobe’s PSIRT
2016-06-16: Submitted via email to Adobe’s PSIRT
2016-06-17: Reply received from PSIRT and a ticket number is assigned
2016-09-09: Response received from the vendor that the fix will be released next week
2016-09-13: Fix released
2016-09-14: Public disclosure

Advisory: Intel Crosswalk SSL Prompt Issue [CVE 2016-5672]

Summary

The Intel Crosswalk Project library for cross-platform mobile development did not properly handle SSL errors. This behaviour could subject applications developed using this library to SSL MITM attacks.

Vulnerability Details

The Crosswalk Project, created by Intel’s Open Source Technology Center, allows mobile developers to use HTML, CSS and Javascript to develop and deploy mobile apps across multiple platforms from the same codebase. The library packages the HTML assets provided by the developer and runs them inside a WebView on the device. The library also bridges some of the common APIs and services from the Javascript code in the WebView to the underlying platform. The project supports deployment to iOS, Windows Phone and Android. It is implemented in multiple apps, some of which can be found here.

For the Android implementation of CrossWalk – when an invalid or self-signed SSL certificate is used during communication with the server, the underlying library displays a prompt to the user asking them to grant permission or deny permission to this certificate. If the user allows the certificate, that choice is remembered going forward and from that point in, all subsequent requests with invalid SSL certificates are accepted by the application, and are not rechecked. This applies even to connections over different WiFi hotspots and different certificates. This may allow a network-level attacker to mount MITM attack using invalid SSL certificate and capture sensitive data.

screenshot_crosswalk
Example of error dialog

The fix changes the behaviour to generate a programmatic error message not visible to the user  about an invalid SSL certificate. This issue has been fixed in the following versions of Crosswalk and all users of the library are encouraged to upgrade:

  • 19.49.514.5 (stable)
  • 20.50.533.11 (beta)
  • 21.51.546.0 (beta)
  • 22.51.549.0 (canary)

This issue was originally discovered while testing a third-party Android app using this library.

References

CERT/CC tracking: VR-180
CERT/CC vulnerability note: VU#217871
Crosswalk bug report: XWALK-6986
Crosswalk security advisory: see here
CVE ID: CVE-2016-5672
Intel blog: see post here

Credits

Thank you to CERT/CC for coordination on this issue, and to the Intel Open Source Technology Center for the fix. Bug discovered and advisory written by Yakov Shafranovich.

Timeline

2016-05-25: Reported issue to the Intel PSIRT, got an automated reply
2016-05-30: Reached out to CERT/CC for help reaching Intel
2016-06-01: Request from CERT/CC for more details, provided details via secure form
2016-06-15: Response from CERT/CC that Intel is planning a fix within 45 days
2016-06-23: Direct contact from Intel
2016-07-01: Asking CERT/CC to reserve a CVE, CERT/CC assigns a CVE
2016-07-22: Intel fix is finished and ready for testing
2016-07-25: We confirm the fix and coordinate disclosure dates
2016-07-29: Coordinated public disclosure

Research: Crashing Browsers Remotely via Insecure Search Suggestions

Summary

Intercepting insecure search suggestion requests from browsers, and returning very large responses leads to browser crashes (but not RCE). Affected browsers are FireFox on the desktop and Android, and Chrome on desktop and Android – other Chromium and FireFox derived browsers maybe affected. Internet Explorer and Safari are not affected. The issue is exploitable remotely, albeit not easily.

Background – Search Suggestions

Most browsers, desktop and mobile, support a feature which allows users to type either in the address bar or the search box and see a list of “search suggestions”. These are similar to the search suggestions provided by most search engines within their homepages and search bars. Examples of search suggestions in the browser and search engine webpage appear below:

The protocol that underlies this mechanism is OpenSearch Suggestions Extensions, a JSON protocol running over HTTP (as defined here). This protocol allows browsers and other applications to send simple keyword queries to the search engine servers which return JSON responses translated by the browser into results in the search bar. It should be noted that some search engines define their own APIs instead of OpenSearch, which browsers then implement.

Search engines can also publish OpenSearch description documents (as defined here) and embed those in their webpages, which browsers can automatically discover and use. The discovery of new search engines happens automatically in some browsers when the user visits a particular site (Chrome and IE Edge [SSL only]), or triggered manually by the user via an icon in the search bar (FireFox). FireFox and Internet Explorer (prior to Edge) also support plugins and APIs for doing this as well.

An example of an open search description document defining the suggestion protocol from AOL Search (original from here) – note the bolded part that defines the search suggestion protocol:

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
                       xmlns:moz="http://www.mozilla.org/2006/browser/search/">
    <ShortName>AOL Search</ShortName>
    <Description>The AOL Search engine delivers great search results so
    you can search less and discover more.</Description>
    <Language>en-us</Language>
    <InputEncoding>UTF-8</InputEncoding>
    <Image width="16" height="16" type="image/x-icon">http://search.aol.com/favicon.ico</Image>
    <Url type="text/html" method="get" template="http://search.aol.com/aol/search?q={searchTerms}&amp;s_it=opensearch"/>
    <Url type="application/x-suggestions+json" template="http://autocomplete.search.aol.com/autocomplete/get?output=json&amp;it=opensearch&amp;q={searchTerms}"/>
    <moz:SearchForm>http://search.aol.com/aol/webhome</moz:SearchForm>
</OpenSearchDescription>

Background – Search Engines and HTTPS

Even in the the post-Snowden era, many popular search engines still do not support encryption (HTTPS). Other search engines may support HTTPS but also still support non-HTTPS connections and do not redirect users automatically to HTTPS. Because browser vendors tend to include the most popular search engines in specific countries by default, they end up including multiple search engines which are not using HTTPS. This also applies to the search suggestions endpoints used by browsers.

Some examples (for English locale, US only):

  • Android AOSP stock browser (source)
    • Bing (non-SSL version)
    • Yahoo (non-SSL version)
  • Chrome (desktop and Android) (source)
    • AOL Search (does not support SSL)
    • Ask.com (does not support SSL)
  • FireFox (desktop only) (source)
    • Ebay (does not support SSL)

Exploit Details

Because browsers include multiple non-HTTPS search engines with insecure search suggestions endpoints, it would be possible for an attacker on the network level to intercept the traffic flowing between the browser and the search engine endpoints, and substitute their own. If a very large response is returned (2+ GBs), the browser can run out of memory and crash. This is due to the fact that browsers do not check for sizes in the search suggestions responses. Obviously, this is more of an issue for mobile devices which have lower memory than desktops.

For Android AOSP browser and Chromium, this issue appear to be directly tied to the processing code of search engine responses. For FireFox, this is a more generic issue around large XMLHTTPRequest responses, which is what the browser is using internally for search suggestions. Our bug reports with the vendors provide more details on which code is causing this. This re-enforces the fact network traffic SHOULD NEVER be trusted.

The following crashes were observed – we have not been able to cause an RCE or a buffer overflow:

  • Android AOSP stock browser on Android (v4.4) – application crashes
  • Chrome v51 on Android (v6.01) – application crashes
  • Chrome v51 on desktop Linux (Ubuntu v16.04) – the entire computer freezes requires a reboot (this maybe to due to swapping being disabled with an SSD drive)
  • FireFox v47 on desktop Linux (Ubuntu v16.04) and Android (v6.01) – application crashes

Safari v9.1 and Internet Explorer 11 and Edge appear not to be are not affected, although a similar bug has happened before with Safari. We did not test prior versions of either Safari or IE. We also did not test any other browsers derived from Chromium or FireFox.

The practical exploitation of this issue is mitigated by several factors:

  • The attacker must have control over DNS and the network traffic of the victim machine. This is most likely in cases of a rogue WiFi hotspot or a hacked router.
  • Most browsers have a rather short timeout for search engine suggestions response, not allowing sufficient time for the large response packet to be transferred over network
  • Due to the very large response size needed to trigger this issue, it is only exploitable over broadband or local networks such as rogue WiFi hotspot

Vendor Responses

Google response re: Android AOSP browser:

The team reviewed this issue and don’t believe there is a security vulnerability here. It seems the worse things that can happen is the browser crashes due to resource exhaustion. The phone is still usable so there isn’t a denial of service.

Google response re: Chromium:

We don’t consider DoS to be a security vulnerability. See the Chrome Security FAQ:

https://www.chromium.org/Home/chromium-security/security-faq#TOC-Are-denial-of-service-issues-considered-security-bugs-

Mozilla / FireFox response has been to remove the security restriction on this bug, therefore indicating that this is not a security issue.

Steps to Replicate

(This is for Chrome but is similar for other browsers)

1. Install DNSMASQ and NGINX:
sudo apt-get install dnsmasq nginx
2. Modify the /etc/hosts file to add the following entries to map to the IP of the local computer (varies by vendor of the phone):
192.168.1.x ss.ask.com
3. Configure /etc/dnsmasq.conf file to listen on the IP:
listen-address=192.168.1.x
4. Restart DNSMASQ:
sudo /etc/init.d/dnsmasq restart
5. Use fallocate to create a file in “/var/www/html/”
sudo fallocate -l 5G query
6. Modify DNS settings on the test machine or the same machine to point to “192.168.1.x”. If same machine, modify resolve.conf as follows:
nameserver 192.168.1.x
7. Start Chrome, go to settings and choose “Ask.com” as the default search provider.
8. Open new tab and try to type something in the omnibox.

References

Android bug reports: 214784 and 214785
Chromium bug reports: 624779 and 624794 (patch accepted)
FireFox bug reports: 1283675 and 1283672
OpenSearch description document: doc here
OpenSearch Suggestions extension v1.1: doc here
Safari Search Suggestions bug: see ArsTechnica story here

Credits

Researched and written by Yakov Shafranovich.

Timeline

2016-06-30: Bug filed with Android
2016-06-30: Bug filed with Chromium
2016-06-30: Bug filed Mozilla/FireFox
2016-06-30: Response from Chromium, Won’t Fix
2016-07-12: Response from Android, not a security issue
2016-07-13: Android team is ok with disclosure
2016-07-14: Mozilla removes security restrictions on the bug
2016-07-26: Public disclosure

Research: Securing Android Applications from Screen Capture (FLAG_SECURE)


Summary — TL, DR

Apps on Android and some platform services are able to capture other apps’s screens by using MediaProjection API. Because of the way this API implements “securing” sensitive screens, there exist some possible security issues. The best way to secure your Android app is to use FLAG_SECURE on sensitive screens and DO NOT use the virtual keyboard (here is why).

MediaProjection API

Since Android 5.0, there exists a new MediaProjection API that allows apps to record videos and take screenshots of screens belonging to other apps. The API is described as follows:

Android 5.0 lets you add screen capturing and screen sharing capabilities to your app with the new android.media.projection APIs. This functionality is useful, for example, if you want to enable screen sharing in a video conferencing app. The new createVirtualDisplay() method allows your app to capture the contents of the main screen (the default display) into a Surface object, which your app can then send across the network. The API only allows capturing non-secure screen content, and not system audio. To begin screen capturing, your app must first request the user’s permission by launching a screen capture dialog using an Intent obtained through the createScreenCaptureIntent() method.

(On Android versions prior to 5, there are other methods such as undocumented APIs, and ADB, we are focusing on Android 5+)

This API also drives several other functions in the OS:

All of these functions as well as the MediaProjection API can take screenshots and videos of other apps. For apps to use the API, special permission is required, for platform features, no special permission is needed. Additionally, any applications signed by the system key (Google apps) can use this API without permission as well.

A good open source example of an application that uses the API can be found here:

https://github.com/JakeWharton/Telecine

Secure and non-secure content

As mentioned in the Google docs above, “the API only allows capturing non-secure screen content”. What exactly is “secure” and “non-secure” content?

This refers to a special flag which can be applied to views in Android, called FLAG_SECURE. It is described in Android docs as follows:

Treat the content of the window as secure, preventing it from appearing in screenshots or from being viewed on non-secure displays

Setting this flag on Android view will prevent screenshots from being taken manually, and any other app or platform service will show a black screen. This functionality is not global for the entire app, but can be set on specific screens which can be more sensitive, and not set on others. There is no other way or permission that can mark an entire app or any part of it from being excepted from screen capture or recording.

NOTE: Even on views marked with FLAG_SECURE, the virtual keyboard is ALWAYS visible. This is due to a known Android bug which Google has so far refused to fix:

https://code.google.com/p/android/issues/detail?id=129285

How screen capture really works in Android

The term “secure” as used in this context does not mean that the content of the app cannot be captured, rather that it cannot be “viewed on non-secure displays”. This is because screen capture and the concept of secure / non-secure isn’t what developers may think it is.

Behind the scenes, this API and related platform services use the concept of Casting (similar to AirPlay). Apps that capture screenshots and record videos, must create a virtual display to which then the device content is cast to. The FLAG_SECURE flag is also not used for security but rather means copyrighted content in context of DRM and displays — i.e. secure content would be something like a DVD, and a secure display would be an HDTV.

This is clear on the device itself — when an app begins to record the screen, the cast icon is turned on in the notification bar. This is also clear from the Android source code and this doc:

Display flag: Indicates that the display has a secure video output and supports compositing secure surfaces. If this flag is set then the display device has a secure video output and is capable of showing secure surfaces. It may also be capable of showing protected buffers. If this flag is not set then the display device may not have a secure video output; the user may see a blank region on the screen instead of the contents of secure surfaces or protected buffers.

That would means that an Android device casting to a DRM-protected display like a TV would always display sensitive screens, since the concept of secure really means “copyrighted”. For apps, Google forestalled this issue by preventing apps not signed by the system key from creating virtual “secure” displays, but not for physical devices. There is also an existing Android bug asking for the concept of DRM and screen security to be separated into different flags:

https://code.google.com/p/android/issues/detail?id=93026

Security issues with the current API

First of all, a basic foundation of mobile app security is a clear separation between apps. One Android app is should never able to read the preferences, data or capture cloud notifications of another app. This paradigm breaks down in case of screen capture/recording. An app gaining access to the MediaProjection API or any of the platform services using it, is able to capture screen output from other apps including PIN numbers, passwords, credit card numbers, etc.

Second, by using a flag used for marking copyrighted content, it would make it easier to subvert the system. Some ways this can be subverted include:

  • Gaining permissions to create a virtual display marked as secure would show all secure content. Right now this is preventable by using the system key, but a rooted phone or some other way that fools the system into creating such display would by pass this protection.
  • Also, casting to a physical secure display, or perhaps a wireless one, would also display content

Third, even with the FLAG_SECURE in use, some parts of the screen can still be captured. The virtual keyboard is one existing example, but there may be others (perhaps notifications?).

[ADDED 06/24/2016: Mark Murphy from CommonsWare points out several other issues with FLAG_SECURE child objects – see his blog post here]

Fourth, there is no clear indication to the user they are being recorded other than the cast icon. Clicking on the icon shows no devices since virtual devices aren’t going to be listed. A better warning may be needed.

A better solution as suggested in this bug report, would be to define a separate flag and never allow any app or system service to see its output under any reason, and also to blank out the entire screen even if other apps or service display anything on it. An even better solution would be to make this opt-in for apps, instead of opt-out.

Attack vectors

There are several possible avenues of attack which would result in an app being installed on a user’s phone recording their app activity. These include:

  • Malicious apps in the app store that masquerade as legit casting apps requiring record permission — since users don’t know that casting apps can also record their screen
  • Remote install via compromised desktop as described in this paper
  • Overlaying permission screens as described here

To record even non-secure screens, the following can be tried but they are not practically feasible:

  • On rooted phones, creating a virtual display marked as “secure”
  • Fooling the system into thinking that a given app is a system app, allowing it to create secure displays

All of these would result in an app sitting on the phone and recording user activity. However, other than the last two methods, FLAG_SECURE views would not be recordable, although the virtual keyboard is. The only indicator to the user would be the cast icon, but when they click on it, no devices would be listed.

[ADDED 2020-03-23: As per this excellent blog post from Yanick Fratantonio, FLAG_SECURE will NOT protect against attacks using accessibility services (a11y)]

Attacks in the Wild

Some examples of these type of attacks happening in the wild:

  • July 2018 – Panoptispy Study – see here, here, here and here
  • July 2018 – Anubis Android malware – see here and here

Conclusion — Protect Your Apps

To protect your apps from being recorded by other apps, FLAG_SECURE should be used on any views containing sensitive data. Additionally, since the virtual keyboard is also vulnerable, it is recommended that these screens either use a custom keyboard, or if feasible to use an on-screen custom layout (for numeric input like PIN numbers).

We have surveyed many of the top apps in the Google Play store, and many of them including some Google-owned apps do not use FLAG_SECURE or if they do, do not secure the keyboard.

We also hope that Google would lock down this API and solve the issues highlighted in this article.

Credits

Researched and written by Yakov Shafranovich.

References

Google CID: 3–5606000008769

Advisory: Arro and Other Android Taxi Hailing Apps Did Not Use SSL

Overview

Arro and possibly over 100 other Android taxi hailing apps did not SSL to secure communications between the application and its servers.

Background

Arro is a taxi hailing service allowing users to hail yellow taxis in New York from their smartphones. The service also allows users to pay for their ride via the application while they are in a taxi. The underlying technology is a white branded version of an application called Taxi Hail, made by a company called Mobile Knowledge, in Ottawa, Canada, a subsidiary of Creative Mobile Technologies, LLC (CMT) of New York, NY. Both are providers of technology solutions for the taxi industry. At least 100 other white branded taxi applications run on the same platform as Arro, with a link to a non-exhaustive list appearing later in this document.

Details

While monitoring network traffic from an Android smartphone, we observed that most communications between the Arro Android application and servers was unencrypted and did not use SSL. Instead, regular HTTP calls were being used. Further investigation showed that the underlying application and servers were a white branded version of TaxiHail, developed by Mobile Knowledge.

Information observed included:

  • Username and passwords for the users of the application
  • User profile including address and phone number
  • Credentials for various APIs and payment gateways used by the application
  • Latitude and longitude of the user requesting a taxi
  • Last four digits and expiration date of the user’s credit cards on file
  • When adding a new credit card — full credit card information

Payments were made via a separate gateway that uses SSL and were not at risk. However, adding credit cards would be done without SSL.

A secondary minor issue was also discovered:

The GoArro app created a text log on the SD Card of the device being tested. This log, located in “/TaxiHail/errorlog.txt” contained GPS locations for the user, which would accessible to applications on the same phone without location access. This issue has also been fixed.

References

Arro website: https://www.goarro.com/
CERT/CC ID: VU# 439016
CMT website: http://creativemobiletech.com/
List of white branded apps: https://play.google.com/store/search?q=com.apcurium.MK&c=apps&hl=en
TaxiHail website: http://www.mobile-knowledge.com/products/passenger-solutions/taxihail/

Credits

This has been originally discovered and written by Yakov Shafranovich via collaboration with Shaftek Enterprises Security Research Team. Thank you to Garret Wasserman of CERT/CC for helping to communicate with the vendors.

Timeline

2015–10–14: Arro notified
2015–10–14: Initial vendor response
2015–10–15: Followup communications to Arro, no response
2015–10–20: CERT/CC notified
2015–10–23: CERT/CC response
2015–11–06: Mobile Knowledge acknowledged the problem via CERT/CC
2015–11–30: Fix deployed by vendor
2015–12–01: Fix confirmed
2015–12–08: Public disclosure, coordinated with CERT/CC

Research: Chrome For Android Reveals Phone Model and Build

[UPDATED: 2018-12-25 – we published an expanded post with fix information]

Overview

Google’s Chrome browser for Android tends to disclose information that can be used to identify the hardware of the device it is running on. This problem is further exacerbated by the fact that many applications on Android use Chrome WebView or Chrome Custom Tabs to render web content.

Background — Chrome and Headers

The Chrome browser for Android is provided by Google as the build-in browser in the Android operating system for mobile devices. It is based on the Chromium open source project. It also provides the WebView and Custom Tabs APIs for other applications running on the Android platform, to be used for rendering web content within the apps themselves without opening a separate browser window.

As all browsers, Chrome sends a variety of headers as part of every request to the web servers it communicates with. These headers are defined in the HTTP protocol, latest standard of which can be found in RFCs 7230, 7231, 7232, 7233, 7234 and 7235. Among these is the User-Agent header which is the subject of this post.

The “User-Agent” header in HTTP is defined by RFC 7231, section 5.5.3 as follows:

The “User-Agent” header field contains information about the user agent originating the request, which is often used by servers to help identify the scope of reported interoperability problems, to work around or tailor responses to avoid particular user agent limitations, and for analytics regarding browser or operating system use.

Background — Android Model and Build ID

Android devices have a build-in MODEL and BUILD ID, identifying the phone model and Android build. They are defined in in android.os.Build.MODEL and android.os.Build.ID properties. These are further defined in the Android Compatibility Definition document (section 3.2.2) as follows:

MODEL — A value chosen by the device implementer containing the name of the device as known to the end user. This SHOULD be the same name under which the device is marketed and sold to end users. There are no requirements on the specific form

ID — An identifier chosen by the device implementer to refer to a specific release, in human-readable format. This field can be the same as android.os.Build.VERSION.INCREMENTAL, but SHOULD be a value sufficiently meaningful for end users to distinguish between software builds. The value of this field MUST be encodable as 7-bit ASCII and match the regular expression “^[a-zA-Z0–9._-]+$”.

An attempt to map models to more descriptive names can be found on GitHub. A list of known build IDs for Nexus devices can be found here and here.

Details

As per Chrome docs, the Chrome for Android User Agent string includes the Android version number and build tag information. This information by default is also sent when applications use Android’s WebView and Chrome Custom Tabs APIs to serve web content in their own applications. While Android does offer ability to override these (via WebSettings.setUserAgent() in WebView), most applications choose not to do that to assure compatibility by relying on the default header.

Aggravating this issue is that the user agent header is sent always, with both HTTP and HTTPS requests, often by processes running in background. Also, unlike the desktop Chrome, on Android no extensions or overrides are possible to change the header other than the “Request Desktop Site” option on the browser itself for the current session.

For example of a user-agent header for Chrome Beta, on Nexus 6, with Android v5.1.1:

Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.34 Mobile Safari/537.36

When a user chooses the “Request Desktop Site” option, the user agent header sent is a generic Linux header instead. Here is an example for Chrome Beta, on Nexus 6, with Android v5.1.1:

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.34 Safari/537.36

The difference is that on mobile mode, the following string is extra:

Android 5.1.1; Nexus 6 Build/LYZ28K

The fact that it identifies the operating system and its version is not unique. This follows generally what many other browsers have been doing on desktop and mobile. It is the build tag that is the problem. As described above, the build tag identifies both the device name and its firmware build. For many devices, this can be used to identify not only the device itself, but also the carrier on which it is running and from that the country.

An example can be easily seen from the above where build LYZ28K can be easily identified as Nexus 6 running on T-Mobile, implying a US presence. It would also be trivial to use the build information to figure out the carrier based on which carriers are known to be at what build number. Build numbers are easily obtainable from manufacturer and phone carrier websites

Bug # 494452 has been filed for this against Chromium before, but Google has choose to keep the design of the user agent string intact.

Possible Mitigation by Android Applications Using WebView

As discussed above, application authors can use WebSettings.setUserAgent() method to set the override the user agent. While many are reluctant to do so in order to lose compatibility, we would like to suggest the following approach of using the default user agent and erasing the build information in it.

Conclusion

Even the NSA described that user agents only identify browsers. Unfortunately, on Android they can also identify the device model, carrier and more. In our opinion, this is simply too much information as it reveals the underlying firmware. While user fingerprinting exists, it is less trivial to tie a specific piece of software to a specific piece of hardware with the granularity of carrier, build and country. An analogy to this would be a desktop browser sending the vendor name and the build number of the BIOS in a desktop computer. Additionally, this information can be used to target users with malware attacks targeting specific builds known to be vulnerable.

We suggest following the approach taken by Mozilla:

Adding a device identifier to the Firefox OS User Agent (UA) string is STRONGLY DISCOURAGED by Mozilla.

and:

Mozilla strives to provide greater privacy for users. Therefore, we have been working to reduce the level of “fingerprintability” of different browser configurations — that is to say, how uniquely identifiable a particular user’s browser is to sites through detection methods of which the user is unaware. (i.e. server-side methods) Adding e.g. hardware information to the UA reduces privacy by increasing fingerprintability.

Credits

Researched and written by Yakov Shafranovich.