Upcoming Advisory for Apache Tomcat Vulnerability – CVE-2019-0221

We will be releasing an advisory on a security vulnerability that was reported to the Apache Software Foundation, specifically in Apache Tomcat. This issue is being tracked under CVE-2019-0221. The issue was discovered by Nightwatch Cybersecurity Research and reported to Apache via the EU FOSSA-2 project, hosted by Intrigri.

Related links:

  • Apache advisory – here
  • CVE entry – here
  • Tomcat security pages – v7, v8 and v9

Finding Unlisted Public Bounty and Vulnerability Disclosure Programs with Google Dorks

Introduction

Bug bounty/vulnerability disclosure platforms are used by companies to coordinate the reporting, triaging and in some case, rewarding,  of security vulnerabilities. In many platforms the various programs are not always public – some may be public, some maybe unlisted but public, some may be private and some may be invite-only. In this post we outline how we found a set of public programs that were not listed on the platform site but were findable via Google searches.

Embedded Forms

While most platforms host the program information, policies and submission pages on their own sites, their customers may occasionally want to embed or host a particular program on the site owned by the customer or one that is agnostic, not the platform. For these uses cases, some platforms have an embedding feature which allows customers to embed a submission form for vulnerabilities within the customer owned website or host it via a website that doesn’t appear to be connected to the platform vendor. Here is documentation for some of the platforms:

The problem is that if a company ends up embedding a form, it will get indexed by Google and can be found via a Google search. The trick is to look for something unique in the text of the form. Here is for example a vulnerability reporting form for Walmart, provided by BugCrowd – as you can see it says “Powered by BugCrowd”

Screen Shot 2019-05-02 at 7.40.02 PM

If you check the BugCrowd public list of programs, WalMart will not be listed:

Screen Shot 2019-05-02 at 9.10.49 PM

However, it may appear on the list such as the one from Disclose.IO:

Screen Shot 2019-05-04 at 11.48.15 PM.png

Google Dorking Other BugCrowd Embedded Forms

Now if you put the text from the form into Google as follows, you can find a bunch of other ones as well:

"powered by bugcrowd" -site:bugcrowd.com

These do not appear in the BugCrowd public list, and many of them are not in the Disclose.IO list. Example:

Screen Shot 2019-05-02 at 9.08.36 PM

What About HackerOne?

For HackerOne, a blog post shows an example of a form which looks very similar to a standard one.

Screen Shot 2019-05-02 at 9.19.01 PM

We tried Googling for the following query got no results:

"powered by hackerone" "submit vulnerability report"

Eventually, we just Google for the following and got many unrelated results:

"submit vulnerability report"

Among those, we were able to find a single embedded form from HackerOne for a non-public program. Because HackerOne uses an image for their “Powered By” message, it is probably harder to find or maybe not that many programs use the HackerOne forms yet 🙂 [Based on some additional feedback it looks like HackerOne forms are generated dynamically and may not be indexable by Google, see Lyft as an example]

Screen Shot 2019-05-02 at 9.21.34 PM

Screen Shot 2019-05-02 at 9.23.10 PM

Screen Shot 2019-05-02 at 9.24.50 PM

What About Synack?

While Synack doesn’t operate any public programs, they do offer a managed disclosure process which is hosted by “responsibledisclosure.com”. A simple Google Search against that site shows a bunch of programs (these are listed in Disclose.io):

site:responsibledisclosure.com

Screen Shot 2019-05-02 at 9.34.33 PM.png

Other Platforms?

We haven’t explored other platforms but feel free to do so yourself 🙂

Responses from the Platforms

This issue was reported to the three platforms listed above, here are their responses:

BugCrowd:

“We don’t guarantee that all public programs are listed directly on Bugcrowd.com – a number of companies leverage our Embedded Submission Form to host a Bugcrowd submission form (like you’re finding via these searches) directly on their own sites. Even though these programs aren’t directly advertised on our Programs page, they’re not meant to be considered private/secret. It’s up to the companies choosing to use this form to decide how and where they display it.

Nothing is being “leaked,” as any companies who do choose to run private programs that include an intake via our Embedded Submission Form understand what they’re doing: The Embedded Submission Form integration enables you to host a submission form from your own website rather than through Bugcrowd. This integration provides a streamlined workflow so that researchers can easily submit vulnerability reports directly to you, while allowing you to continue to manage and track submissions through Crowdcontrol.

You can manage and track submissions through Crowdcontrol for private and public programs. These are companies choosing to host our ESF on public/indexed pages, so the fact that they’re not listed at https://bugcrowd.com/programs is exactly what you’d expect.”

