Allsafe is an intentionally vulnerable application that contains various vulnerabilities. Unlike other vulnerable Android apps, this one is less like a CTF and more like a real-life application that uses modern libraries and technologies. Additionally, I have included some Frida based challenges for you to explore. Have fun and happy hacking!
I have my Frida scripts (more like templates) in other repository. I’m sure they might be quite handy for the Frida related tasks. Check it out: https://github.com/t0thkr1s/frida
frida
This repository contains various Frida scripts for Android application penetration testing. I created this project to demonstrate the capabilities of the Frida dynamic-analysis framework. You can read my “Introduction to Frida” blog post on Medium, where I’m explaining how to use Frida with Android.
Introduction To Frida
Frida is a dynamic instrumentation toolkit for developers,
reverse-engineers, and security researchers.
Project Requirements
Required tools to follow along:
- Java decompiler (JD-GUI)
- Android emulator (Genymotion)
- Dynamic instrumentation toolkit (Frida)
You’ll need to download 3 files from here: https://github.com/frida/frida/releases
- Python-frida
- Python-frida-tools
- Frida-server-android
Depending on your distribution, you can easily install the first two and their dependencies. As for the frida-server-android, I’m going to walk you through the installation and emulator setup.
The Android Application
I created an Android application just for demonstration and testing purposes. I’m going to use it during the examples, you can download it from here:
https://github.com/t0thkr1s/frida
Download
You can simply clone the repository or head over to the releases page to download the Frida scripts.
git clone https://github.com/t0thkr1s/frida
Install
You must have Frida installed on your system. You can simply do this with
pip3 install frida-tools
Creating A Virtual Device
I added a new Genymotion virtual device with Android version 5.0 (API 21).
The setup is pretty straightforward just the usual next, next and finish. It’s time to download the Frida Server for the Android client. Don’t forget to check the correct architecture! Next, we need to upload the server to the emulator. I installed Genymotion in the /opt directory
t0thkr1s@btksoftware:/opt/genymobile/genymotion/tools$ ls
aapt adb glewinfo lib64
Uploading the file
./adb push ~/Downloads/frida_server /data/local/tmp/
Changing file permissions
./adb shell “chmod 755 /data/local/tmp/frida_server”
Running the server in detached mode
./adb shell “/data/local/tmp/frida_server &”
Now, the emulator is ready and the server is running!
Reverse Engineering
In order to understand the inner workings of an application, we need to reverse engineer it. Fortunately, we can restore the java source files easily.
I’m not going to write about reverse engineering Android apps here, because I already did it in my previous post.
I have to admit that the reverse engineering of the demo application reveals all the secrets hidden in it. So, in order to make it more realistic let’s suppose the encryption key is generated from the user-provided PIN code which is used to encrypt private data in the app.
In this case, brute-forcing the PIN code might be a good solution for compromising the security of the whole app. That’s why you need to choose long and strong PINs.
PIN Bypass
Okay, you looked through the reversed source code and you found a method, which checks if the provided PIN is correct or not.
Spoiler: The PIN is in the strings.xml file.
Most of the time, it’s not that easy… Let’s suppose, we don’t know the PIN. You found the PinUtil class and the boolean checkPin(String pin) method. This checks the pin and returns true if the pin is correct, otherwise, it returns false.
The idea here is that we don’t need to know the pin just return true and we’re in. The following python script does just like that. I wrote a little Javascript code using the Javascript API and hardcoded it in the python script. Basically, it uses the PinUtil’s checkPin() method and overrides the return value. It’s that easy. Next, you need to specify the package name of the application to attach Frida, then load the script and wait for the log messages.
import frida, sys
jscode = “””
Java.perform(function() {
console.log(“[ * ] Starting implementation override…”)
var MainActivity = Java.use(“infosecadventures.fridademo.utils.PinUtil”);
MainActivity.checkPin.implementation = function(pin){
console.log(“[ + ] PIN check successfully bypassed!”)
return true;
}
});
“””
process = frida.get_usb_device().attach(‘infosecadventures.fridademo’)
script = process.create_script(jscode)
print(‘[ * ] Running Frida Demo application’)
script.load()
sys.stdin.read()
PIN Brute-force
Previously, I mentioned that knowing the PIN could be really beneficial. In this example, I going to show you how to brute-force with Frida.
First, let’s suppose that the PinUtil’s checkPin(String pin) method is not static. By using Java.choose, we can search the memory for a PinUtil instance and the onMatch is called when the instance is found. Then, we can use that instance’s methodin a loop to test all numbers with a length of 4. This is actually not a time-consuming process. You can even try brute-forcing numbers with a length of 5 and finish in a day depending on the number.
The PinUtil’s class checkPin(String pin) function is static. This means that we don’t need to search for the PinUtil object in the memory just call the method using the class name. However, I implemented both (static and non-static solution) in the script below. I hope it’s not confusing. The jscode variable will be overridden by the second assignment and that will be used.
import frida, sys
# For non-static classes
jscode = “””
Java.perform(function() {
console.log(“[ * ] Starting PIN Brute-force, please wait…”);
Java.choose(“infosecadventures.fridademo.utils.PinUtil”, {
onMatch: function(instance) {
console.log(“[ * ] Instance found in memory: ” + instance);
for(var i = 1000; i < 9999; i++){
if(instance.checkPin(i + “”) == true){
console.log(“[ + ] Found correct PIN: ” + i);
}
}
},
onComplete: function() { }
});
});
“””
# For static classes
jscode = “””
Java.perform(function () {
console.log(“[ * ] Starting PIN Brute-force, please wait…”)
var PinUtil = Java.use(“infosecadventures.fridademo.utils.PinUtil”);
for(var i=1000; i < 9999; i++)
{
if(PinUtil.checkPin(i+””) == true){
console.log(“[ + ] Found correct PIN: ” + i);
}
}
});
“””
process = frida.get_usb_device().attach(‘infosecadventures.fridademo’)
script = process.create_script(jscode)
print(‘[ * ] Running Frida Demo application’)
script.load()
sys.stdin.read()
Root Check Bypass
I included this example because it’s quite common in banking and other applications to restrict rooted device access. It’s a simple check and very, very similar to the PIN bypass example.
I encourage you to write the script yourself and check back, when you finished!
Finding The Encryption Key
Now, everything in this script should also be familiar to you. You can log a method’s incoming parameters and return normally. This way, we have the ability to log the encryption key used and also the plain text. Again, the key is hardcoded in the code, but you won’t always be this lucky in real life. Here is how I implemented this:
import frida, sys
jscode = “””
Java.perform(function() {
console.log(“[ * ] Starting implementation override…”)
var EncryptionUtil = Java.use(“infosecadventures.fridademo.utils.EncryptionUtil”);
EncryptionUtil.encrypt.implementation = function(key, value){
console.log(“Key: “);
console.log(key);
console.log(“Value: “);
console.log(value);
return this.encrypt(key, value);
}
});
“””
process = frida.get_usb_device().attach(‘infosecadventures.fridademo’)
script = process.create_script(jscode)
print(‘[ * ] Running Frida Demo application’)
script.load()
sys.stdin.read()
Tasks / Vulnerabilities
Insecure Logging
Simple information disclosure vulnerability. Use the logcat
command-line tool to discover sensitive information.
Resources & HackerOne Reports:
- Logcat Tool
- Coinbase OAuth Response Code Leak
Hardcoded Credentials
Some credentials are left in the code. Your task is to reverse engineer the app and find sensitive information.
Resources & HackerOne Reports:
- Zomato Hardcoded Credentials
- 8×8 Hardcoded Credentials
- Reverb Hardcoded API Secret
Root Detection
This is purely for Frida practice. Make the code believe that you device is not rooted!
Arbitrary Code Execution
Loading modules securely with third-party apps are not easy. Write a PoC application and exploit the vulnerability!
Resources & HackerOne Reports:
- Arbitrary Code Execution via Third-Party Package Contexts
Secure Flag Bypass
Another Frida-based task. No real vulnerability here, just have fun bypassing the secure flag!
Resources & HackerOne Reports:
- Android FLAG_SECURE Reference
Certificate Pinning Bypass
Certificate pinning is implemented using the OkHttp library. You have to bypass it in order to view the traffic with Burp Suite.
Resources & HackerOne Reports:
- Certificate and Public Key Pinning
- Coinbase Vulnerabilities
Insecure Broadcast Receiver
There’s a vulnerable broadcast recevier in the application. Trigger it with the correct data and you’re done!
Resources & HackerOne Reports:
- Android Broadcasts Overview
- ok.ru Broadcast Receiver Exploitation
- Bitwarden Vulnerable Broadcast Receiver
Deep Link Exploitation
Similar to the insecure broadcast receiver, you need to provide the right query parameter to complete this task!
Resources & HackerOne Reports:
- Android Deep Linking
- Grab Insecure Deep Link
- Periscope Deep Link CSRF
SQL Injection
Just a regular SQL injection that you’d find in web applications. No need to reverse the code to bypass the login mechanism.
Resources & HackerOne Reports:
- SQL Injection in Content Provider
Vulnerable WebView
You can also complete this task without decompiling the application. Pop an alert dialog and read files!
Resources & HackerOne Reports:
- ownCloud WebView XSS
Smali Patching
In this task, you have to modify the execution flow of the application by editing the Smali code. Finally, rebuild and sign the APK!
Resources & HackerOne Reports:
- Uber APK Signer
Native Library
The application uses a native library that validates the entered password. Reverse engineer the library to find the password then use Frida to hook the native method.
Resources & HackerOne Reports:
- Ghidra
- Cutter