This post is part of a series:
- Inside SafetyNet part 1 (Oct 2015)
- Inside SafetyNet part 2 (Feb 2016)
- Inside SafetyNet part 3 (Nov 2016)
- How to implement Attestation securely using server-side checks (my blog, Cigital blog)
- SafetyNet Playground (POC server-side implementation) Play Store - Android source - PHP source
It’s been six months since my last blog post on Android’s SafetyNet. I was then examining a mid-July 2015 version of the system. As expected, there have been updates since then; the last was released mid-December 2015. I’ll briefly describe the differences in this post; for a more complete overview of the checks inside the SafetyNet system and its usage please read through my previous posts.
SafetyNet changes
A few but important new modules have been added in recent versions and some older ones were restructured.
Dalvik Cache module
This module attempts to find modified dalvik cache files. As is known, dex code inside an APK gets optimised during installation and is kept in a separate folder in “odex” files [on old Android versions that still use Dalvik]. Malicious actors could modify these optimized files directly instead of modifying APKs, in order to evade detection.
The module monitors /data/dalvik-cache/arm
or /data/dalvik-cache
and maintains the results, comparing the hashes of odexed files with their stored versions.
LOG DEVICE STATE module
This module retrieves a few system properties from android.os.SystemProperties
and sends them back:
ro.boot.verifiedbootstate
ro.boot.veritymode
ro.build.version.security_patch
ro.oem_unlock_supported
ro.boot.flash.locked
LOG SYSTEM PARTITION FILES module
This module has been previously discussed. A new submodule has been now been added, named SystemIntegrityChecker
(SIC). This attempts to remotely verify the state of the /system
partition; an interesting concept from many aspects.
SIC retrieves the SHA256 hash oof the /system
entry from SafetyNet’s data store. It then performs a HTTPS request to a SIC server containing the hash and some meta-information about the directory. The response will contain a hashMatches
integer flag. SafetyNet will use this flag and report through the appropriate SafetyNet APIs.
As far as I can tell the SIC system is not yet in use. I am not sure why a request to a separate SIC server needs to happen; the only reasonable explanation seems to be that entities other than Google might need to maintain their own SIC servers, e.g. device manufacturers. Still, the whole process could possibly happen through backend APIs instead. In any case, someone is going to have to maintain a list of hashes of the system partitions of various devices/configurations or the “last seen hash” for each user, so that changes are detected. We’ll know soon enough I guess.
How is the /system
hash created?
SafetyNet runs an process that recursively walks “/system” and calculates a HashTree over its contents.
For every file it encounters it captures meta-information (timestamps, permissions, selinux context etc) and its SHA256 hash into a local data store. For every directory, it generates a hash that considers the store entry of every file inside the directory. If there are hash mismatches between previous and current recursive walks over /system
, the offending files are entered in separate lists to be audited.
The LOG SYSTEM PARTITION FILES module continues to include the results of the SystemPartitionFileFinder
sub-module.
As a reminder, this module retrieves the status of various files in /system
. The list of “files of interest” is configured over the air. Currently, the following files are checked, along with 5 random files:
/system/app/providerdown.apk,
/system/priv-app/cameraupdate.apk,
/system/app/cameraupdate.apk,
/system/priv-app/ThemeManags.apk,
/system/app/HTMLViewer.apk,
/system/app/com.android.hardware.ext0.apk,
/system/app/com.android.wp.net.log.apk,
/system/app/com.google.fk.json.slo.apk,
/system/app/com.google.model.mi.apk,
/system/app/SettingProvider.apk,
/system/app/SecurityCertificate.apk,
/system/app/LiveWallpaper.apk,
/system/app/BatteryControl.apk,
/system/app/Models.apk,
/system/bin/.daemon,
/system/bin/.daemon/mis,
/system/bin/.daemon/nis,
/system/bin/daemonnis,
/system/bin/nis,
/system/bin/.sr/nis,
/system/bin/.sr,
/system/bin/.memnut,
/system/bin/.suv,
/system/bin/.sc/mis,
/system/bin/uis,
/system/usr/.suv,
/system/xbin/.memnut,
/system/xbin/.suv,
/system/xbin/ku.sud,
/system/xbin/.rt_daemon,
/system/xbin/.rt_bridge,
/system/xbin/.monkey.base,
/system/xbin/.ext.base,
/system/xbin/.like.base,
/system/xbin/.look.base,
/system/xbin/.must.base,
/system/xbin/.team.base,
/system/xbin/.type.base,
/system/xbin/.view.base,
/system/xbin/.word.base,
/system/xbin/.zip.base,
/system/xbin/.bat.base,
/system/xbin/com.android.wp.net.log,
/system/xbin/.b,
/system/xbin/.df,
/system/xbin/.c,
/system/xbin/.sys.apk,
/system/xbin/.ld.js,
/system/xbin/.ls
SafetyNet modules
Here is an up-to-date list of all SafetyNet logging modules. My previous blog post describes most of these.
LOG_APPS_TAG = "apps";
LOG_ATTESTATION_TAG = "attest";
LOG_CAPTIVE_PORTAL_TEST_TAG = "captive_portal_test";
LOG_DALVIK_CACHE_TAG = "dalvik_cache_monitor";
LOG_DEVICE_ADMIN_TAG = "device_admin_deactivator";
LOG_DEVICE_STATE_TAG = "device_state";
LOG_EVENT_LOG_TAG = "event_log";
LOG_FILES_TAG = "su_files";
LOG_GMSCORE_INFO_TAG = "gmscore";
LOG_GOOGLE_PAGE_INFO_TAG = "google_page_info";
LOG_GOOGLE_PAGE_TAG = "google_page";
LOG_HANDSHAKE_TAG = "ssl_handshake";
LOG_LOCALE_TAG = "locale";
LOG_LOGCAT_TAG = "logcat";
LOG_MX_RECORDS_TAG = "mx_record";
LOG_PACKAGES_TAG = "default_packages";
LOG_PROXY_TAG = "proxy";
LOG_REDIRECT_TAG = "ssl_redirect";
LOG_SD_CARD_TAG = "sd_card_test";
LOG_SELINUX_TAG = "selinux_status";
LOG_SETTINGS_TAG = "settings";
LOG_SETUID_TAG = "setuid_files";
LOG_SSLV3_TAG = "sslv3_fallback";
LOG_SUSPICIOUS_PAGE_TAG = "suspicious_google_page";
LOG_SYSTEM_CA_CERT_STORE_TAG = "system_ca_cert_store";
LOG_SYSTEM_PARTITION_FILES_TAG = "system_partition_files";
Extras
SafetyNet is not just about the modules described here. During the attestation process some other checks happen via different systems; for example there is code that acts as old-fashioned root-detection, trying to figure out if the following files/directories exist in the filesystem (or if traces of them appear in device logs).
I do hope that the output of the rest of the SafetyNet modules is also taken into account during the calculation the ctsCompatibility response.
"/system/bin/su"
"/system/xbin/su"
"/system/bin/.su"
"/system/xbin/.su"
"/system/xbin"
"/system/bin"
"/system/sd/xbin"
"/system/bin/failsafe"
"/data/local"
"/system"
"/system/bin/.ext"
"/data/local/xbin"
"/data/local/bin"
Over-the-air configuration
As mentioned above, SafetyNet is configured by Google at runtime; even though the code itself is also updated once every three months on average.
The following are some of the more interesting configuration options:
Signal Tags Whitelist - Idle Mode
This configures which modules are used by the SafetyNet “idle mode” logger.
n: "snet_idle_tags_whitelist"
v: "system_partition_files,
system_ca_cert_store,
setuid_files,
dalvik_cache_monitor,
logcat,
event_log,
device_state"
Signal Tags Whitelist - Normal Mode
This configures which modules are used by the SafetyNet “normal mode” logger.
n: "snet_tags_whitelist"
v: "default_packages,
su_files,
settings,
locale,
ssl_redirect,
ssl_handshake,
sslv3_fallback,
proxy,
selinux_status,
sd_card_test,
google_page_info,
captive_portal_test,
gmscore,
logcat,
event_log"
Event Log Tags
This is used by the Event Logger
module. The SafetyNet service is configured to retrieve and log the following event tags:
n: "snet_report_event_logs"
v: "50125:2,
50128:2,
conscrypt:3,
78001:2,
65537:2,
90201:2,
90202:2,
70151:2"
The tags correspond to /system/etc/event-log-tags
:
- 50125:2
- SMS denied by user
exp_det_sms_denied_by_user (app_signature|3)
- 50128:2
- SMS denied by user
exp_det_sms_sent_by_user (app_signature|3)
- conscrypt:3
- unexpected (early) ChangeCipherSpec message
- 78001:2
- FrameworkListener dispatchCommand overflow
exp_det_dispatchCommand_overflow
- 65537:2
- FrameworkListener dispatchCommand overflow
exp_det_netlink_failure (uid|1)
- 90201:2
- log whether user accepted and activated device admin
exp_det_device_admin_activated_by_user (app_signature|3)
- 90202:2
- log whether user declined activation of device admin
exp_det_device_admin_declined_by_user (app_signature|3)
- log whether user declined activation of device admin
- 70151:2
exp_det_attempt_to_call_object_getclass (app_signature|3)
SIC Server URL
n: "snet_sic_server_url"
v: ""
This is currently empty, but will eventually be the server URL for the “System Integrity Checker” service described above.
DroidGuard
These posts are aimed primarily at providing some clarity over the SafetyNet system to developers who wish to adopt attestation APIs in their applications. It must be noted that attestation is just a small aspect of the SafetyNet system; the main use is to retrieve data so that Google can monitor the security of the Android ecosystem and track on-going incidents.
As I’ve hinted in my previous post, while performing this investigation I stumbled upon DroidGuard
, a set of components that communicates with remote Google Play APIs and is used for fraud detection, anti-abuse and operations like DRM.
SafetyNet interacts, along with many other components, with DroidGuard. Although these two systems may co-operate for some checks, DroidGuard is an independent system that serves different purposes, more inline with Google’s anti-malware efforts. I will not be revealing details about this system; as I think that such details would only benefit malware authors, not application developers that want to keep their Android apps protected. Similarly, revealing details on ‘how to bypass SafetyNet’ is not the goal here. Such details are shared directly with Google and enterprise developers interested in assessing the system before using it.
Improving SafetyNet
Here’s a bucket list of things I’d like to see in SafetyNet and some thoughts.
- SafetyNet is not a root detection system although it goes a long way towards that goal. It suffers from some early symptoms of more traditional on-device checking systems: It’s designed for large scale data gathering and does not adequately protect itself against targeted attacks. It will tell Google that X% of devices are tampered, but, for now, it will stop short of trying to actively resist tampering by malware that specifically wants to present a false image to the checkers. Of course this is an ultimately futile effort, but the bar can be raised.
- I’d like to see at least some degree of code protection for the checkers.
- It’d be great if checks were performed using a range of high-level and low-level APIs.
- I’d also be good if more SafetyNet checkers influence the compatibility decision; more than the straightforward su binary tests.
- How much the compatibility decision is influenced by historical data about a device is an open question. Moving away from point-in-time checks could be a worthwhile goal.
- Some clarity around the SIC server system would be nice to have.
- Making use of trustzone
- Multi-platform support for the Attestation APIs would be interesting to see (iOS attestation…)