Since my previous post about zero-permission Android applications, I have continued researching along the same lines. This work is similar to research presented by Lookout at Defcon. As that work is a few years old, I thought this topic should be reviewed with fresh eyes.
At Defcon 18, three researchers from Lookout Mobile Security presented on several permission-related security issues. My observation is that most of the research presented was targeted at Android 2.2 and below. They demonstrated that an app with no permissions can reboot a device, start on boot, block user input, and obnoxiously play noise. More interestingly, they showed that they could launch the browser and perform two-way communication with a remote server, and that they could do so when the screen was off.
Building on this work, I wanted to test out their approach to two-way communication using the browser while the screen is off and the device is locked. I found that, indeed, registering a URI handler and calling that URI from within the browser worked well. I was able to have the app query my server, causing the server to call a URI to instruct the app on what to send next. This would cause the app to send that data and query the next instruction and then close the browser window when there was nothing left to do. Hiding this activity was another matter.
I could not launch the browser while the screen was off, at least not in 2.3 or 4.0: the intent to launch the browser would begin, but it would block until the screen turned back on. On 2.3, this meant that when the screen was off, my app would launch and then wait until the screen was on but still locked. My app could then freely perform two-way communication. Of course, if the device was quickly unlocked once the screen was on, it would be evident that the browser was open. On 4.0, things were a little trickier: I found that when the screen was on but the device was locked, the browser would launch but fail to navigate to the requested page. I'm not sure what changed in 4.0, but it definitely makes sneaky browser games much more difficult to perform.
Building upon my previous release, this version of my No Permissions app includes many new actions I could accomplish without requesting permissions. Like before, it can gather version and identifier information and send that information to my server. It can also upload any readable file, whether from the SD card or from a world-readable directory, and send that data to the server. I also created a location mining function that would read the pictures stored on the SD card, scan them for EXIF tags, and upload the location within the EXIF along with the time the picture was taken. While not as good as having the FINE_LOCATION permission, this information can contribute to creating an accurate impression of where a person was, assuming that the storing of location data within pictures is enabled. The app uses the browser trickery described in the previous paragraph for two-way communications, as such the server is able to instruct the app to download a file, store it in the app's private storage, and either open the file with the default handler for that file type or execute it as Java code. While not allowing any new permissions, executing new Java code can further expand the possible activities. Lastly, I created the option to take a base64-encoded string and execute that on the command line -- if the app detects that the device may be rooted, it attempts to perform that command line action as root, otherwise it executes it as our unprivileged app's user id.
At some point, when attempting to implement code to run shell commands given by the server, I noticed that ping was the only binary in /system/bin that was setgid and world-executable. After some testing, I quickly realized that my application with zero permissions was able to successfully ping Internet hosts. I tested this out on a device running 2.3.5 and it worked, but when I tested the code on a device running 4.0.4, it didn't. After a bit of reverse engineering, I found that the ping binaries were different on the two devices. In fact, the differences corresponded to this commit by Nick Kralevich. According to the git logs, the fix was committed after the deadline for the 2.3.x branch. This means that any device running Android 2.3.x or below is vulnerable to this slight oversight in permission checking. Just to be thorough, I downloaded a ROM for a Honeycomb-based tablet. The ROM, which was at Android 3.0.1, contains a ping binary with the changes present in the 4.0.x branch.
It's important to realize this is not a regular ICMP tunnel; we can only execute the ping binary from a command-line. The end result is that one can send 24 bytes of data to a remote server and receive a small integer in the range 8-64 (less than 6 bits of data) in return. This technique allows for a slow trickle of ICMP packets to carry information off of a device and is able to receive enough information back to know what data to send next from a list of possible options. While being a much smaller channel on which to exfiltrate data, this is undetectable to the end-user. In fact, when testing this on a rooted device with a firewall app, I found that the firewall only filters TCP and UDP, missing the ICMP packets completely.
As a side note, execution of the ping binary is also the only way I determined that an application with zero permissions can perform DNS lookups. It may be possible to achieve a wider communication channel using DNS lookups, but I did not look into this option.
Based on this research, I strongly advise that users update to Ice Cream Sandwich (4.0.x), if possible. In addition, disable location data within pictures you take if you don't need the feature. Do not store any files or data on your SD card or external storage any longer than necessary; move them to your computer or delete them if you no longer need them on your phone or tablet. Finally, be careful about what apps you install; even if it doesn't ask for many permissions, a malicious app can perform all sorts of nasty actions on your device.
Android app developers should continue to write apps that only request the permissions needed by the app, and they also need to be wary of any 3rd-party code, such as advertising libraries, that they include in their apps. App developers should also be mindful of file-level permissions of any locally stored files and avoid using external storage where possible; I suggest that they consider using libraries such as SQLCipher to increase the privacy of any stored user data.
Google has some work to do, too. It's my opinion that Google needs to take responsibility for device updates away from the neglectful carriers and push the latest version to every device that can run it. If 4.0 isn't possible for all devices, security updates like fixing the ping binary should be back-ported to the older 2.3 branch. Further, Google should be adding more permissions, such as restricting access to browser launching and restricting the execution of shell commands.
The source for the revised No Permissions app is available here: NoPermissions-1.5.zip
The source for the Ping tunneling app is available here: Ping.zip