HackerOne:

“This feature is not intended to be private but to help ease programs’ engagement with the larger hacker community. We do caution programs, prior to setting up the feature, to understand that their program will no longer be private if the form is exposed in a public way. Beyond that, the program benefits from our normal private experience, and we do not include other call outs or invitations to the programs on HackerOne unless explicitly requested.

Some companies, like Punchh, use this feature to allow researchers to submit reports to their vulnerability disclosure program via their own website.”

Synack:

“Although we do not advertise our Responsible Disclosure programs, they are publicly accessible and not considered to be private information”

Timeline

2019-02-20: Reported to Synack and rejected
2019-02-22: Reported to BugCrowd and rejected
2019-05-02: Draft blog post shared with HackerOne, Synack and BugCrowd
2019-05-03: Comments received from platform vendors
2019-05-04: Blog post published

Remote Code Execution (RCE) in CGI Servlet – Apache Tomcat on Windows – CVE-2019-0232

Summary

Apache Tomcat has a vulnerability in the CGI Servlet which can be exploited to achieve remote code execution (RCE). This is only exploitable when running on Windows in a non-default configuration in conjunction with batch files.

The vendor released a fix in Tomcat versions 7.0.94, 8.5.40 and 9.0.19. Users are encouraged to upgrade as soon as possible. CVE-2019-0232 has been assigned to track this issue.

Vulnerability Details

Common Gateway Interface (CGI) is a standard protocol to allow web servers to execute command line programs / scripts via web requests. This protocol also allows passing of command line arguments to the script or program being executed via URL parameters. The protocol itself is defined in RFC 3875.

The following CGI request:

  • http://localhost:8080/cgi/test.bat?&dir

converts to:

  • test.bat &dir

Apache Tomcat supports execution of CGI scripts / programs in a non-default configuration via a special CGI servlet. This servlet also parses URL parameters and translates them into command line arguments. The actual execution of the CGI scripts happens via Java Runtime Environment (JRE)’s java.lang.Runtime class, exec() function.

When CGI support is enabled in Apache Tomcat in Windows, and command line argument passing is enabled, it is possible to cause command injection via parameter interpolation when calling a batch file (*.bat / *.cmd). This happens because “cmd.exe” performs interpolation on some special characters before execution which can cause other shell commands to be called. Neither Apache Tomcat or the Windows JRE perform any kind of input validation for these special characters. A partial list of these characters can be found here and here. Additional information about why this issue is specific to the Windows JRE can be found in this blog post by Markus Wulftange.

Steps To Replicate

1. Install a Java Runtime Environment (JRE) in Windows.

2. Download a vulnerable version of Tomcat and extract.

3. Modify the conf\context.xml file on line 19, to enable privileged context:

<Context privileged="true">

4. Modify conf\web.xml to enable the CGI Servlet by removing the comments around line 387 as follows and adding the following parameters (enableCmdLineArguments is only needed for Tomcat 9):

<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
  <param-name>cgiPathPrefix</param-name>
  <param-value>WEB-INF/cgi</param-value>
</init-param>
<init-param>
  <param-name>executable</param-name>
  <param-value></param-value>
</init-param>
<init-param>
  <param-name>enableCmdLineArguments</param-name>
  <param-value>true</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>

5. Enable the CGI servlet by removing comments around this – you also need to change the URL pattern to match the one in the previous step (“cgi”):

