본문 바로가기

security_downloads

Setting up a dynamic Android testbed Part III: Inspecting and modifying local storage

728x90

In this blogpost series, we attempt to setup a dynamic Android testbed which exhibits the following features: 

  1. Inspect and modify all traffic generated by the mobile application(s) under assessment 
  2. Inspect and modify all local storage generated by the mobile application(s) under assessment 

In Part I we discussed the choice between an emulated or physical environment and compared the capabilities of various popular emulators. However, more and more mobile applications which we review are performing checks that ensure that the environment on which it runs is legitimate, or simply don't properly function in an emulated environment, which rules out emulators. In Part II various techniques to inspect and modify traffic on physical android devices were covered.

In this blogpost we describe how to perform local storage inspection and modification on physical Android devices which have a Stock ROM installed. We first discuss how to circumvent the Android Application Sandbox by rooting the device and get access to the local storage of an arbitrary mobile application. Hereafter, an approach to identify sensitive data storage by comparing file system snapshots of distinct application states is presented. Finally, some local storage vulnerabilities we often identify are briefly enumerated. 

Bypass Android Application Sandbox

The Android Application Sandbox ensures that applications cannot read the memory or private local storage of applications other than themselves. The access control is entirely based on the underlying linux operating and file system. When an application is installed, it gets assigned a unique user account which is then used to run the application (memory sandbox), hereby ensuring that the local storage written by the application is only accessible to its own user. Android Stock ROMs do not expose legitimate functionality to circumvent this local storage restriction, unlike iOS which exposes local private application storage via USB when enabled (see iFunboxiExplorer). This sandbox approach has been proven to be a reliable solution, which can only be circumvented in two ways. One approach is tomodify the application's release APK to enable debugging (section 5), after which Adb's backup function can be leveraged to access the application data. However, this requires decompiling, modifying and then recompiling an application, which could be detected or even prevented by an application or its protection layer. Therefore, we usually prefer to take the most generic approach: rooting the device. 

Rooting

The Android operating system is entirely based on linux, which has the concept of root as the god user of the system. Root is allowed to access any files or perform any privileged action, the so-called root privileges. Becoming root on devices has been researched already extensively in the past for practically every Android phone model.

Getting root on popular Android devices is not that hard. It concretely means getting the su binary with proper suid biton the device's file system, just as on any other linux distro. Usually, the rooting scenario is a variation on the following steps:

  1. Unlock device (e.g. fastboot on Google Nexus, Odin on Samsung, RSD Lite on Motorola, etc.)
  2. Flash a custom recovery mode, hereby erasing all user-specific data (e.g. Team Win Recovery Project orClockWorkMod)
  3. Boot into recovery mode and install a custom update.zip file from external storage or by sideloading, containing at least the su binary and a bash or edify script which copies it to the Android file system and sets its appropriate permissions. We prefer a 'light' update.zip which copies only the su binary and a wrapper application, such as thesuperuser.zip file of ClockWorkMod. The other popular alternative SuperSU is less interesting for our purpose since it has a bigger footprint. It moves system applications, installs a daemon and a recovery shell script on top of the usual su binary and wrapper SuperSU application (check \META-INF\com\google\android\update-binary-script). 
  4. Restore original stock recovery and lock device again

The first two steps are necessary to install the custom update.zip file in the third step. In normal Stock ROM recovery modes this update functionality is also present, but zip files must be signed with the Stock developer's private key in order to pass the signature check, which generally is not published for obvious reasons. Note that on certain Samsung models a custom update.zip file signed with the AOSP testkey is also accepted, which implies that Samsung forgot to generate their own keypair and just used the testkey from the AOSP instead, which is worrying for one of the biggest players in the Android market. We can confirm this works on several of our Samsung test devices. This is problematic in a way that it allows an attacker who stole a mobile Android phone to bypass the first and especially the second step, which would erase all user-specific data from the device as a protection measure before indirectly allowing rooting.

A quick way to verify whether the rooting was successful is to enable USB debugging, connect your android device to a PC with the Android SDK and execute command "su" in the adb shell followed with command "id" to verify whether the current UID has been changed to root - just like a normal application would do to gain root privileges dynamically:
Additionally, dedicated applications to verify root access such as Root Checker can also be utilized to verify that the superuser application actually prompts the user to allow or deny access to applications that request root privileges via the su binary:

Local storage retrieval

Now we have root, we must leverage it to get access to the local application storage. Application-specific data is located in the /system/data/packagename/ for system applications and in /data/data/packagename/ for applications installed after Stock ROM flashing. Within this folder a subset of the following subdirectories exists, depending on the application:
  • databases - SQLite databases
  • shared_prefs - for application-specific stored preferences
  • cache - for cached data
  • lib - for native libraries
  • files - for files not fitting any other category
