If you read through the disclosed bug bounty reports on platforms such as hackerone.com it is clear that most bug bounty hunters are targeting web applications and neglecting the mobile application landscape. This is an opportunity that you can take advantage of.
I’ve had a lot of success recently looking at mobile apps, specifically android applications. After searching online for decent training material I stumbled upon the Udemy course Android Application Penetration Testing which has proven invaluable. (Disclaimer, I get no financial gain or anything else out of linking to this course, other than more competition in the android bug bounty space.) 4.5 hours of training at 2x regular playback speed and you’re in a good starting position.
Just like web applications, you can find the OWASP Mobile Top 10 very useful for identifying vulnerabilities to look for. My personal favourites are:
- M2 — Insecure Data Storage
- M3 — Insecure Communication
- M4 — Insecure Authentication
- M6 — Insecure Authorization
Tools and Resources
To get started with android you’re going to need the following installed on your testing machine:
- Java and JDK
- Android studio to run emulated android devices and capture debug information from apps
- ADB and related libs for installing packages and running a shell on android devices. Android Studio may install most of this for you.
- apktool to unzip and decode android packages
- dex2jar (you’re going to need to go to the Downloads section unless you want to build it yourself) to convert apk files to standard jar files
- JD-GUI to decompile jar files into readable java code
- Wireshark for capturing and analysing network traffic
In addition to this, you’re going to need a way to download android package files (APK) published by companies on the google play store. There are a few online sites providing this service which you can find with a quick google search. I’ve managed to get the following to work recently:
There are also browser plugins that claim to be able to download APKs for you without using a third party site, however these ask for your google credentials. If you’re going to try these I advise creating a fresh google account just for this purpose.
Most download sites will need the package name in the format ‘com.package.name’. As this isn’t always obvious or stated explicitly in the scope section of the bug bounty page, you can find it from the google play store URL. For example, facebook has the URL https://play.google.com/store/apps/details?id=com.facebook.katana&hl=en_GB where com.facebook.katana is the package name. Put this in your download tool and off you go.
The Testing Process
For me, testing can be broken into three phases:
- Source code analysis
- Dynamic analysis of code behaviour on the device
- Network analysis of communication between the app and online company services
Source Code Analysis
An android apk file is just like a standard java jar file and can be unzipped with any zip tool. The output however isn’t particularly usable as it is encoded differently to a traditional jar.
On that basis, the first thing to do is run it through apktool to extract and decode compiled resources such as the AndroidManifest.xml and hopefully some other useful stuff. Apktool will extract everything to a folder with the following command:
apktool d com.package.name.apk
Developers stick all sorts of things they shouldn’t into the AndroidManifest file. Often you can find API keys and secret keys, tokens, usernames, passwords, as well as a list of all of the application activites and definitions of how you can interact with them. You’ll get a whole bunch of other resources such as smali files which can contain secret information (these are the compiled java classes for android), images, xml documents, and sometimes other stuff. Either scan through the output manually file by file or run some searches within the extract folder for key works like ‘secret’, ‘password’, ‘user’, ‘token’, ‘api’, ‘key’, etc.
While android apps are traditionally java applications, they do not compile to standard bytecode. Instead, they are compiled by the Android SDK into Dalvik bytecode which runs with a reduced subset of functions designed to be lightweight enough to run on low power devices such as mobile phones, tablets, and other android devices. In order to reverse engineer the applications we need the convert the apk to a jar file with dex2jar. The install is straight forward and the best way to run it is with the bash script shown on their website:
sh d2j-dex2jar.sh com.package.name.apk
This will produce a usable jar file without any of the other resources such as xml, images, etc. With this, open up JD-GUI and open the jar file to see decompiled java. At last! The inner workings of the application. From here you can search for bad stuff (keys, passwords, usernames, tokens, etc.), understand how the application works, find other packages from third parties that have been bundled in which may also have vulnerabilities, and so much more. Reading through the source code and apktool output should give you all endpoints used by the application when talking to the company’s servers or third-party APIs. Make note of these as they will be useful later.
If you’ve found anything naughty at this point then well done! Start raising some bug tickets and get those bounties.
Dynamic Analysis of Code Behaviour on the Devices
Once we’ve had a look inside for low hanging fruit, the next step is to load the package onto an android device. If you have one lying around feel free to use that, however, I find it easier and much more useful to use an emulated device. This will become more obvious in the next section when we address network communication.
Open up android studio, install a new emulator device and get it running. I’m currently using a Nexus 5X API 26 with the Android 8.0 (Google APIs) image. Only certain images will let you get a root adb shell. You can probably do it by rooting the image as if it was a real phone but why bother when another image will do the same thing without wasting time. If you try to run without the Google APIs image you’ll get the error “adbd cannot run as root in production builds” when trying to launch a root shell.
Install the package onto the emulator with:
adb install com.package.name.apk
The app should appear in the apps list once this completes. Click on it to launch the app and you’re ready to start testing!
Applications are sandboxed into their own location for security reasons. The only storage they have access it is at:
Before you do anything else with the application connect to the device through adb and browse through this directory. From your command prompt:
adb root adb shell cd /data/data/com.package.name/ ls -lrt
You’ll see a few folders standard across most applications. Have a look through them all to get a feel for what is there. If you can’t get into /data/data/ from your shell then you’re not running as root. Fix this before going further.
Start using the app. Create an account, login, logout, log back in, start doing whatever the app does. While doing all of this keep an eye on the data folders for changes with ls -lrt.
shared_prefs is where developers put xml files containing application preferences and other customisation data. Sometimes Oauth2 tokens go in here, other times usernames and passwords go here in either plane text or encrypted format. If you find anything naughty in plain text once you start using the application, raise a bounty ticket. If the data is encrypted the property name will still be visible and you’ll see a random-looking base64 encoded string for the value. Don’t worry, the application needs to be able to decrypt this so the encryption mechanism will be in the source code viewable through JD-GUI. Have a look until you find the encryption mechanism. Raise a ticket.
The databases directory contains sqlite database files which you can download to your own machine with:
adb pull /data/data/com.package.name/databases/databasename.db ~/databasename.db
Now you can open this with a sqlite client and start searching through tables
sqlite database.db .tables select * from $tablename;
Usernames, passwords, tokens, api keys, etc. all can sometimes be found in the databases instead of shared_prefs files. Run through different functions within the app and watch how these change. Report to the vendor as usual.
There’s other stuff you can do such as launching specific activities listed in the AndroidManifest that would otherwise require some sort of authentication if used through the standard app flow. You can play with these to see if you can bypass local login to access local data but I’m not going to go into that level of detail here.
Network analysis falls into two areas: looking at raw packets, and running HTTP requests through an intercepting proxy such as Burp Suite or OWASP ZAP. The easiest to do is to spin up wireshark and start capturing network packets as you use the application. If any traffic is sent unencrypted over HTTP instead of HTTPS have a look to see if it contains session cookies, usernames, passwords, etc. If it does, raise a ticket. If not, they’ve passed the first test and your job just got a little bit harder.
Start your intercepting proxy and configure the android emulator to proxy all traffic through burp or other proxy. You’ll also need to install your burp SSL CA cert on the device. If you’ve done this and suddenly find you can’t access the web anymore from the app but your actual web browser works fine then the application has likely implemented SSL pinning within the application. This means the app is overriding the system SSL certificate checks. You can bypass this with a little bit of work then install the patched package back onto your emulator and start testing. If you’ve done it right then traffic should start to appear in your proxy http logs. If you don’t need to bypass SSL pinning then raise a ticket as the app provider should probably be doing this.
Again, run through the functionality of the application and watch the network requests through burp. At this point, you can start to do all of the usual web application vulnerability testing with the aid of a local application to generate requests for you. Have fun and see what you can break.