<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi/*</url-pattern>
</servlet-mapping>

6. Create a folder for the CGI files:

mkdir webapps\ROOT\WEB-INF\cgi

7. Place the following text into a batch file located in “webapps\ROOT\WEB-INF\cgi\test.bat”

@echo off
echo Content-Type: text/plain
echo.
echo Hello, World!

8. Run Tomcat via the following command:

cd bin
catalina run

9. Trigger the following URLs and observe the dir command being run:

http://localhost:8080/cgi/test.bat?&dir

s1

Additional Notes – Environment Variables and Path

By default, Tomcat doesn’t pass all of the environment variables from the parent process that runs Tomcat itself. That means that if you run “set”, you will not see any environment variables other than those set by Tomcat itself. This also means that you would need to spell out the directory path of the command you are trying to run. However, if the “passShellEnvironment” parameter is set to true, the variables from the parent process will be passed through and you can call any command in PATH as well as view those variables. If the command cannot be found, there will be a error in the console log “XXXX is not recognized as an internal or external command”.

Example of trying to run a command without a full directory including the Tomcat console logs:

s5 s6

Examples of running with the parameter being set or spelling out the directory path:

s8s9.PNG

Example of trying to view the environment variables without and with the passShellEnvironment parameter being set to “true”:

s3

s2.PNG

Additional Notes – Memory Leaks / Denial of Service

If the command being executed is a long running command, it maybe possible to cause a denial of service or a memory leak. This happens because Tomcat waits for the OS process to complete.

Here is an example of netstat being triggered:

screen4

screen3

Additional Notes – Other Commands and STDERR

The “executable” parameter indicates which executable should be used to run the script. By default, this is set to “perl” with the expectation that the files being executed are Perl scripts. If this is set to empty, then it is possible to execute batch files since those are executed by “cmd.exe”. HOWEVER, it seems that the command interpolation only happens with batch files – if this is set to real program, then command interpolation doesn’t necessary occur and this vulnerability may be not exploitable.

Also, if the command being triggered outputs to STDERR instead of STDOUT, that output doesn’t get piped back to the web request – instead it goes to the Tomcat console log.

Here is an example when “java.exe” is set as the executable parameter and produces output to STDERR:

b3

Vendor Response

This issue was responsibly reported to the vendor via the EU FOSSA bounty program operated by Intigriti. Vendor analysis indicated that the core cause for this issue has to do with the way the Java Runtime Environment (JRE) interprets command arguments in Windows specifically and doesn’t impact Apache Tomcat when used with other operating systems. The vendor assigned CVE-2019-0232 to track this issue and provided a fix.

The vendor fix consists of two parts:

  • Disabling command line arguments from being passed to the CGI servlet in the default configuration (“enableCmdLineArguments” set to “false“) for Tomcat 7 and 8  – this was already disabled by default in Tomcat 9.
  • Adding a new configuration parameter (“cmdLineArgumentsDecoded“) to the default CGI configuration that will be used for input validation if passing of command line arguments is enabled and will be set to the following regular expression (OS specific). Note that if the user changes this parameter, they may become vulnerable again.
    • Windows - [[a-zA-Z0-9\Q-_.\\/:\E]+]
    • Other operating systems - [.*]

Affected Versions and Mitigation

Apache Tomcat is only vulnerable to this issue if the following conditions are met:

  • Running on Windows
  • CGI support is enabled either via the web.xml for a specific web application or the server as whole (see documentation). This is disabled by default.
  • The “privileged” setting is set to “true” in the Context element. This is “false” by default.
  • Tomcat 9 onlyenableCmdLineArguments is set to “true” (enabled by default in Tomcat 7 and 8)
  • The “executable” parameter is empty, and the the CGI scripts being executed are batch files (either .bat or .cmd). It is not clear if other commands that use “cmd.exe” are vulnerable as well.

The vendor indicated that the following versions are vulnerable (no information is available on earlier versions):

  • Tomcat 9 – versions 9.0.0.M1 through 9.0.17 (9.0.18 is not affected)
  • Tomcat 8 – versions 8.5.0 to 8.5.39
  • Tomcat 7 – versions 7.0.0 to 7.0.93

Users are encouraged to upgrade to the following fixed versions or later:

IMPORTANT NOTE: even when running a fixed version, you SHOULD NOT change the “cmdLineArgumentsDecoded” configuration parameter to a different value. If you do, your installation may become vulnerable. If an upgrade is not possible, users can apply one of the following mitigations:

  • Disable CGI support (it is disabled by default)
  • Or set the “enableCmdLineArguments” parameter to “false“. This setting will disable command line arguments from being passed via the CGI servlet.

Bounty Information

This report satisfied the requirement of the EU FOSSA bounty program and a bounty has been paid.

References

Blog post on JRE behavior: see here (Markus Wulftange)
CGI Standard: RFC 3875
CVE-ID: CVE-2019-0232
CVSS v2.0 Score: 9.3 – (AV:N/AC:M/Au:N/C:C/I:C/A:C)
CVSS v3.0 Score: 8.1 – (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H)
Tomcat CGI Servlet source code: see GitHub
Vendor advisory: see here

Credits

Text of the advisory written by Yakov Shafranovich.

Timeline

2019-02-14: Initial report submitted to the platform
2019-02-17: Initial report validated by the platform
2019-03-03: Report acknowledged by the vendor
2019-03-14: Interim evaluation received from the vendor
2019-03-22: Communication with the vendor
2019-04-10: Public advisory issued by the vendor
2019-04-30: Public disclosure by reporter

Upcoming Advisory for Apache Tomcat Vulnerability – CVE-2019-0232

We will be releasing an advisory on a security vulnerability that was reported to the Apache Software Foundation, specifically in Apache Tomcat. This issue is being tracked under CVE-2019-0232. The issue was discovered by Nightwatch Cybersecurity Research and reported to Apache via the EU FOSSA-2 project, hosted by Intrigri.

UPDATE: The advisory has been published here.

Related links:

  • Apache advisory – here
  • CVE entry – here

Content Injection in Amazon Kindle’s FireOS [CVE-2019-7399]

Summary

The FireOS operating system provided by Amazon for Fire tablet devices can be injected with malicious content by an MITM attacker. An attacker can also capture the serial number of the device. The root cause is lack of HTTPS for legal content (terms of use and privacy policy) within the settings section.

The issue was discovered in FireOS v5.3.6.3 and fixed by the vendor in v5.3.6.4 that was released in November 2018. Devices will automatically update to the latest version. CVE-2019-7399 has been assigned by MITRE to track this issue.

Vulnerability Details

FireOS is an operating system provided by Amazon for the Fire tablet devices.  It is a customized fork of Android. While monitoring network traffic on a test device, we observed that several calls from the settings section (terms of use and privacy policy) are done without HTTPS and can be injected with malicious content by an MITM attacker. It is also possible for the attacker to observe this traffic and capture the serial number (DSN) of the device.

Screenshots of the captured traffic:

Screenshot_2018-09-03-13-11-20 Screenshot_2018-09-03-13-11-26

Steps To Replicate (on Ubuntu 18.04)

1. Install the application on the Android device but do not start it.

2. Install dnsmasq and NGINX on the Linux host:

sudo apt-get install dnsmasq nginx

3. Modify the /etc/hosts file to add the following entry to map the domain name to the Linux host:

192.168.1.x www.kindle.com
192.168.1.x kindle.com

4. Configure /etc/dnsmasq.conf file to listen on the IP and restart DNSMASQ

listen-address=192.168.1.x
sudo /etc/init.d/dnsmasq restart

5. Add a file with malicious content (you may need to use sudo):

cd /var/www/html
mkdir support
echo powned >support/privacy
echo powned >support/terms

6. Modify the settings on the Kindle device to static, set DNS to point to “192.168.1.x”. AT THIS POINT – the Kindle device will resolve DNS against the Linux computer and serve the large servers file

7. Tap “Settings”, “Legal and Compliance”, and tap either “Terms of Use” or “Privacy”. Observe injected content.

Vendor Response and Mitigation

The issue was discovered in FireOS v5.3.6.3 and fixed by the vendor in v5.3.6.4 that was released in November 2018. Devices will automatically update to the latest version. MITRE assigned CVE-2019-7399 to track this issue.

References

Amazon tracking # PO135449968
CVE-ID: CVE-2019-7399

Credits

Text of the advisory written by Yakov Shafranovich.

Timeline

2018-09-03: Initial report to the vendor
2018-09-04: Report triaged and being reviewed by the vendor
2018-09-17: Communication from the vendor, issue still being reviewed
2019-01-10: Fix confirmed, communication regarding disclosure
2019-01-30: Vendor pinged about CVE assignment
2019-02-03: Draft advisory sent for review
2019-02-04: CVE issued by MITRE
2019-02-07: Public disclosure; minor syntax updates

Chrome Browser for Android Reveals Sensitive Hardware Information (partial fix available)

[NOTE: This is an expanded version of an earlier post from 2015 with updated information and fix from the vendor]

Summary

Google’s Chrome browser, WebView and Chrome Tabs for Android discloses information about the hardware model, firmware version and security patch level of the device on which it is running.  This also affects any Android applications that are using Chrome to render web content.

This information can be used for track users and fingerprint devices. It can also be used to determine which vulnerabilities a particular device is vulnerable to in order to target exploits.

While the vendor (Google) rejected the initial bug report in 2015, they had issued a partial fix in October 2018 for Chrome v70. The fix hides the firmware information while retaining the hardware model identifier. All prior versions are believed to be affected. Users are encouraged to upgrade to version 70 or later. Since this fix doesn’t apply to WebView usage, app developers should manually override the User Agent configuration in their apps.

Both the vendor and MITRE refused to issue a CVE number to track this issue since they do not consider it to be security related.

Background — Chrome and Headers

The Chrome browser for Android is provided by Google as the default 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. Software build information easily maps to the security patch levels for many devices as seen on this Google page (based on date).

Vulnerability 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. It can also be used to determine which security patch level is on the device and which vulnerabilities the device is vulnerable to.

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 such as this one.

Replication Instructions

To replicate this issue or to check if your device is affected, you can visit any website that shows the user agent headers being sent by your browser such as or you can type “view user agent” in Google search. Alternatively, you can use JavaScript as follows on a site like JsFiddle:

document.write(navigator.userAgent)

Vendor Response and Mitigation

Bug # 494452 has been filed for this bug in 2015 against Chromium, and was rejected by the vendor as “WAI” – “Working As Intended”. However, in 2018, a new bug # 860229 was filed by the vendor along with a feature request, and this was partially fixed in October 2018 in Chrome v70 for Android by removing the firmware build information from the header. The device model number remains.

The fix only applies to the Chrome application itself, and not to the WebView implementation used by application developers as per the following explanation:

Does not apply the change to Android Web View as mandated by the Android Compatibility Definition Document.

Users are encouraged to update to Chrome v70 or later to fix this issue. Application authors should 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 and model information in it.

Both the vendor and MITRE refused to issue a CVE number to track this issue since they do not consider it to be security related.

References

Chromium bugs: 494452 and 860229
Chromium feature request # 4558585463832576
Our talk about abusing this: originally given at BSides Philly 2016 – see here
Original blog post from 2015: see here

Credits

This advisory was written by Yakov Shafranovich.

Timeline

2015-05-31: Initial report submitted to the vendor
2017-06-03: Bug rejected by the vendor as “WAI” – “Working As Intended”
2015-09-30: Initial public disclosure published
2016-12-06: Public talk at BSides Philly
2018-07-04: New Chromium bug filed directly by the vendor
2018-08-10: Fix merged for Chrome
2018-10-29: Fixed version released
2018-12-25: Updated disclosure published

Wickr Me for Android Allowed Screen Capture

Wickr offers a suite of applications which provide secure instant messaging, voice and audio calls. The Android version of Wickr Me Messenger allowed screenshots to be taken by other apps on the device because FLAG_SECURE option wasn’t used.

To replicate, try the following:

  1. Open the application.
  2. Press Power + Volume Down at any sensitive screen and observe a screenshot being taken.

The underlying reason is because the app is not using “FLAG_SECURE” for such screens (more information on FLAG_SECURE can be found in our earlier blog post). By contrast, many Android apps with higher security requirements use it.

Vendor Response and Mitigation

This issue was reported in May 2016 against version 2.6.4.1, and was fixed in September 2018 in version 4.55.1. A bounty has been paid.

References:

  • Google Play Link to the app – see here
  • Our earlier blogpost about FLAG_SECURE on Android – see here

 

Sensitive Data Exposure via RSSI Broadcasts in Android OS [CVE-2018-9581]

[NOTE: This bug is part of a series of three related Android bugs with the same root cause: CVE-2018-9489, CVE-2018-9581 and CVE-2018-15835. A presentation covering all three bugs was given at BSides DE in the fall of 2018.]

Summary

System broadcasts by the Android operating system expose WiFi signal strength information (RSSI). Any application on the device can capture this information without additional permissions. Rogue applications can potentially use this information for indoor positioning in order to locate or track users within a small area near the WiFi router. Same issue also applies to the underlying Android API, although an additional permission is required.

All versions of Android are believed to be affected. The vendor (Google) has not yet fixed this issue, however on Android 9 / P one of the two broadcast types is no longer revealing sensitive data (as part of the fix for CVE-2018-9489). The vendor assigned CVE-2018-9581 to track this issue. Further research is also recommended to see whether this is being exploited in the wild.

Background

Android is an open source operating system developed by Google for mobile phones and tablets. It is estimated that over two billion devices exist worldwide running Android. Applications on Android are usually segregated by the OS from each other and the OS itself. However, interaction between processes and/or the OS is still possible via several mechanisms.

In particular, Android provides the use of “Intents” as one of the ways for inter-process communication. A broadcast using an “Intent” allows an application or the OS to send a message system-wide which can be listened to by other applications. While functionality exists to restrict who is allowed to read such messages, application developers often neglect to implement these restrictions properly or mask sensitive data. This leads to a common vulnerability within Android applications where a malicious application running on the same device can spy on and capture messages being broadcast by other applications.

Another security mechanism present in the Android is permissions. These are safeguards designed to protect the privacy of users. Applications must explicitly request access to certain information or features via a special “uses-permission” tag in the application manifest (“AndroidManifest.xml”). Depending on the type of permission (“normal”, “dangerous”, etc”) the OS may display the permission information to the user during installation, or may prompt again during run-time. Some permissions can only be used by system applications and cannot be used by regular developers.

Screenshots of application permissions in Google Play and at run-time:

pic3 pic4 pic6

Vulnerability Details

The Android OS broadcasts the WiFi strength value (RSSI) system-wide on a regular basis. No special permission is needed to access this information. The RSSI values represent the relative strength of the signal being received by the device (higher = stronger) but are not directly correlated to the actual physical signal strength (dBm). This is exposed via two separate intents (“android.net.wifi.STATE_CHANGE” prior to Android 9; and “android.net.wifi.RSSI_CHANGED” in all versions of Android).

While applications can also access this information via the WifiManager, this normall requires the “ACCESS_WIFI_STATE” permission in the application manifest. For the WiFi RTT feature that is new to Android 9 and is used for similar geolocation, the “ACCESS_FINE_LOCATION” is required. But, when listening for system broadcasts, no such permissions are required allowing applications to capture this information without the knowledge of the user.

There are two separate security issues present:

  1. RSSI values are available via broadcasts, bypassing the permission check normally required (“ACCESS_WIFI_STATE”).
  2. RSSI values, via broadcasts or WifiManager can be used for indoor position without the special location permission.

Steps to Replicate by Regular Users

For Android device users, you can replicate these issues as follows:

  1. Install the “Internal Broadcasts Monitor” application developed by Vilius Kraujutis from Google Play.
  2.  Open the application and tap “Start” to monitor broadcasts.
  3.  Observe system broadcasts, specifically “android.net.wifi.STATE_CHANGE” (prior to Android 9) and “android.net.wifi.RSSI_CHANGED” (all versions).

Screenshot example:

screen1

Steps to Replicate by Developers via Code

To replicate this in code, create a Broadcast receiver and register it to receive the actions “android.net.wifi.STATE_CHANGE” (Android version v8.1 and below only) and “android.net.wifi.RSSI_CHANGED”.

Sample code appears below:

public class MainActivity extends Activity {
@Override
public void onCreate(Bundle state) {
    IntentFilter filter = new IntentFilter();        
    filter.addAction(android.net.wifi.STATE_CHANGE);
    filter.addAction(android.net.wifi.RSSI_CHANGED);
    registerReceiver(receiver, filter);
}
    
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
    Log.d(intent.toString());
    ….
}
};

Testing Methodology

Our test used the following devices:

  • Pixel 2, running Android 8.1.0, patch level July 2018

  • Nexus 6P, running Android 8.1.0, patch level July 2018

  • Moto G4, running Android 7.0, patch level April 2018

  • Kindle Fire HD (8 gen), running Fire OS 5.6.10, which is forked from Android 5.1.1, updated April 2018

  • Router used was ASUS RT-N56U running the latest firmware

(We included the Kindle Fire to show that forks of Android inherit this functionality)

The following steps were performed:

  1. Install Broadcast Monitor app.
  2. Put the phone into airplane mode.
  3. Walk into the room.
  4. Turn off airplane mode (to trigger the RSSI broadcasts).
  5. Get the RSSI values from the following broadcasts:
    1. android.net.wifi.RSSI_CHANGE – newRssi value
    2. android.net.wifi.STATE_CHANGE – networkInfo / RSSI
  6. Repeat steps 3-4 for each room.

Results of the testing cleared showed that each room had a unique range of RSSI values when using a particular device.

Range of values collected during testing:

Room #

Pixel

Nexus

Moto G4

Kindle Fire

1

39 – 43

44

39 – 42

59 – 60

2

45 – 49

49 – 56

48 – 52

45 – 46

3

42 – 44

50

51 – 53

49 – 50

4

54 – 56

60 – 63

60 – 62

66

Vendor Response and Mitigation

The vendor (Google) classified this issue as Moderate and assigned CVE-2018-9581 to track this issue. No fix is available yet, however on Android 9 / P one of the two broadcast types (“android.net.wifi.STATE_CHANGE”) is no longer revealing sensitive data (as part of the fix for CVE-2018-9489). It is unknown if this issue is being exploited in the wild.

References

Android ID # 111698366
CVE ID: CVE-2018-9581
Google Bug # 111662293
GitHub: Internal Broadcasts Monitor
Presentation given at BSides DE: see here

Credits

We want to thank Vilius Kraujutis for developing the Internal Broadcasts Monitor application and making the source code available in GitHub.

We would like to thank multiple academic researchers who have previously published research locating users via RSSI values, including the following papers:

This advisory was written by Yakov Shafranovich.

Timeline

2018-03-28: Initial report submitted to the vendor re: CVE-2018-9489
2018-07-19: Separate report created for this issue as per vendor request; testing results provided
2018-07-20: Vendor response received – issue under investigation
2018-08-09: Provided results of Android 9 testing
2018-08-14: Draft advisory provided for review
2018-08-28: Asking about disclosure
2018-09-14: Vendor response receiving, still pending
2018-09-19: Pinged vendor
2018-09-21: Vendor response receiving, issue under investigation
2018-10-14: Notified vendor about upcoming talk
2018-10-15: Vendor response receiving, issue under investigation
2018-10-25: Asking for CVE assignment
2018-10-30: Asked again about CVE assignment
2018-11-01: Asked MITRE for CVE assigment
2018-11-05: CVE assigned by the vendor, notified MITRE
2018-11-06: Slides provided for review
2018-11-09: Public disclosure during a presentation at BSides DE
2018-11-11: Advisory published

Sensitive Data Exposure via Battery Information Broadcasts in Android OS [CVE-2018-15835]

[NOTE: This bug is part of a series of three related Android bugs with the same root cause: CVE-2018-9489, CVE-2018-9581 and CVE-2018-15835. A presentation covering all three bugs was given at BSides DE in the fall of 2018.]

Summary

System broadcasts by the Android operating system expose detailed information about the battery. Prior research has demonstrated that the same charging information – when exposed via browser battery status API – can be used to uniquely identify and track users. As the result, the battery API was removed from most browsers.

On Android however, this information is made available with high precision. Furthermore, no special permission is required by any application to access this information. As the result, this can be used to uniquely identify and track users across multiple apps. This was verified via limited testing to be possible within a short period of time.

Android versions 5.0 and later are affected. The vendor (Google) does not classify this bug as a security issue and has not released any fix plans. CVE-2018-15835 has been assigned by MITRE to track this issue. Further research is also recommended to see whether this is being exploited in the wild.

Background

Android is an open source operating system developed by Google for mobile phones and tablets. It is estimated that over two billion devices exist worldwide running Android. Applications on Android are usually segregated by the OS from each other and the OS itself. However, interaction between processes and/or the OS is still possible via several mechanisms.

In particular, Android provides the use of “Intents” as one of the ways for inter-process communication. A broadcast using an “Intent” allows an application or the OS to send a message system-wide which can be listened to by other applications. While functionality exists to restrict who is allowed to read such messages, application developers often neglect to implement these restrictions properly or mask sensitive data. This leads to a common vulnerability within Android applications where a malicious application running on the same device can spy on and capture messages being broadcast by other applications.

Another security mechanism present in the Android is permissions. These are safeguards designed to protect the privacy of users. Applications must explicitly request access to certain information or features via a special “uses-permission” tag in the application manifest (“AndroidManifest.xml”). Depending on the type of permission (“normal”, “dangerous”, etc”) the OS may display the permission information to the user during installation, or may prompt again during run-time. Some permissions can only be used by system applications and cannot be used by regular developers.

Screenshots of application permissions in Google Play and at run-time:

pic3 pic4 pic6

Vulnerability Details

The Android OS broadcasts information about the battery system-wide on a regular basis including charging level, voltage and temperature. No special permission is needed to access this information. This is exposed via the “android.intent.action.BATTERY_CHANGED” intent and is only available on Android 5.0 or later. The same information is also available via Android’s BatteryManager without a special permission.

A similar capability existed in browsers via W3C’s Battery Status API. However, extensive research by Łukasz Olejnik et al. showed that this API can be used to fingerprint devices, thus leading to tracking of users. Additional research revealed this being used in the wild by multiple websites, and the API was removed from most web browsers as the result.

In our limited testing we were able to distinguish devices located behind the same NAT device within a short period of time, thus leading to session re-spawning, but we were not yet able to replicate all the prior research regarding the HTML5 battery status API. This testing was based on the uniqueness of the current battery charging counter as being different across defines.

As the result, the same privacy issues that applied in the original Battery Status API should apply for Android applications resulting in applications being able to fingerprint and track users, and re-spawn session across multiple apps on the same device. Further research is needed to see if this is being actively exploited in the wild.

Steps to Replicate by Regular Users

For Android device users, you can replicate these issues as follows:

  1. Install the “Internal Broadcasts Monitor” application developed by Vilius Kraujutis from Google Play.
  2.  Open the application and tap “Start” to monitor broadcasts.
  3.  Observe system broadcasts, specifically “android.net.wifi.STATE_CHANGE” and “android.net.wifi.p2p.THIS_DEVICE_CHANGED”.

Screenshot example:

text

Steps to Replicate by Developers via Code

To replicate this in code, create a Broadcast receiver and register it to receive the action “android.intent.action.BATTERY_CHANGE”). Sample code appears below:

public class MainActivity extends Activity {
@Override
public void onCreate(Bundle state) {
    IntentFilter filter = new IntentFilter();        
    filter.addAction(
	android.intent.action.BATTERY_CHANGE);
    registerReceiver(receiver, filter);
}
    
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
    Log.d(intent.toString());
    ….
}
};

Vendor Response and Mitigation

The vendor (Google) classified this issue as “NSBC” = “Not Security Bulletin Class” – meaning ““It was rated as not being a security vulnerability that would meet the severity bar for inclusion in an Android security bulletin.” CVE-2018-15835 was assigned by the vendor for tracking. No fix is yet available.

References

Android ID # 77286983
Android Power information: see here
CVE ID: CVE-2018-15835
Google Bug # 77236216
GitHub: Internal Broadcasts Monitor
Presentation given at BSides DE: see here

Credits

We want to thank Vilius Kraujutis for developing the Internal Broadcasts Monitor application and making the source code available in GitHub.

We would like to thank multiple academic researchers who have previously published research on the HTML5 Battery API including the following papers:

This advisory was written by Yakov Shafranovich.

Timeline

2018-03-28: Initial report submitted to the vendor
2018-03-29: Initial response from the vendor received – issue being investigated
2018-04-03: Vendor classified this as “NSBC”; follow-up communication
2018-04-04: Follow-up communication with the vendor
2018-05-02: Checking on status, response from vendor – issue still under investigation
2018-06-05: Checking status, no response from the vendor
2018-07-01: Checking status, no response from the vendor
2018-07-10: Response from vendor – issue still under investigation; pinged for a timeline
2018-07-12: Vendor still classifies this as “NSBC”; asking about disclosure
2018-08-09: Additional information sent to the vendor re: Android 9
2018-08-14: Draft advisory provided for review
2018-08-21: Vendor is looking in future improvements but the bug is still “NSBC”; communication regarding CVE assigned
2018-08-23: CVE assigned by MITRE
2018-08-28: Another draft of the advisory provided for review
2018-09-19: Pinged vendor for status
2018-10-14: Notified vendor regarding upcoming talk
2018-11-06: Slides provided for review
2018-11-09: Public disclosure during a presentation at BSides DE
2018-11-11: Advisory published

Microsoft Authenticator for Android Allows Screen Capture

Microsoft offers an application for Android called “Microsoft Authenticator” which is used to setup two-factor authentication (2FA). This application operates in two modes – one allows to generate standard OTP codes like many other apps (Google Authenticator, Authy, etc). The second mode allows a user to register with Azure’s Multi-Factor Authentication (MFA) service, and allows users to authenticate by tapping a prompt on their phone instead of entering an OTP code (similar to Google Prompt).

However, it looks like that the application still allows screenshots to be taken. This is true for setting up the OTP with a manual seed, viewing generated OTP codes, and entering a username + password when setting up Azure MFA. The implication is that if a user’s device ends up running a rogue app, that app can capture the initial OTP seed (if entered manually), the initial username and password for MFA, as well as all generated OTP codes as they are shown by the app, and thus break two factor authentication.

To replicate, try the following:

  1. Open the application.
  2. Setup a new OTP code by adding “other account” + a random seed, and view codes. Alternative, try to sign-up for MFA with a personal account.
  3. Press Power + Volume Down at any sensitive screen and observe a screenshot being taken.

The underlying reason is because the app is not using “FLAG_SECURE” for such screens (more information on FLAG_SECURE can be found in our earlier blog post). By contrast, many Android apps with higher security requirements use it.

Vendor Response

We filed a bug report with the vendor (Microsoft) and here is their response:

Our team assessed the issue, and this does not meet the bar for servicing. We have informed the product team about this issue. MSRC is closing the case.

As for CVE, since there is no fix going for this, we will not be assigning any CVE for this issue.

References:

  • Azure Multi-Factor Authentication – see docs here
  • Google Play Link to the app – see here
  • Google Prompt for Android – see here
  • MSRC Case # 46793
  • Our earlier blogpost about FLAG_SECURE on Android – see here