Skip to content

In this article I find vulnerabilities in an app called Allsafe. You can get it from the GitHub repo below:

GitHub - t0thkr1s/allsafe-android: Intentionally vulnerable Android application.
_Intentionally vulnerable Android application. Contribute to t0thkr1s/allsafe-android development by creating an account…_github.com

Insecure Logging

I begin by running the adb logcat command to read the logs. When we enter a secret, it gets logged, making it vulnerable to a loss of confidentiality.

Reference: MASWE-0001: Insertion of Sensitive Data into Logs

Hardcoded Credentials

When we open the fragment, we are tasked with reverse engineering the application to retrieve the username:password combination. I use the jadx allsafe.apk command to decompile the application, and then I use VS Code to read the files.

The first thing I see is a SOAP API request body, where the hardcoded username and password are clearly visible in the code.

Reference: M1: Improper Credential Usage

Firebase Database

The Firebase database URL and other details, such as API keys, are stored in the strings.xml file under the /res/values folder.

In Firebase, when you visit a database URL with the /.json endpoint, you can see the entire database in JSON format. When we navigate to https://allsafe-8cef0.firebaseio.com/.json, we can find the flag and secret there.

Reference: M8: Security Misconfiguration

Insecure Shared Preferences

This section covers using shared preferences to store sensitive information. When we navigate to /data/data/infosecadventures.allsafe/shared_prefs, we see that a user.xml file has been created.

This file is used to store user data in an insecure way. To protect sensitive data, developers should store cryptographic material in the Android Keystore, use EncryptedSharedPreferences if preferences must persist, and implement session tokens with expiration instead of persisting passwords.

Reference: MASWE-0006: Sensitive Data Stored Unencrypted in Private Storage Locations

SQL Injection

In this section, we are tasked with creating an SQLi payload to bypass authentication. I was able to bypass authentication using the following payload: test' OR 1=1 --

Reference: MASWE-0086: SQL Injection

PIN Bypass

In this section, we are tasked with writing a Frida script to override the return value of the PIN validation method. First, I run frida-server on my emulator, and then I locate the corresponding code to craft the script.

When I analyze the class infosecadventures.allsafe.challenges.PinBypass, I find that the PIN is checked in the checkPin method. It simply verifies whether the PIN equals a value that is Base64-encoded.

To make our work easier, we will use the documentation generated by Gemini to write a Frida script: docs.google.com

// Allsafe PIN Validation Bypass  
Java.perform(function () {  
  const PinBypassFragment = Java.use('infosecadventures.allsafe.challenges.PinBypass');  
  PinBypassFragment.checkPin.implementation = function (pin) {  
    return true; // Bypass the check by always returning true  
  };  
});
I then run our script using the command: frida -U -f infosecadventures.allsafe -l ./frida-pin-bypass.js When I enter a random pin, it allows me in.

Root Detection

In this section, we will craft a Frida script to bypass all root checks implemented by the application. Fortunately, they are not written as a .so library, which makes our job easier.

When we inspect the infosecadventures.allsafe.challenges.RootDetection class, we see that the application uses the com.scottyab.rootbeer package to handle root detection.

To simplify the process, I will use a Frida script created by ub3rsick to bypass the root detection implemented by RootBeer, as it makes our job much easier.

Reference: MASTG-KNOW-0027: Root Detection

Deep Link Exploitation

Here, we need to find a deep link associated with the app and then identify its parameter.

First, I navigate to the AndroidManifest.xml file to check the scheme. It is clear that the scheme is allsafe, and we've already found the endpoint /congrats. Now, we just need to focus on the parameter.

I accessed the deep link using the command: adb shell am start -W -a android.intent.action.VIEW -d allsafe://infosecadventures/congrats?a=1. The application responded with “No key provided!”, giving us a hint about the required parameter.

Then, I tried: adb shell am start -W -a android.intent.action.VIEW -d allsafe://infosecadventures/congrats?key=a and observed the response.

At this point, I decided to check the source code. The code verifies whether the key parameter matches the string defined in strings.xml. I located the key and used it in the new command: adb shell am start -W -a android.intent.action.VIEW -d allsafe://infosecadventures/congrats?key=ebfb7ff0-b2f6–41c8-bef3–4fba17be410c

Reference: MASTG-TEST-0028: Testing Deep Links

Insecure Broadcast Receiver

In the AndroidManifest.xml file, we see that the NoteReceiver class is exported.

We then check the source code of the application and identify the intent variables required to create the notification.

Based on these variables, we create a notification using adb and call the NoteReceiver with the following command:

adb shell am broadcast -n infosecadventures.allsafe/infosecadventures.allsafe.challenges.NoteReceiver — es “server” “prod.allsafe.infosecadventures.io” — es “notification_message” “test”

Reference: MASWE-0063: Insecure Broadcast Receivers

Vulnerable WebView

This section instructs us to exploit the vulnerability without reading the source code. For a vulnerable WebView, we need to look for a JavaScript-enabled WebView with no input sanitization or output encoding.

Using a simple payload: <script>alert(‘test’)</script> we were able to trigger an alert window.

For the second task, I noticed that when I enter a valid URL, it renders the HTML page.

I then decided to try file:///etc/hosts to check if it can fetch local files as well.

Reference: MASTG-BEST-0012: Disable JavaScript in WebViews

Certificate Pinning

Certificate pinning is a technique used to make it difficult for an attacker to intercept and view API traffic in mobile applications. To bypass the pinning, I use my Frida script to disable it.

Reference: MASTG-TECH-0012: Bypassing Certificate Pinning

Weak Cryptography

From the code, it is evident that the application is using AES encryption in ECB mode. In ECB mode, identical plaintext blocks produce identical ciphertext blocks, which can reveal patterns in the data.

Additionally, the encryption key is stored directly in the app code. Once the key is known, all encrypted messages can be easily decrypted.

Reference: MASTG-BEST-0005: Use Secure Encryption Modes

Arbitrary Code Execution

When we analyze the code, we find that the ArbitraryCodeExecution class has an invokeUpdate method, which is used to check whether the current application is outdated by invoking a class from allsafe_updater.apk stored in the Download folder.

To test this vulnerability, I developed a PoC application to obtain a reverse shell from the device:

https://gist.github.com/ayboraa/ee382a8307fe6c915a8384f1f5c3f32b

Here we got our reverse shell:

Native Library

Here, our goal is to bypass the native library method. I begin by loading the library in Ghidra for further analysis.

First, I find an exported method called checkPass and determine its offset: 0x000298b0

I then inspect the method and confirm that it returns a boolean value.

Assuming that it returns true if the password is correct, we will build our Frida script based on this information.

I have used my Frida script as shown below:

https://gist.github.com/ayboraa/ba974ec97cac7403390a98bc055ccd5e

And I was able to bypass native library check.

How does it work?

Wait for the library to load

  • Hooks Android’s dlopen functions to detect when libnative_library.so is loaded into memory.

Calculate the real function address

  • GHidra gives a static address (functionOffset) based on its analysis base (gHidraBaseAddress).
  • Runtime base address is obtained from the OS.
  • Actual memory address is calculated as:

realAddress = runtime_library_base + (GHidra_function_address - GHidra_base)

Hook the target function

  • Once the library is loaded, Frida attaches to the computed function address, allowing you to monitor or alter its behavior.

Hope you find this post helpful.