If you attack someone, they will defend themselves, but if you tickle them, they will eventually crack open. This surprisingly applies to Android apps as well! Therefore, I created AndroTickler, not to test apps against certain attacks or examine them for specific vulnerabilities, which developers would learn to avoid. However, it helps pentesters to analyze and test apps in their own style, but in a faster, easier and more flexible way. AndroTickler is a Swiss-Army-Knife pentesting tool for Android apps. It provides information gathering, static and dynamic analysis features, and also automates actions that pentesters frequently do and highly need during their pentests. In addition, it makes use of the powerful Frida to hook to the app and manipulate it in real-time.
AndroTickler is available at the github page here, where each AndroTickler command is explained in detail. Therefore, the main intent behind this blog post is to explain what AndroTickler does and how to use it to pentest Android apps.
Requirements to Tickle
AndroTickler is a java based tool that runs best on Linux. It requires common tools that usually exist on any mobile app pentester’s computer, such as adb and sqlite. It uses adb to communicate with the Android device, on which the app to be tested is installed. Additionally, it requires a rooted Android device to access the app’s storage directory and test the security of the app in the worst case senario: against a local attacker with root privileges. Some AndroTickler features require Frida and jarsigner to be installed on your machine, but the rest of the functions would work perfectly without them. It also uses other tools, mainly to decompile and recompile APK files such as Apktool, Dex2jar and JD. But these tools are already shipped with AndroTickler, so you don’t need to struggle with dependencies.
On your machine, AndroTickler creates its workspace directory, where it keeps all data of the tested apps. It also creates a directory on the device’s external storage (/sdcard) to temporary copy files from the device to the workspace directory. The locations of both directories are specified in a small configuration file Tickler.conf. The default location of these directories is $AndroTickler.jar_path/Tickler_Workspace and /sdcard/Tickler respectively.
After building AndroTickler , copy AndroTiclkler.jar from build/libs directory to the main directory (where Tickler.conf exists). Also make sure that the 2 files d2j-jar2dex.sh and d2j_invoke.sh in libs/notJars/dex2jar-2.1/ are executable.
So without any further due, connect your rooted Android device and let the tickling begin!
Hello App !
Each Android app has a unique package name, which AndroTickler uses to identify its target. You can search for the app’s package name using -findPkg <search_key> command. From now on, any AndroTickler command that targets our app refers to it using -pkg <package_name>.
The first time AndroTickler is executed on any Android app, it automatically does the following:
-
Create a directory for the app with its package name in Tickler workspace directory. From now on, all directories in this blog post are relative to this directory, unless mentioned otherwise.
-
Copy the app’s APK file from the device.
-
Disassemble the APK using APKtool.
-
Extract its Manifest file.
-
Decompile the app’s code using dex2jar and JD tools.
-
Copy the app’s storage directory.
Therefore, it collects all possible sources of information about the app, which it will use later in information gathering features.
Information Gathering
Now, before starting pentesting our app, we need to collect information about it. -info command gets general information about the app such as the permissions it requires and whether it allows backup and debugging. Also if the app uses the insecure Android external storage.
Then we focus on the 4 main components of the app (Activities, Services, Content providers and Broadcast receivers). Just listing these components tells a lot about the app features and helps to discover hidden components that are not easily observable by a normal user, such as hidden developer menus and fishy broadcast receivers. AndroTickler lists all components using -l command. You can also list components of a specific type or a certain component. Additionally, AndroTickler analyses the app’s Manifest file to find out if these components are exported. Exported components are reachable to other apps on the device, therefore they are considered exposed targets to attack the app. AndroTickler also collects the intent messages the components are reachable through and analyses the decompiled code to get the extra parameters the app requires in these intent messages. -l -v flag displays this verbose information.
The next step is to get deeper in the decompiled code of the app.
Code Analysis
-squeeze command squeezes the decompiled code to obtain as much juicy information as possible about the app, such information include:
-
Common components and Frameworks, such as Webview, Okhttp and SQLCipher
-
Binary libraries in the APK file
-
Information to be logged in logcat messages
-
Interaction with shared preferences, keystore and databases
-
Usage of external storage
-
URLs that the app might communicate with
-
Indication of certificate pinning
-
Usage of cryptography and weak cipher suites and hashing mechanisms
-
Comments in the code
-
Possible credential disclosure
AndroTickler squeezes by default all decompiled code and that usually results in a large output, therefore it is recommended to redirect it to a text file. If you want to squeeze only the code related to the app and not external libraries included within the app, -squeeze short command narrows down the analyzed code. For example, if the test app is called de.notenaf.myApp, then only the decompiled code in JavaCode/Code/de/notenaf will be analyzed and therefore excluding code that probably belongs to libraries such as com.google.* . Sometimes the source code of the app is also available, which is usually more appealing and less obfuscated than the decompiled code. Therefore AndroTickler can squeeze code at any given location using -squeeze <location> command.
Moreover, AndroTickler allows to search the decompiled code using -sc <search_key> command. Also searching code at a specific location is possible using -sc <search_key> <code_location>
Storage Analysis
Every Android app stores its data in a dedicated directory that only it can access. However, on a rooted device, any malicious app with root privileges can reach this data. Therefore it is highly recommended that apps store any sensitive information in an encrypted form.
AndroTickler pulls the app’s data storage directory using -dataDir command. By default, it updates DataDir directory in the app’s Tickler directory. Then you can analyze it however you prefer. If you want to save several states of the app’s storage directory (for example state1, state2 ….etc) , then just specify a name, such as -dataDir state1. In this case, the data storage directory is saved as transfers/state1 and will not get updated.
Additionally, -diff command compares between 2 states. The app’s data storage directory is copied to DataDirOld, then you go crazy and do what you like to the app. After you’re done, AndroTickler pulls the data directory again to DataDir direcotry and applies diff command to compare between the before and after cases.
Now back to “better-encrypt-critical-data-at-rest” recommendation, AndroTickler looks for unencrypted databases in the app’s storage using -db command. You can also dump any of the unencrypted databses using -db d. Note that some encrypted databases might not be detected by -db commands.
AndroTickler also searches for any key in the app’s storage directory using -sd <search_key> command. It updates its version of the app’s storage (as in -dataDir command), then searches it for the key in a case-insensitive way. Additionally, it searches for the key’s Base64 format too. If there is a hit in an unencrypted database, it also returns the database’s and the table’s names.
Tickling
After gathering enough information about the app and analyzing its code and storage, now it’s time for the real tickling! AndroTickler triggers every component using all combinations of intents that match its intent filter. If an intent causes an interesting result, AndroTickler can capture a screenshot of the device to be used as a PoC. Additionally, AndroTickler captures all logcat messages during the tickling session to give a better overview on the app’s reaction towards every intent message. The logcat messages file lies in logs/ directory and its path is printed at the beginning of the command’s output. Each intent is appended and marked in the log messages file, so that you can know which intent caused the following logcat messages. Therefore, it is recommended to display the log file in another shell for better monitoring (such as tail -F $logFile). It is also recommended to monitor the app’s traffic (using Burp or any other tool) to get the complete picture of how each intent affects the app.
AndroTickler creates the intent messages and sends them using am tool over adb. It uses root/normal privileges to tickle unexported/exported components respectively, in order to demonstrate the security of the app on both rooted and unrooted devices. In addition to confirming some of the vulnerabilities detected during information gathering and code analysis, this approach helps to discover serious vulnerabilities such as:
-
Authentication bypass: bypassing the login feature into protected activities and features.
-
Authorization bypass: A user can attack his own app to achieve parts of the is not allowed to. Each one of us wishes for this vulnerability when we are stuck at game level we cannot pass!
-
User unaware features: causing the app to do any action that is not triggered by the user. A malicious app on the same device can exploit such vulnerabilities to manipulate user data or do actions on his behalf
-
App crash: Improper intent messages could cause an app to crash. This can be a big problem for high availability apps.
AndroTickler sets default values of the intent extras. Since you might want to try specific extra value with an intent, AndroTickler prints every intent it sends to the app. You can simply copy and modify it in an adb shell. Furthermore, AndroTickler terminates the app after each intent it sends, to ensure that any unexpected behavior of the app is certainly due to the latest intent.
As an example, the following command tickles only the exported components and also collects logcat messages during tickling session:
java -jar AndroTickler.jar -pkg <package_name> -t -exp -log
Tickling with Frida
Frida is a powerful tool to hook to Android apps (among others) and manipulate their behavior in real-time. There are many reasons for pentesters to manipulate Android apps, such as disabling root detection or certificate pinning on the fly, without the bother of modifying the app’s code, recompiling and reinstalling the app. Frida should already be installed on your machine and you need to specify the location of Frida server on your Android device in the Tickler.conf file.
Frida_server_path = /data/local/tmp/frida-server-10.6.26-android-arm
AndroTickler uses Frida to show the parameters and return values of any method (or manipulate any of them), in the following cases:
-
If the parameter/return value is of primitive type (int, bool, etc).
-
If the method is not overloaded.
A single AndroTickler command creates a JS file in fridaScripts/ directory. Therefore, even if the following conditions are not met. You can modify the generated JS file in fridaScripts/. Then you can run the same AndroTickler command with a -reuse flag, to execute the modified file. Additionally, you can also run any Frida JS script using -frida script <script_location>command.
A collective example
Let’s assume the following simple scenario. When searching for rooted in the code using -sc rooted command, the following hit is returned
#FileName: [Java_Code_Dir]/de/notenaf/myApp/RootChecks.java
private boolean isRooted(String path) {
A method that checks if the device is rooted …. looks interesting! So by checking the decompiled method in the above location, we find that this method searches for su binary in location String. So to circumvent this root check, we could either:
1) Change the parameter of this method to “/tmp” where there is no su binary, using the following command
java -jar AndroTickler.jar -pkg de.notenaf.myApp -frida set de.notenaf.myApp.RootChecks isRooted 1 0 “/tmp/”
- set to modify a value
- de.notenaf.myApp.RootChecks is the class name
- isRooted is the method name
- 1 is the number of argument
- 0 is the index of the argument to change (as in args[0])
- “/tmp” is the new value
2) Change the return value to false
java -jar AndroTickler.jar -pkg de.notenaf.myApp -frida set de.notenaf.myApp.RootChecks isRooted 1 1 false
where
- First 1: is the number of arguments
- Second 1: is the index of the argument. Since there is only 1 argument and no args[1], then the target here is the return value. In general, any number >= number of arguments would address the return value
I know the commands seem a bit complicated, but please keep in mind that this line replaces writing a whole script 🙂
Other functionalitites
Some people prefer old school app manipulation, as in decompiling, modifying, rebuilding, signing then installing the app. AndroTickler makes that as simple as possible for pentesters. The app is already decompiled at its first run and extracted to extracted directory. A pentester can duplicate this directoy and apply the changes he needs, such as modifying the app’s smali code or replacing the pinned certificates with his own. Then AndroTickler will do the rest. -apk command builds the modified app with ApkTool, signs the app then asks the user if he wants to install the new version of the app. If yes, AndroTickler’s directory of the app will be backed up to <package_name>_timestamp directory and the new app is installed. Note that AndroTickler needs jarsigner to sign the new app.
java -jar AndroTickler.jar -pkg <package_name> -apk <modified_directory> <newApkname.apk>
To debug an app on a device, the debuggable flag in its Manifest file should be set to true. Using -dbg command, AndroTickler creates a debuggable version of the app, signs and install it as explained above. Moreover, to test if the app allows background snapshot vulnerability, which might disclose sensitive data to a root privileged attacker. -bg pulls the snapshots captured of all apps to bgSnapshots directory.
And finally
That was a quick review on the functionalities of AndroTickler. I hope you find it helpful in your pentesting and I appreciate all your comments, suggestions and questions 🙂
If you reach this line then you’re already a mobile security fan 🙂 Our Troopers 18 conference in Heidelberg presents some interesting talks in this field such as Mobile App Security Fails and How To Survive Them and Hunting Android Malware: A novel runtime technique for identifying malicious applications.
Have a nice weekend!
Ahmad