By Lee Neely & Chris Crowley
Recent updates to the Android OS have changed the permission model for external storage, and these changes will likely impact the way pen testers assess the actions and corresponding risks associated with applications, both malicious and benign, particularly when analyzing how they interact with external storage.
Consider this scenario: You are provided an application from an unknown third party to assess. Your assignment is to assess both the behavior and trustworthiness of the application. Because of the permission model changes, the application behaves differently when trying to access external storage than it would have in earlier releases of the Android OS.
In this article, we’ll provide information on how the permission model changed and some tips and techniques you can leverage when you are assessing an application in your next Android pen test.
There were two changes which we will discuss separately. They have different impacts when assessing application behavior. Additionally, based on feedback after the KitKat release, Lollipop (5.0) introduced a new intent that allows application developers to return to the more familiar behavior. More on the Lollipop change later.
The first change, which has the greater impact on applications, was a change in the permission model for external storage. The second is a refinement in the treatment of application private storage area on secondary storage, which could be a bonus for malware.
Android external storage is defined to be a case-insensitive filesystem with immutable POSIX permission classes and modes. External storage can be provided by physical media, such as an SD card, or by exposing a portion of internal storage through an emulation layer. (see https://source.android.com/devices/storage/ )
Android versions prior to KitKat (4.4) provided a single access model for external storage. Access to this storage was protected by a single permission WRITE_EXTERNAL_STORAGE. Starting in Jelly Bean (4.1) read access was protected with the READ_EXTERNAL_STORAGE permission. Prior to Jelly Bean, read access did not require any special permissions.
KitKat introduced two storage models for external storage; one known as primary storage which is essentially unchanged and another known as secondary storage. Primary storage is a part of the device internal storage. The APIs for accessing primary storage are unchanged. Secondary storage is provided by physical media, such as an SD card. Secondary Storage implements new permissions, such that attempts to write outside the applications private storage area (/storage/extSDCard/Android/Data/[Package Name]) are not permitted by the application without additional permissions. The concept of these application specific directories was introduced in FroYo (2.2.)
Permissions on external storage are synthesized. This can be confusing if you’re used to accessing SD cards that utilize the FAT file system without concerns about permissions. This is because the FAT file system doesn’t support permissions natively. Starting in KitKat, the owner, group and modes of files on external storage devices are now synthesized based on directory structure. These synthesized permissions are accomplished by wrapping raw storage devices in a FUSE daemon.
The First Change:
When Honeycomb (3.0) was introduced, a new paradigm for secondary storage access was also included. The paradigm includes the relevant additional permissions: WRITE_MEDIA_STORAGE and READ_MEDIA_STORAGE. (Note the change from *_EXTERNAL_STORAGE.) These permissions allow read and/or write access across the secondary storage device and are granted to system, manufacturer and mobile operator applications. Initially some device manufacturers also granted this on the fly to applications with WRITE_EXTERNAL_STORAGE permission. With the KitKat updates, this behavior has disappeared requiring applications to use new API calls to perform updates on items in secondary storage. Thus it has received the most attention with the KitKat release.
Applications with only the READ_EXTERNAL_STORAGE permission are largely not impacted. While the new permission model also tightened the permissions on the application specific directories on secondary storage; most applications were not accessing those locations. The WRITE_EXTERNAL_STORAGE permission also includes READ_EXTERNAL_STORAGE permissions.
The Second Change
The application specific folders (/storage/extSDCard/Android/Data/[Package Name]) are now deleted upon application uninstall. That means that if you store important information in that directory, then uninstall the application that created that information, your data will also be deleted. In contrast, while this behavior could be desired if an application is trying to hide its tracks or malware, it could be frustrating during the forensic examination or during times where you expect data to persist between actions taken while testing a device.
When analyzing application behavior, be sure to examine the application specific folders. Also, compare the folders on Jelly Bean and KitKat devices for content differences due to the permission changes.
How does that permission model work?
These permissions are implemented in kernel level groups.
The WRITE_EXTERNAL_STORAGE permission grants membership to the sdcard_rw and sdcard_r groups, which used to have full access to the secondary storage device.
The READ_EXTERNAL_STORAGE permission grants membership to the sdcard_r group, and therefore grants permission to read the secondary storage device.
The WRITE_MEDIA_STORAGE permission grants membership to the media_rw and media_r groups. This is the group system applications use to access the entire secondary storage device.
It turns out there is also a READ_MEDIA_STORAGE permission with a corresponding media_r group. It is not clear how this differs from the READ_EXTERNAL_STORAGE group.
Groups are associated with their permissions in system/etc/permissions/platform.xml. Researchers wishing to restore the old behavior are modifying this file to add the media_rw group to the WRITE_EXTERNAL_STORAGE permission. This modification requires a rooted device.
To illustrate, here are secondary storage directory listings from a KitKat and Jelly Bean device:
Here is the private application storage directory on a Jelly Bean device: (Android/data on the secondary storage device.)
shell@android:/storage/sdcard0 $ ls -la Android/data
-rw-rw-r-- root sdcard_rw 0 2013-03-28 15:04 .nomedia drwxrwxr-x root sdcard_rw 2011-12-31 16:01 com.android.browser drwxrwxr-x root sdcard_rw 2013-03-28 15:32 com.google.android.apps.maps drwxrwxr-x root sdcard_rw 2013-03-28 15:04 com.google.android.videos drwxrwxr-x root sdcard_rw 2013-03-28 15:04 com.google.android.youtube drwxrwxr-x root sdcard_rw 2013-03-22 16:11 flipboard.app
Here is the same directory on a KitKat device:
shell@d2vzw:/storage/extSdCard $ ls -la Android/data -rwxrwx--- root sdcard_r 0 2014-12-15 19:58 .nomedia drwxrwx--- u0_a84 sdcard_r 2014-12-15 20:11 com.android.browser drwxrwx--- u0_a137 sdcard_r 2014-12-15 20:14 com.google.android.apps.magazines drwxrwx--- u0_a56 sdcard_r 2014-12-15 19:58 com.google.android.music drwxrwx--- u0_a124 sdcard_r 2014-12-15 19:58 com.google.android.youtube drwxrwx--- u0_a92 sdcard_r 2014-12-15 20:48 com.sec.android.gallery3d drwxrwx--- u0_a6 sdcard_r 2014-12-15 19:58 com.sec.android.nearby.mediaserver drwxrwx--- u0_a153 sdcard_r 2014-12-15 20:12 com.vcast.mediamanager
If you examine the two listings you can see that the group controlling access to the private application directories has changed, and the ownership of the individual directories has changed to match the application owner/user on the device. Also notice the world read/execute permissions on these directories is removed in KitKat. With those changes a given application can no longer write to other application directories.
Note: the sdcard_r group doesn’t actually have write permissions to these directories, the FUSE daemon is synthesizing the results.
Let’s take a look at the permissions at the top level of the secondary storage device:
Storage Permissions in Jelly Bean:
shell@android:/storage/sdcard0 $ ls -la drwxrwxr-x root sdcard_rw 2014-11-10 16:02 .downloadTemp drwxrwxr-x root sdcard_rw 2011-12-31 16:01 .face drwxrwxr-x root sdcard_rw 2014-12-15 21:27 .thumbnails drwxrwxr-x root sdcard_rw 2011-12-31 16:01 Alarms drwxrwxr-x root sdcard_rw 2011-12-31 16:01 Android drwxrwxr-x root sdcard_rw 2011-12-31 16:01 Application drwxrwxr-x root sdcard_rw 2011-12-31 16:01 DCIM
Storage Permissions in KitKat:
shell@d2vzw:/storage/extSdCard $ ls -la drwxrwx--x root sdcard_r 2014-12-15 19:58 Android drwxrwx--- root sdcard_r 2014-12-15 19:58 LOST.DIR drwxrwx--- root sdcard_r 2013-02-21 04:57 books drwxrwx--- root sdcard_r 2013-02-21 06:32 camera drwxrwx--- root sdcard_r 2013-02-21 06:31 documents drwxrwx--- root sdcard_r 2013-02-21 04:57 downloads drwxrwx--- root sdcard_r 2013-02-21 04:57 music
From here, it looks like nothing can write to the top level under KitKat. In practice, the system applications are able to read and write just fine.
So, when you’re assessing the operations of an application, you now need to consider both the overt READ/WRITE_EXTERNAL_STORAGE permissions, actions taken in the application private storage area, and lastly, use of the new intents designed to manage access to this storage.
What is the reasoning behind the change?
In short, the media card was unstructured storage and not well managed, which made it easy for applications to both write and read that data. That’s why OHA is continually adjusting the behavior, because there is a critical balance between access to the phone owner’s data, and the risk of exposing that data. The new model is to wrap access to external storage through the FUSE daemon as well as cleanup and/or normalize access to the media card.
From the http://source.android.com/devices/tech/storage/index.html web site:
The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.
What are the impacts?
Apps can no longer write ad-hoc to the media card, so things like third-party photo editors don’t work without changing how they are accessing those files. Read permissions still work, so third party media players/readers still work. Files are lost on application uninstall and device backup applications have had to adjust where files are stored. Additionally, running applications from a media card no longer works. Sideloading applications from the media card works provided the APK file is in a viable location, such as the downloads directory, and the options are set to allow application installation from other sources.
What does that mean when assessing an application?
- Application use of primary rather than secondary storage.
- This is not changed. If an application makes no use of secondary storage, your assessment is not impacted by these changes.
- An application may avoid the whole issue by never trying to write there.
- Application developers may try new ways to access secondary storage.
- Look for applications trying to add the WRITE_MEDIA_STORAGE permission in the manifest.xml file. Note: this only works for system/manufacturer applications.
- Look for calls to the new APIs – Pen Testers can assume malware has already adjusted to the new paradigm.
- Examine use of private application storage space
- Check for use of the new private application space on secondary storage, and consider how the application may try to leverage it being deleted on uninstall. Conversely if you uninstall the application, remember it gets deleted.
- Does the application use new intent introduced in Lollipop?
- Lollipop contains a new intent designed to emulate the old behavior.
- This is the supported/preferred mechanism for accessing secondary storage and isn’t necessarily an indication of a problem.
- Just to be sure, make sure the platform.xml file hasn’t been modified.
- Examine system/etc/permissions/platform.xml to see if media_rw group was added to WRITE_EXTERNAL_STORAGE definition which restores the old behavior and could be indication of device modification/rooting.
- It could be illuminating to compare the application behavior on a Jelly Bean device.
New in Lollipop
With Lollipop, a new ACTION_OPEN_DOCUMENT_TREE intent was introduced that allows application developers to return to the more familiar behavior. It is expected that applications will implement this intent as the simplest mechanism to restore the expected behavior. Google Software Engineer Jeff Sharkey explained the change and is quoted below.
After the change was rolled out in KitKat, Google heard loud and clear that developers wanted richer access beyond these directories, so in Lollipop they added the new ACTION_OPEN_DOCUMENT_TREE intent. Apps can launch this intent to pick and return a directory from any supported DocumentProvider, including any of the shared storage supported by the device. Apps can then create, update, and delete files and directories anywhere under the picked tree without any additional user interaction. Just like the other document intents, apps can persist this access across reboots.
This gives apps broad, powerful access to manage files while still involving the user in the initial selection process. Users may choose to give your app access to a narrow directory like “My Vacation Photos,” or they could pick the top-level of an entire SD card; the choice is theirs.
To make it easy for developers to transition to these new APIs, there’s a new DocumentFile support library class. It looks and feels just like a traditional java.lang.File object, which makes it easy to adapt existing code:
-Lee Neely & Chris Crowley
p.s. If you want to secure your mobile infrastructure and apps using world-class methodologies and techniques, you should definitely check out SANS Security 575, a GREAT course on mobile device security and pen testing.
Chris Crowley will be teaching it in Houston from March 28-28, 2015.
Josh Wright will be teaching it at SANS Orlando from April 13-18, 2015.