Introduction

One of the core designs of the Android operating system’s sandbox is to assign different applications a unique user identifier (UID). By doing this, Android reuses the underlying Linux kernel and filesystem properties to enforce boundaries. There are certain situations where apps may share the same UID, but that requires they be signed with the same certificate and explicitly request the same UID. The vast majority of the apps on the play store get installed as their own user. Because Android relies on the Linux file permission model, the files an application creates also have a set of read/write/execute permissions for the owner, group, and others.

This blog post will go into detail about some apps and libraries still making mistakes and show how they may be leveraged for arbitrary code execution and privilege escalation through permission stealing (CWE-732, CWE-250). For the examples below, we’re using a small payload which leverages the logwrapper and id tools to demonstrate that code execution has taken place and what UID, groups, and selinux context our code is running as. This output will show up in the system logs.

Please note that following with our NowSecure Disclosure Policy we disclose “Basic App Vulnerabilities” immediate on discovery to both users and developers. Specifically, users of the apps named in the article can avoid the vulnerabilities by uninstalling the application until the developer applies fixes.

6/18/2015 – The LiveChurch.tv’s ‘Bible’ has been updated on the play store and the Vitamio library has been removed. As of version 6.0.4, the app does not contain the vulnerable code.

Background

The file permission system, described here, can be difficult to fully understand at first. While these numbers (aka modes) appear close numerically, 0770 has immensely different security and privacy implications for a file than 0777. In our analyses of apps, we too frequently see programmers choose careless permissions for their files and grant other unix users (i.e., other apps) the ability to read and write files which are meant to be private and even despite Google’s warnings regarding world readable and world writeable modes.

Creating world-readable files is very dangerous, and likely to cause security holes in applications. It is strongly discouraged; instead, applications should use more formal mechanism for interactions such as ContentProvider, BroadcastReceiver, and Service.

Case #1, Poweramp Music Player

The Poweramp Music Player app uses lax file permissions for preference files and some of its executable code.

View the code on Gist.

From the above, we can see that both of the native code libraries in the files directory are writable by anybody on the system (world-writable), along with three of the XML files in the shared_prefs folder. The latter of these is interesting because it allows any other application installed to modify Poweramp’s settings. This means other apps can change the way Poweramp behaves and if there were any sensitive data in those XML files such as username and password, it would be ripe for the picking.

But, we can try to do better than that. If we can overwrite one of the files/lib*.so files and get Poweramp to load our code, then we can assume their UID, groups, and all of their Android permissions. As of this writing, the play store description describes the permissions as

Photos/Media/Files modify or delete the contents of your USB storage read the contents of your USB storage

Device ID & call information read phone status and identity

Other disable your screen lock change your audio settings pair with Bluetooth devices modify system settings full network access send sticky broadcast prevent device from sleeping view network connections



From a developer’s point of view, that gives us access to the following manifest permissions:

View the code on Gist.

Attempt #1:

Lets do a quick test to verify that we can (A) overwrite their file and (B) get Poweramp to try to load an ELF that isn’t theirs.

View the code on Gist.

So, yes, we can simply overwrite the file. it is now 5 bytes long. Unfortunately, when we start the application, in logcat, we see the following:

View the code on Gist.

and our file has been overwritten

View the code on Gist.

The application has given us a hint that because the file’s size did not match what it expected, it overwrote it. So, what happens if we create a file with the correct size?

View the code on Gist.

Then start the app and watch logcat… BAM!

View the code on Gist.

This dlopen() line shows that the app did attempt to load our library. Since it was not a valid ELF file, it was rejected and Poweramp overwrote it again. So now we know that the app will run our ELF if we simply replace their library with a valid one. However, this will almost certainly break some functionality of the app. It will either crash or the user will notice that there’s no music playing. What we can do is create a backup copy of their library, insert ours in its place, and then call through to the original library that we put in a safe place. Source code for something that does just that can be found here.

First, this app truncates libaudioplayer_native.so to 0 bytes and starts Poweramp so that app will rewrite a correct version out to disk. Then, it backs up the original lib and copies a libtest.so out of its assets in place of libaudioplayer_native.so . After its done that, it restarts Poweramp to get it to load the new app. The replacement code is simple enough but does demonstrate getting an app to run code which its developer never intended for it to run. The following lines in logcat show that our code works (abbreviated for clarity).

View the code on Gist.

The section uid=10096(u0_a96) gid=10096(u0_a96) groups=1015(sdcard_rw),1028(sdcard_r),3002(net_bt),3003(inet),9997(everybody),50096(all_a96) context=u:r:untrusted_app:s0 comes from Poweramp executing our payload code. It shows that we have been granted the groups for writing to external storage, bluetooth, and internet. In addition to these, we’d also have Poweramp’s android permissions for dismissing the lockscreen, adjusting system settings, wakelocks, and READ_PHONE_STATE (access your imei, etc).

Case #2 QPython – Python for Android

For historical reasons, Android has ‘external’ storage, which is not usually external to the device. This is a directory which nowadays is managed by a fuse program emulating a fat32 filesystem. Because fat32 has no concept of file owners and groups, every file in external storage is accessible to apps with the proper android permission. From a privacy standpoint, it makes sense, then, that an application shouldn’t store sensitive data here. Google’s docs for storage say something to this effect, too.

In most devices, the external storage is mounted with the noexec flag, which means that programs and shared libraries cannot be run from here. However, there are many apps which store interpreted code and VM bytecode on external storage, which is then processed as instructions by another binary. Some examples of languages using interpreted code and VM bytecode are javascript, python, java, shell script, lua, php, and html. When an application loads this code from a file which writable by other applications, it allows those other apps to elevate their privileges by stealing permissions. We will demonstrate this by attacking the QPython – Python for Android app.