However, some applications also do utilize the by design world-readable external storage, if available. There are a couple of ways to read the local storage of an arbitrary application, which are enumerated below.

File explorer application

One straightforward option is to use a file explorer application which has the ability to elevate its privileges to root, and thus explore the complete file system. ES File Explorer File Manager is a popular file explorer solution which supports elevating to root, but there are many others. After enabling root access and granting the application the necessary root privileges via Superuser, one can simply browse the otherwise protected /data/data/packagename/ folders and inspect the local storage, for example the local storage of the Superuser application itself:
However, when trying to open the su.sqlite file, ES File explorer doesn't know how to open the sqlite extension:
Attempting to open it with the built-in ES Note Explorer results in gibberish:
This pinpoints the main weakness of this approach: inspection and modification of local storage is dependent on the available viewers deployed on the device, which must also support elevation to root. This is not always trivial, which is why we prefer transferring the local storage files to our kali system and perform static analysis and modification there.  

ADB pull

One can also leverage the built-in adb pull and push commands to retrieve and modify private local application storage files. However, this is not completely straightforward, since adb does not elevate privileges to root by default (actually, it's the ROM's responsibility to enable this) and thus the pull command does not have permission to access the private files:
This can be resolved by changing the permissions of all files and subdirectories with a recursive chmod invocation from an elevated adb shell, after which the complete application directory can be pulled recursively and inspected with the kali sqlitebrowser client:
However, this is still not ideal from a stealth point of view, since applications can easily detect that their own files' permissions have been altered. One possibility is to write a script which enumerates the permissions of each file, then changes the permissions with the help of chmod to be readable by anyone, pull/push it via adb, and hereafter restore the original permissions again. But there is a more straightforward option.

SSH Root Server

Since Android is actually a linux system under the hood, applications have been written to deploy a full-fledged SSH server. Some of these applications support elevation to root if available, which is exactly what we need to permanently have direct access to the Android device its file system. SSHDroid is one of these applications.

Simply by granting it root access indefinitely via Superuser upon first start, connecting the Android device to a wireless access point  reachable by kali, starting the SSHDroid SSH server with a changed root password and connecting to it via kali, one can remotely access the Android file system as root:
By utilizing the sshfs utility, we can now mount the complete remote android file system as root, and thus access and modify private local storage of any application directly:

Snapshot Analysis

We now have all the tools we need to perform storage analysis and find insecure data storage vulnerabilities. However, in the case of large applications which store a significant amount of data, it can be difficult to get a grasp of how everything is structured and where the sensitive data is exactly located. This is where snapshots come into place.

By taking file system snapshots at distinct application states and comparing them via simple diffs, locating where sensitive data is saved is straightforward. Often when first launching an application, it will ask for credentials. By taking a file system snapshot before and after submitting the credentials to the application and hereafter performing a recursive diff between the snapshots, the exact files that have been changed can be pinpointed, which is usually a much smaller subset than the total number of files. As an example, we identify the cleartext Facebook SDK access token vulnerability reported recently by MetaIntell in the popular Viber Android application.

After installation but before entering user details, we make a file system snapshot of both the data directory of the application and the contents of the sd card:
Hereafter we select 'Use Facebook details' and login with our Facebook account to continue. 
Finally we make another snapshot and use the simple recursive diff -r command to compare our two snapshots of both private application storage and sdcard storage. It immediately becomes clear where the Facebook access token is stored (which admittedly was not too hard anyway in this case):

Common vulnerabilities

Below is a non-exhaustive list of local storage vulnerabilities we have identified during our Android mobile penetration test engagements:

  • Unnecessary storage of sensitive data. 
  • Sensitive data stored in cleartext on external, world-readable storage such as the SD card (e.g. WhatsApp). Note that SD card write restrictions have recently been introduced from Android 4.4 Kit Kat onwards.
  • Sensitive data stored in cleartext in private local storage (e.g. aforementioned Facebook SDK access token vulnerability). This can become worse if the application is allowed to be moved to the SD Card, at which point its private data might become public.
  • Stored sensitive data encrypted with a weak encryption/hash algorithm. 
  • Stored sensitive data encrypted with a static encryption key in source code (either as string, byte array or some other obfuscated form).
  • Stored sensitive data encrypted with a dynamic encryption key stored in world-readable or private storage whenKeyStore or KeyChain is available.

We also bring into account whether the following options are on or off by default to determine appropriate risk ratings, amongst many other factors that the fragmented world of Android has to offer:

  • Device encryption
  • External storage encryption
  • Application can be moved to external storage
  • Root protection or not
728x90