Software Integrity

 

Using the SafetyNet API

The SafetyNet attestation API is a Google Play Services API that any developer can use in order to gain a degree of assurance that the device their application is running on is “CTS compatible.” CTS stands for Compatibility Test Suite, which is a suite of tests a device must pass, prior to release, to be allowed to include Google Play Services. Traditionally, it was used by device manufacturers to ensure that their devices met Google’s requirements. The term is now overloaded with more meanings, like ‘the device is in a non-tampered state’ after release. Tampered state has multiple definitions and includes ‘being rooted,’ ‘being monitored’ and ‘being infected with malware’.

SafetyNet is a tamper-detection framework that is part of recent versions of Google Play Services. All Play-enabled Android devices using Android 2.3 and above already use SafetyNet as long as the Play Services package is updated. Among other things, this service informs Google about the ‘safety’ status of each device, providing indicators related to rooting, tampering, active man-in-the-attacks and others.

Learn more about the developer instructions on how to use this service.

As is evident from the instructions, there is a lot of flexibility in the ways a developer can use the service.

SafetyNet implementation

Imagine that you, as a developer, have an application that communicates with a remote web service endpoint to fetch some important data.
SafetyNet API

 

Now, imagine that you want to ensure that the device your application is running on is not rooted or tampered with in some other way. The application may choose to do client-side checks, implementing SafetyNet attest() insecurely, as in the following sequence diagram:

SafetyNet API
This basic client-only implementation flow can leave your application vulnerable to trivial hooking attacks that manipulate the attestation responses. Xposed modules bypassing this basic implementation of SafetyNet have already been published. One such attack, used in this particular Xposed module, is returning True in all calls to getBoolean for variables named ctsProfileMatch or isValidSignature. We would expect such check to exist inside the code of the mobile app so that it can validate the AttestationResult.

A more secure way to implement the SafetyNet attest() API is by utilizing a client-server architecture, as described in the following sequence diagram:
SafetyNet API
In this implementation, the WebService will get Google’s CTS compatibility response in a way that cannot be tampered with by other application running on the device. The WebService can then react appropriately based on the device state.

In order for this implementation to work, your web service needs be configured with 3 things:

  • package name of your application
  • SHA-256 hash of the APK uploaded to Google Play
  • SHA-256 signature hash of the certificate used to sign your APK

The workflow is described below.

  1. The MobileApp requests a random value from your WebService using a getNonce() API. This nonce acts like a CSRF token in normal web applications: It is used to prevent replay.
  2. The WebService generates a nonce securely (e.g. via a SecureRandom API) and returns it to MobileApp.
  3. The MobileApp performs an attest() request containing this nonce. This API is provided by the Google Play Services SDK, bundled into the application. It must be noted that ‘tampering checks’ do not necessary take place at this point; Google Play Services on the device asynchronously and continuously performs those. The attestation request is only meant to ask Google about the most recently observed CTS compatibility status.
  4. GoogleServices respond with the attestation result, which is in JSON Web Signature (JWS) format – a signed JSON object.
  5. The MobileApp performs the REST request to the WebService it intended to perform, but includes JWS AttestationResult in the request as a parameter.
  6. At this point, the WebService must first verify that the JWS object is indeed signed by GoogleServices. Ther are two ways to do this: Either manually, via comparing with Google’s public keys, or via asking GoogleServices to do it on your behalf. For this blogpost, we will pick the second method. The WebService forwards the JWS object to Google servers via an Android Device Verification API request.
  7. GoogleServices check the JWS signature
  8. GoogleService respond if the JWS signature was indeed created by Google, thus the JWS object has not been tampered with.
  9. Your WebService further validates that the payload data of the JWS object match the original compatibility check request. The AttestationResult payload is a dictionary, populated by GoogleServices, that includes at least the following: nonce, apkCertificateDigestSha256, timestamp, apkDigestSha256, apkPackageName, ctsProfileMatc
    1. Checks that the received nonce matches the last generated nonce (in case you keep session state, that would be the last nonce for the current session)
    2. Checks that the apkCertificateDigestSha256 field matches the SHA-256 hash of the certificate used to sign the APK uploaded to Play Store.
    3. Checks that the timestamp is within appropriate limits compared to when the nonce was generated
    4. Checks that the apkDigestSha256 field matches the hash of the APK
    5. Checks that the apkPackageName field matches the expected package name of the mobile app
    6. Finally, the web service checks that the ctsProfileMatch field is true.
  10. If all checks succeed, the normal response to the client app’s REST request is returned. If checks fail, one strategy would be to return an error message for that REST API. Another could be to log the error and feed it into your fraud detection systems.

Attacks on the SafetyNet service are still possible

Developers should be aware that a local attacker with root privileges will always be able to defeat ‘tamper-detection’ checks on the client side, via tampering with the data Google Service feed to the SafetyNet service.

The advantage of using SafetyNet over conventional root-detection and tamper-detection approaches seem to be that it shifts the workload of attackers as follows: When attacking conventional root-detection mechanisms, an attacker can examine how the protection mechanism’s controls are designed and disable these controls or feed them with  manipulated data in ways they know the checks will be bypassed. On the contrary, SafetyNet is implemented in such way that only the data collection part of the system can be observed; not the implementation of most checks. For example, SafetyNet has the capability to retrieve a list of all files in the filesystem. An attacker attempting to defeat the system would need to examine all gathered data and make educated guesses over what Google would consider a sign of tampering. Note that the attacker wouldn’t be able to observe what the data sent to Google from a non-rooted device looks like; so the attacker cannot simply use that data.

In practice though, it seems that the current SafetyNet implementation can be easily defeated via moving the su binary to a different location and hooking a call that reads a file with information about the selinux status of the device.

We expect that in the future, Google will implement more checks like verification of the integrity of the /system partition, turn on some checks that are not currently enabled and do a better job in data correlation.

Developers that are already using a different system of rooting or tamper detection can include SafetyNet attestation results as an additional mechanism in their existing implementation.

SafetyNet Playground sample application

Synopsys consultants created a sample application, Safety Playground, which makes use of the attestation API in the secure way described above, utilizing a client-server architecture.

SafetyNet Playground consists of an Android application and an associated web service that can be used as a sample for developers attempting to use Google’s SafetyNet attestation API securely.

This sample app will attempt to make a REST request to a sample web service. The server will return a “success” response only if the SafetyNet service attests that your device passes CTS compatibility checks.

All Android application developers can use SafetyNet in the way we demonstrate in our proof of concept code to ensure that the checks cannot be bypassed easily. Of course, with enough effort, all client-side code is by-passable by attackers with higher privileges.

Caveat: SafetyNet attestation is a Google Play service – it may not be the best approach for your application if you want your app to run on non-Google Play devices (e.g. Amazon).

References

Credits

SafetyNet research: John Kozyrakis, Technical Strategist at Synopsys.
SafetyNet Playground app and web service development: Georgi Boiko, Security Consultant at Synopsys.

 

Google Play is a trademark of Google Inc.