[NOTE: This is an expanded version of an earlier post from 2015 with updated information and fix from the vendor. Full blog post here: https://wwws.nightwatchcybersecurity.com/2018/12/25/chrome-browser-for-android-reveals-hardware-information/]
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 - https://source.android.com/compatibility/cdd) 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 (https://github.com/meetup/android-device-names). Software build information easily maps to the security patch levels for many devices as seen on this Google page [https://developers.google.com/android/ota] (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 [https://wwws.nightwatchcybersecurity.com/2016/11/30/speaking-at-bsidesphilly-this-friday/] Original blog post from 2015: see here [https://wwws.nightwatchcybersecurity.com/2015/09/30/research-chrome-for-android-reveals-phone-model-and-build/] 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 _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: http://seclists.org/fulldisclosure/