The QPython application appears to have a full python 2.7 installation packaged inside it, including a libs , site-packages , pip folders, setuptools, and even some scripts and example projects. Unfortunately, these are all stored on the external storage. Python contains a handful of APIs for running subprocesses. This means that we can insert some payload code into any one of the interpreted files and when the app runs them, it will run our own code. And when our code runs, it will have all the permissions that QPython has. The manifest lists the following:

View the code on Gist.

While the play store describes these as:

Version 1.1.1 can access:

Location approximate location (network-based) precise location (GPS and network-based)

Photos/Media/Files modify or delete the contents of your USB storage access USB storage filesystem read the contents of your USB storage

Camera take pictures and videos

Microphone record audio

Wi-Fi connection information view Wi-Fi connections

Other access SurfaceFlinger full network access view network connections control Near Field Communication pair with Bluetooth devices install shortcuts prevent device from sleeping control vibration control flashlight read battery statistics



Building an app to take advantage of this vulnerability is much less involved than one might imagine. These are python scripts and it only takes scriptkiddie level skills to abuse them. A proof-of-concept can be seen here. This code checks if QPython is installed, and if so, it writes out

View the code on Gist.

to /sdcard/com.hipipal.qpyplus/lib/python2.7/site-packages/sitecustomize.py . This sitecustomize.py script is loaded by the interpreter automatically. To see it in action, watch logcat while we open the QPython app’s python interpreter –

View the code on Gist.

We can see from the output that we have been granted bluetooth and internet unix groups. We also have access to all those other interesting permissions listed in the app’s manifest.

Case #3 Vitamio SDK

Our final example affects the Vitamio SDK, which is used by thousands of applications. Vitamio is a multimedia library that developers may include in their app to help them play various types of audio and video files. The vast majority of these apps we’ve seen are by developer CTS cBroadcasting who managed to rack up a couple thousand apps all on their own. Some popular examples from other developers include LiveChurch.tv’s ‘Bible’ who claim 180M+ users worldwide and UC Browser HD and FM Radio, each with between 10 and 50 million downloads from the Play Store.

When the Vitamio library is initialized, it creates a world-writable directory and then extracts its payload of several native libraries into this directory, with world-writable permissions. This can be seen by disassembling their libvinit.so native library. The Java_io_vov_vitamio_Vitamio_native_initializeLibs function creates calls through to a utility function to mkdir with 0x1ff for the mode parameter. This 0x1ff translates to 0777 in octal, or read, write, and execute permission for all users. Then it procedes to create files in a loop and chmod them to 0x1b6. This 0x1b6 translates to 0666, or read and write permission for all users.

Part of the helper function to create 0777 directories:

View the code on Gist.

Section of Java_io_vov_vitamio_Vitamio_native_initializeLibs which creates 0666 files:

View the code on Gist.

Our attack scenario is almost identical to the Poweramp attack. We will pick an app using Vitamio, then try to swap out one of its native libraries with our own and cause it to run our own code.

Our sample app this time is Video Player for Android with 10M+ downloads. We can first install the app and run it 1 time so it extracts its libraries.

View the code on Gist.

Now, lets pick one and nuke it!

View the code on Gist.

And when we use the app to try and watch a video, we see this in logcat –

View the code on Gist.

So, now we know the app will try to execute our code. Let’s give it some. Here’s our main.c for our native library –

View the code on Gist.

Compile this with the NDK. Then move the original libvplayer.so to libvplayer_orig.so and push our library in its place. SE for Android doesn’t directly allow us to “adb push” and overwrite this file, but we can push it to /data/local/tmp and then copy it into place.

View the code on Gist.

And now, we try to play a sound from within the Video Player app, and watch for our code to call out to us in logcat –

View the code on Gist.

… and WHAMMY. Similar attacks are possible with the other applications using the Vitamio library. Its just a matter of finding the proper codepath to trigger the app to start playing a media file with the library. Some codepaths may even be exposed by an intent which may be fired off by the attacking app, and lowering the amount of user interaction required.

Conclusion

The unix filesystem properties play a very important role is keeping an application’s data safe from other apps and protecting user privacy. Developers should pay close attention when setting these permissions to avoid leaking its private data to other apps or being a gateway for apps to escalate by stealing their permissions. Developers who are not familiar with the concepts behind these properties should take the time to study up a bit.

While the examples outlined in this blog demonstrated gaining code execution, there can be very serious consequences for an app simply storing data in a world readable file. At NowSecure, we scrutinize a lot of apps. Developers seem to love storing data such as usernames and passwords in xml and sqlite files. This in itself is considered a bad idea. When these apps then go and make the file readable by all other apps, they are basically just handing this sensitive data out on a silver platter. In apps dealing with your real, physical money, such as a banking app, a simple mistake like this can make for a very bad day.

There are many different calls a developer may use to set file and directory permissions. The Android Java apis have openFileOutput, openOrCreateDatabase, and setWritable. It is also not uncommon to find a Runtime.exec call with chmod 0777 /path/to/some/file . Developers using native code have the opportunity to set file permissions with creat, open, and chmod. These lists are nowhere near all-inclusive. There are many, many more ways to set permissions for the files an application creates. Some IDEs include support for developers when using these apis. Google’s Android Studio will show a warning if the user attempts to use the depreciated Context.MODE_WORLD_WRITEABLE. Developers chosing to write their code with a text editor such as vi and compile via command line do not automatically get these warnings when creating a file that is world writable and should exercise even more caution.

All of the attacks demonstrated here are local attacks. However, it is not difficult to chain one of these attacks with and arbitrary file write by a network attacker as described here and here . By combining these two vulnerabilities, there is a possibility for a remote attacker to gain arbitrary code execution. What’s more, these two vulnerabilities do not even need to be in the same application.