A Complete Guide to Pentesting Android Applications

Noah MugayaNoah Mugaya
25 min read

In today's mobile-driven world, Android applications are prime targets for attackers seeking to exploit security flaws. As a penetration tester, understanding the intricacies of Android security is crucial to identifying and mitigating vulnerabilities before they are exploited. In this comprehensive guide, we’ll walk through the steps involved in pentesting Android applications, provide practical examples, and use tools and techniques to highlight common vulnerabilities.

1. Android Architecture Overview

Understanding the core architecture of Android applications is fundamental when conducting a pentest. This knowledge helps identify potential attack surfaces that can be leveraged by an attacker. Let’s explore the critical components of Android’s architecture and how they might be targeted during a pentest.

Key Components of Android Architecture

  1. Activities
  • Definition: Activities are the individual screens that form the user interface (UI) of an Android application. Each activity can be thought of as a single, focused interaction that a user performs.

  • Potential Vulnerability: If an activity is not properly secured (e.g., marked as exported), an attacker could invoke that activity directly, even if it was intended to be restricted to internal use.

  • Practical Attack Example: Using Android Debug Bridge (ADB), an attacker could start an exported activity by executing:

  •     adb shell am start -n com.example.app/.SensitiveActivity
    
    • This command forces the app to open the specified activity, potentially exposing sensitive UI elements or data.

2. Services

  • Definition: Services are components that handle long-running operations in the background. They do not have a user interface but can perform critical tasks like fetching data, processing files, or interacting with remote servers.

  • Potential Vulnerability: Misconfigured services (especially those that are exported) can be exploited to perform unauthorized operations.

  • Practical Attack Example: A malicious app can invoke a service directly if it is not adequately protected. For example, using adb:

  •     adb shell am startservice -n com.example.app/.MyBackgroundService
    

This command forces the service to run without the user’s permission.

3. Broadcast Receivers

  • Definition: Broadcast receivers allow apps to listen for system-wide broadcast announcements (e.g., low battery warnings) or communications from other apps.

  • Potential Vulnerability: If poorly configured, a broadcast receiver can accept malicious broadcasts, leading to privilege escalation or triggering unintended behavior within the app.

  • Practical Attack Example: An attacker can inject a malicious broadcast into an app by using the following command:

      adb shell am broadcast -a com.example.app.MALICIOUS_INTENT
    

    If the app is not validating the broadcast properly, this could result in serious security issues such as unauthorized actions being performed.

    4. Content Providers

    • Definition: Content providers enable data sharing between different apps. They manage access to structured data, often using SQLite databases or files.

    • Potential Vulnerability: If a content provider is not secured (e.g., using proper permissions or restricting data access), it could allow unauthorized apps to access sensitive data.

    • Practical Attack Example: Using ADB, an attacker could attempt to query a content provider for sensitive data:

    •     adb shell content query --uri content://com.example.app.provider/Users
      

      This could potentially expose private user information if proper security measures aren’t in place.

    • Android Security Features

      1. Sandboxing

        • What It Is: Each Android app runs in its own isolated environment (sandbox), preventing unauthorized access to the data and resources of other apps.

        • Importance: While sandboxing adds a layer of security, misconfigurations or vulnerabilities in the app (such as incorrect file permissions) can still allow data leakage or unauthorized access to other apps' data.

        • Example Misconfiguration: If an app stores sensitive data in a world-readable file, other apps on the device can read that file, bypassing the intended security of the sandbox.

      2. Permissions Model

        • What It Is: Android apps must request permissions to access certain system resources or user data. These permissions are either requested at install time or runtime, depending on the Android version.

        • Importance: It's crucial to review the permissions requested by an app during a pentest. Apps that request excessive permissions (e.g., access to contacts, camera, or storage without need) increase the attack surface.

        • Example Analysis: You can use tools like apktool to analyze the AndroidManifest.xml file to check for excessive permission requests:

        •     apktool d app.apk -o extracted_app
          
  • Look for permissions like READ_CONTACTS, ACCESS_FINE_LOCATION, and INTERNET. If the app doesn’t need these permissions, it could be a red flag for potential abuse.

Android App Sandboxing and Data Protection

  1. Sandboxing Explained:

    • Each Android app operates within a tightly controlled environment known as a sandbox, which isolates it from other apps on the system. The operating system ensures that apps can only access their own data and cannot interact with the private data of other apps.

    • However, data leakage can occur if developers fail to properly secure internal files, use insecure storage mechanisms, or share data between apps without proper validation.

  2. File and Data Storage Security:

    • Data stored within an app should always be protected, especially if it's sensitive. Developers need to be cautious when using internal storage, external storage, or shared preferences. Misconfigured file permissions can expose sensitive data like user credentials, payment information, or personal identification numbers (PINs).

example

  •     adb shell ls /data/data/com.example.app/shared_prefs/
        adb shell cat /data/data/com.example.app/shared_prefs/UserData.xml
    
    1. If sensitive information such as passwords is stored in plain text, it could easily be retrieved by an attacker who has access to the device or its backup files.

Common Misconfigurations and How to Detect Them

  1. Exported Activities and Services

    • Misconfiguring activities and services by setting the exported attribute to true in the AndroidManifest.xml allows attackers to directly invoke these components from other apps.

    • During a pentest, it's critical to analyze the manifest file for such misconfigurations. By using tools like Drozer or manually reviewing the APK, you can discover potentially exploitable components.

  2. Insecure Inter-App Communication

    • Android apps often communicate with one another using intents, but if these intents are not properly secured (e.g., by using custom permissions or validating the intent data), attackers can inject malicious data or intercept sensitive information.

Example of Intent Hijacking:

        adb shell am start -a android.intent.action.SEND -d "malicious_data"

This could hijack an intent meant for a secure communication channel and lead to privilege escalation or data leaks.

  • 2. Setting Up Your Pentesting Environment

    Creating a robust and effective pentesting environment for Android applications requires the right tools and configurations. Here’s a comprehensive guide to setting up your pentesting environment, including the essential tools and step-by-step setup instructions.

    Required Tools for Android Pentesting

    1. Android Studio

      • Purpose: Android Studio is the official integrated development environment (IDE) for Android development. It’s essential for running emulators and analyzing the application’s behavior.

      • Download Link: Download Android Studio

    2. ADB (Android Debug Bridge)

      • Purpose: ADB is a versatile command-line tool that allows you to interact with Android devices or emulators from your computer. It is used for tasks such as app installation, device manipulation, and accessing the Android file system.

      • Installation: ADB comes bundled with Android Studio, so installing Android Studio will also install ADB.

    3. Burp Suite

      • Purpose: Burp Suite is a powerful tool for intercepting and analyzing HTTP/S traffic. It’s critical for testing network communication in Android apps.

      • Download Link: Download Burp Suite

    4. Frida

      • Purpose: Frida is a dynamic instrumentation toolkit that allows you to inject custom scripts and manipulate app behavior in real-time. It’s useful for bypassing security controls and exploring app internals.

      • Download Link: Download Frida

Setting Up the Tools

  1. Install Android Studio

    • Download and Install: Visit the Android Studio website and download the installer suitable for your operating system. Follow the installation instructions to complete the setup.

    • Create and Run Emulators:

      1. Open Android Studio.

      2. Navigate to "AVD Manager" (Android Virtual Device Manager) from the toolbar or menu.

      3. Click on "Create Virtual Device" and follow the setup wizard to configure your emulator. Choose a device profile and a system image for the emulator.

      4. Once created, you can start the emulator by selecting it and clicking "Play".

  1. ADB Configuration
  • Verify ADB Installation: Open a terminal or command prompt and check if ADB is correctly installed by listing connected devices:

  •     adb devices
    
    • This command should display a list of connected devices or emulators.

    • Launch Interactive Shell: To explore the file system of an emulator or device, launch an interactive shell:

    •     adb shell
      
    • This allows you to navigate the file system, access logs, and perform other actions on the device.

  • 3. Intercepting Traffic with Burp Suite

    • Configure Burp Suite:

      1. Open Burp Suite and go to the "Proxy" tab.

      2. Under "Options", configure the proxy listener to bind to a specific port (e.g., 8080).

    • Set Up Android Emulator to Route Traffic Through Burp:

      1. Open the emulator’s settings.

      2. Navigate to "Network & Internet" > "Wi-Fi" and select the connected network.

      3. Tap "Advanced" and then "Proxy".

      4. Set the proxy to "Manual" and enter the IP address of your computer (you can find this using the ipconfig command on Windows or ifconfig/ip a on Linux) and the port number you configured in Burp Suite (e.g., 8080).

  • Test Traffic Interception:

    1. In Burp Suite, go to the "Proxy" tab and ensure that intercept is turned "On".

    2. Open an app on the emulator and perform actions that generate network traffic.

    3. Check Burp Suite’s "HTTP history" to see if the traffic is being captured and intercepted.

    • Using Frida for Dynamic Instrumentation
  • Install Frida: Follow the installation instructions on the Frida website. Typically, you’ll install Frida on your host machine using pip:

  •     pip install frida-tools
    

Inject Scripts: You can use Frida to dynamically instrument an app. For example, to inject a script into a running app:

  •     frida -U -p <PID> -l my_script.js
    

    Here, <PID> is the process ID of the app you want to target, and my_script.js is the script you wish to run.

3. Reverse Engineering Android Applications

Reverse engineering Android applications is a critical step in understanding how an app functions internally. This process helps identify hidden functionality, hardcoded credentials, and potential security weaknesses. By decompiling an APK (Android Package), you can gain insights into the app’s structure and logic. This section covers the essential tools and techniques for decompiling and analyzing Android applications.

Decompiling APKs

Decompiling involves converting an APK file into a more understandable format, such as source code or intermediate code, so you can analyze its functionality and security.

  1. Apktool

    • Purpose: Apktool is a powerful tool for decompiling APK files into smali code. Smali is an assembly-like language used for Android applications, representing the bytecode of the APK.

    • Installation: Download Apktool from the official website. Follow the installation instructions provided there.

    • Usage:

    •     apktool d app.apk -o extracted_app
      

      This command decompiles the APK file app.apk into a folder named extracted_app. The folder will contain the app’s resources and smali code, allowing you to examine the app’s internal structure.

  2. JADX

    • Purpose: JADX is a tool that decompiles Android bytecode into Java source code, making it easier to read and understand. It is particularly useful for identifying hardcoded API keys, sensitive logic, and weak encryption.

    • Installation: Download JADX from the official GitHub repository. You can use the GUI version for an interactive experience.

    • Usage:

    •     jadx-gui app.apk
      

      This command opens the GUI version of JADX, where you can explore the decompiled Java source code of the APK.

    • example

Analyzing Decompiled Code

Once you have decompiled the APK using Apktool and JADX, the next step is to analyze the extracted code and resources.

  1. Identifying Hardcoded Credentials

    • Look for API keys, tokens, or passwords directly embedded in the source code. These can often be found in configuration files or within Java classes.

    • Example: In the decompiled Java code, you might find something like:

    •     String apiKey = "YOUR_API_KEY_HERE";
      

      This is a potential security risk if the key is exposed in the source code.

  2. Examining Security Implementations

    • Review how encryption and data protection mechanisms are implemented. Look for any weak or outdated encryption algorithms, or hardcoded cryptographic keys.

    • Example:

    •     SecretKeySpec keySpec = new SecretKeySpec("1234567890123456".getBytes(), "AES");
      

      This shows a hardcoded encryption key, which can be a security vulnerability.

  3. Checking for Obfuscation

    • Many developers use code obfuscation to make reverse engineering more difficult. Analyze the code for obfuscation patterns and attempt to deobfuscate if necessary.

    • Example: Obfuscated variable names like a1, b2, etc., may indicate the use of obfuscation tools.

4. Static Analysis

Static analysis involves scrutinizing an app's source code or decompiled output without executing it. This method helps identify potential security issues such as hardcoded credentials, weak encryption, and insecure configurations. This section covers key aspects of static analysis, including practical examples and advanced techniques.

Searching for Hardcoded Credentials

Hardcoded credentials in source code are a significant security risk. These can include API keys, passwords, or access tokens embedded directly in the code.

Example: Finding Hardcoded API Keys

Imagine you’re analyzing a decompiled Java file and come across a line like this:

String apiKey = "12345-ABCDE";

Such hardcoded API keys can expose the application to unauthorized access if they’re not properly protected. To identify these vulnerabilities, you can use various search methods:

  • Using grep on the Command Line

    If you have extracted the APK and have access to the smali or Java files, you can search for hardcoded keys using grep:

  •     grep -r "apiKey" extracted_app/
    
    • This command searches recursively through the extracted APK directory for the term "apiKey," which can help locate hardcoded values.

    • Using JADX for In-Depth Analysis

      In JADX, you can use the built-in search functionality:

      1. Open the APK in JADX GUI.

      2. Press Ctrl+F (or Cmd+F on Mac) to open the search dialog.

      3. Enter keywords such as apiKey, password, or token to find hardcoded values.

Example of Search Result:

Checking for Insecure Data Storage

Android applications often use various methods for storing sensitive data, such as SharedPreferences, local databases (e.g., SQLite), or internal files. Poorly protected storage can lead to data leakage.

Example: Storing Passwords in SharedPreferences

Consider the following Java code snippet that uses SharedPreferences:

  •     SharedPreferences prefs = getSharedPreferences("userPrefs", Context.MODE_PRIVATE);
        String password = prefs.getString("password", null);
    

    In this example, passwords are stored in plain text within SharedPreferences, which is vulnerable to extraction by any user or malicious app with access to the device's storage. Here’s how you can identify such issues:

  • Review SharedPreferences Usage:

    Search for instances of getSharedPreferences and putString in the decompiled code to check how sensitive data is stored.

    Example Search:

  •     grep -r "getSharedPreferences" extracted_app/
    

    Analyze SQLite Databases:

    Look for SQLite database creation and usage within the decompiled code. Databases storing sensitive information should be secured with encryption.

    Example Code:

  •     SQLiteDatabase db = openOrCreateDatabase("appDB", Context.MODE_PRIVATE, null);
    
  • Ensure that databases are not storing sensitive data unencrypted.

  • Inspect Internal File Storage:

    Check if sensitive files are being saved in the app’s internal storage without encryption.

    Example Code:

  •     FileOutputStream fos = openFileOutput("sensitive_data.txt", Context.MODE_PRIVATE);
        fos.write(data.getBytes());
    
    • Ensure that sensitive data is encrypted or otherwise protected.

Advanced Static Analysis Techniques

  1. Code Analysis Tools:

    Utilize specialized static analysis tools like FindBugs or PMD for more comprehensive code analysis. These tools can detect common coding errors and potential security vulnerabilities.

  2. Manual Code Review:

    Sometimes automated tools might miss context-specific issues. Conduct a thorough manual review of the decompiled code to identify unconventional vulnerabilities or insecure coding practices.

  3. Code Obfuscation:

    If the code appears obfuscated, use tools like Procyon or CFR to help deobfuscate the code for better readability.

     java -jar procyon-decompiler.jar -jar app.apk
    

5. Dynamic Analysis

Dynamic analysis involves running and interacting with an application to observe its real-time behavior. This approach provides insights into how the app processes data, manages network communications, and handles user interactions. By monitoring these aspects, you can identify security vulnerabilities that are not apparent through static analysis alone. This section will cover several dynamic analysis techniques, including intercepting network traffic, bypassing SSL pinning, and analyzing runtime behavior with Frida.

Intercepting Traffic with Burp Suite

A common vulnerability in Android apps is insecure communication, which can expose sensitive data during transmission. Burp Suite is a powerful tool for intercepting and analyzing HTTP/HTTPS traffic, allowing you to see how data is transmitted between the app and its backend services.

Example: Intercepting an API Request

  1. Set Up Burp Suite Proxy:

    • Launch Burp Suite and navigate to the "Proxy" tab.

    • Go to "Options" and configure the proxy listener (usually running on 127.0.0.1:8080).

  1. Configure Android Emulator to Use Burp Suite:

    • On your Android emulator or device, navigate to Settings > Network & Internet > Wi-Fi.

    • Long-press on your connected network and select "Modify network."

    • Set the proxy settings to manual, entering the IP address and port where Burp Suite is listening.

Example Network Configuration:

        Proxy hostname: 127.0.0.1
        Proxy port: 8080

3. Intercept and Analyze API Requests:

Once Burp Suite is configured, perform actions in the app that generate network requests. Burp Suite will capture these requests.

Intercepted API Request

  •     POST /api/login HTTP/1.1
        Host: api.example.com
        Content-Type: application/json
    
        {
           "username": "testuser",
           "password": "password123"
        }
    
    1. In this example, sensitive credentials (username and password) are transmitted in plaintext. This exposure can be exploited by attackers if the communication is not secured.

      Burp Suite Analysis:

      • Examine request headers and body for sensitive data.

      • Test for common vulnerabilities such as improper validation or lack of encryption.

Bypassing SSL Pinning with Frida

SSL pinning is a security measure used to prevent man-in-the-middle (MITM) attacks by ensuring that the app only trusts specific certificates. Bypassing SSL pinning allows you to intercept HTTPS traffic even when SSL pinning is enforced.

Example Frida Script to Bypass SSL Pinning

  1. Set Up Frida:

    • Install Frida from the Frida website or via package managers like pip:

    •     pip install frida-tools
      
  2. Write and Run Frida Script:

    Use the following Frida script to bypass SSL pinning in an app that uses the okhttp3 library:

     Java.perform(function() {
         var CertificatePinner = Java.use("okhttp3.CertificatePinner");
         CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {
             console.log("[+] Bypassing SSL Pinning");
             return;
         };
     });
    
  • Save the script as bypass_ssl_pinning.js.

  • Use Frida to inject the script into the target application:

  •     frida -U -f com.example.app -l bypass_ssl_pinning.js
    
    1. This script overrides the SSL pinning method to bypass certificate checks. This allows Burp Suite to intercept HTTPS traffic that would otherwise be protected by SSL pinning.

      Frida Script Execution:

      • Observe the logs for the message [+] Bypassing SSL Pinning to confirm the bypass is working.

      • Use Burp Suite to capture and analyze the now-intercepted HTTPS traffic.

Advanced Dynamic Analysis Techniques

  1. Dynamic Data Analysis with Frida

    Frida can also be used to monitor and modify data at runtime. You can hook into specific methods to inspect or alter data as it is processed by the app.

    Frida Script to Monitor Sensitive Data:

     Java.perform(function() {
         var SomeClass = Java.use("com.example.app.SomeClass");
         SomeClass.someMethod.implementation = function(param) {
             console.log("[*] Original param: " + param);
             var result = this.someMethod(param);
             console.log("[*] Result: " + result);
             return result;
         };
     });
    
  • This script hooks into someMethod of SomeClass and logs its parameters and return values. This technique can help identify how sensitive data is processed and whether it is exposed insecurely.

2. Memory Analysis

  • Use tools like Android Debug Bridge (ADB) to dump the memory of a running process. This can help uncover sensitive information that might be stored in memory, such as encryption keys or credentials.

    ADB Commands:

    • Dump Memory

    •     adb shell dumpsys meminfo com.example.app > meminfo.txt
      
      • Inspect Memory for Sensitive Data:

        Analyze meminfo.txt for any sensitive information that might be stored in memory.

3. App Behavior Analysis

Use tools like Xposed Framework to modify app behavior at runtime. This can be useful for testing how changes in code affect the app's functionality and security.

Xposed Module to Log Sensitive Data:

  •     // Inside an Xposed module
        @Override
        public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
            if (lpparam.packageName.equals("com.example.app")) {
                XposedHelpers.findAndHookMethod("com.example.app.SensitiveClass", lpparam.classLoader, "sensitiveMethod", String.class, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        String sensitiveData = (String) param.args[0];
                        XposedBridge.log("Sensitive Data: " + sensitiveData);
                    }
                });
            }
        }
    

This module logs sensitive data being processed by the sensitiveMethod in SensitiveClass.

Summary

Dynamic analysis is a vital part of Android pentesting, providing insights into how an app functions in real-time. By intercepting network traffic with Burp Suite, bypassing SSL pinning with Frida, and using advanced techniques like runtime data manipulation and memory analysis, you can identify and exploit vulnerabilities that are not visible through static analysis alone. These methods help ensure a thorough assessment of an app's security, allowing you to uncover and address potential risks effectively.

6. Testing Common Vulnerabilities

In this section, we’ll explore how to identify and exploit common vulnerabilities in Android applications. From insecure data storage to WebView vulnerabilities, we’ll cover various aspects of Android pentesting, providing practical examples and advanced techniques to deepen your understanding.

Insecure Data Storage

Insecure data storage is one of the most frequent issues found in Android apps. Apps often store sensitive information, such as passwords, API keys, or session tokens, in locations that can be accessed by attackers, either through insecure mechanisms (e.g., plaintext storage) or in insecure environments (e.g., external storage). Understanding how to locate and retrieve this information is critical to assessing an app's security.

Testing SharedPreferences for Sensitive Data

Android’s SharedPreferences is a convenient way to store small amounts of key-value data. However, if developers store sensitive data like passwords, tokens, or user preferences without encryption, it can easily be extracted.

Example: Extracting SharedPreferences Data

  1. Access the App’s SharedPreferences File:

    First, you need to locate the SharedPreferences file, which is typically stored in the /data/data/[package name]/shared_prefs/ directory on a non-rooted device.

     adb shell
     run-as com.example.myapp
     cat /data/data/com.example.myapp/shared_prefs/user_prefs.xml
    

    SharedPreferences XML:

     <map>
         <string name="username">user123</string>
         <string name="password">pass123</string>
     </map>
    

    This demonstrates a case where sensitive credentials are stored in plaintext.

  2. Mitigating Insecure Storage in SharedPreferences:

    Developers should avoid storing sensitive data in SharedPreferences without proper encryption. Consider using Android's EncryptedSharedPreferences to mitigate these risks.

Testing External Storage for Sensitive Data

Sensitive data stored on external storage is another major security issue. External storage is accessible by any app with the appropriate permissions, meaning attackers can easily access files saved in this location.

Practical Example: Extracting Data from External Storage

  1. Pulling App Data from External Storage:

    If the app stores sensitive files on external storage, you can retrieve them using the following ADB command:

     adb pull /sdcard/Android/data/com.example.myapp/files/
    

    Any sensitive files stored here, such as logs, configuration files, or cached data, can be easily accessed by malicious users

  2. Securely Storing Data:

    Developers should avoid using external storage for sensitive data. If necessary, the data should be encrypted using AES or another robust encryption algorithm.

WebView Vulnerabilities

Android’s WebView allows apps to display web content. However, if improperly implemented, WebView can expose apps to several vulnerabilities, including cross-site scripting (XSS) and insecure content loading.

Testing for JavaScript Injection in WebView

If an app fails to sanitize input to WebView, malicious code could be injected and executed, leading to XSS or other vulnerabilities.

Injecting Malicious JavaScript into WebView

<script>alert('XSS')</script>

If the WebView loads this code and an alert box is displayed, it indicates that the WebView does not properly sanitize or escape JavaScript inputs.

Testing WebView Settings for Insecure Configurations
  1. JavaScript Enabled: Enabling JavaScript in WebView increases the attack surface by allowing arbitrary JavaScript execution.

     WebView webView = findViewById(R.id.webview);
     WebSettings webSettings = webView.getSettings();
     webSettings.setJavaScriptEnabled(true);
    
    1. Allowing File Access: Some apps allow file access through WebView, which can be abused to load local files and potentially read sensitive information.
    webSettings.setAllowFileAccess(true);

Mitigation: Ensure JavaScript is disabled unless absolutely necessary and that file access is appropriately restricted.

7. Network Security

TLS/SSL Verification

Testing for proper implementation of TLS/SSL is essential to ensure that the app securely communicates over the network. Failure to enforce secure communication mechanisms can expose the app to man-in-the-middle (MITM) attacks.

  1. Check for Plaintext Communication:

    If the app uses HTTP instead of HTTPS, sensitive data is transmitted in plaintext. This can be intercepted using tools like Wireshark or Burp Suite.

    of an HTTP Request:

     POST /api/login HTTP/1.1
     Host: api.example.com
     Content-Type: application/json
    
     {
        "username": "testuser",
        "password": "password123"
     }
    
    • Mitigation: Always enforce HTTPS to secure data in transit.

      1. Testing for SSL Pinning:

Some apps implement SSL pinning to prevent MITM attacks by ensuring the app only trusts specific certificates. However, improper implementation or lack of SSL pinning can leave the app vulnerable.

Testing SSL Pinning Bypass with Frida:

Using Frida, you can bypass SSL pinning and intercept HTTPS traffic:

            Java.perform(function() {
                var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
                TrustManagerImpl.verifyChain.implementation = function() {
                    console.log("[+] SSL Pinning Bypassed");
                    return null;
                };
            });
Testing API Security

APIs are often the backbone of mobile applications. Vulnerabilities in APIs can lead to unauthorized access, data leakage, or account takeovers.

  1. Improper Authentication: Test if APIs allow access to endpoints without valid credentials.

  2. API Key Exposure: Look for hardcoded API keys in network traffic or logs.

  3. Authorization Flaws: Try accessing restricted resources by manipulating the API request, such as by changing the user ID.

    Example:

     GET /api/user/123 HTTP/1.1
     Host: api.example.com
    

    Modify the request to access another user’s data:

     GET /api/user/124 HTTP/1.1
    

    8. Root Detection and Bypass

    Many Android apps implement root detection to prevent unauthorized users from modifying the app or accessing restricted functionality. However, bypassing these checks is possible.

    Bypassing Root Detection with Magisk

    Magisk is a popular rooting solution that allows users to bypass root detection by hiding the root status of their device.

    1. Install Magisk on your device.

    2. Enable MagiskHide to hide root status from the app

       su
       magiskhide add [package_name]
      

      by enabling MagiskHide, the app will no longer be able to detect that the device is rooted.

      9. OWASP Mobile Top 10

      The OWASP Mobile Top 10 is a comprehensive framework for assessing mobile application security risks. By understanding these risks, you can systematically evaluate and mitigate vulnerabilities in your apps.

      1. M1: Improper Platform Usage:

        This issue refers to misconfigurations or improper use of Android’s platform features, such as improper permission handling, insecure use of intents, or failing to use Android’s security best practices (e.g., misusing the WebView component

        Example: Intent Spoofing

        Android’s intents can be hijacked if not properly secured. If you send sensitive data using an implicit intent, it could be intercepted by other apps.

        Improper use of Intent:

         Intent intent = new Intent();
         intent.setAction("com.example.SENSITIVE_ACTION");
         intent.putExtra("user_token", "123456");
         startActivity(intent);
        

        Here, an implicit intent with sensitive information (the user token) can be intercepted by any app registered to handle the SENSITIVE_ACTION.

        Mitigation:

        Use explicit intents or secure broadcast mechanisms like LocalBroadcastManager.

         Intent intent = new Intent(this, SecureActivity.class);
         intent.putExtra("user_token", "123456");
         startActivity(intent);
        
      2. M2: Insecure Data Storage:

        Sensitive data (such as passwords or tokens) should never be stored insecurely in files, SharedPreferences, databases, or external storage without encryption.

        Example: Storing Passwords in SharedPreferences

        A developer might store sensitive information in SharedPreferences without encryption:

         SharedPreferences prefs = context.getSharedPreferences("MyAppPrefs", Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = prefs.edit();
         editor.putString("password", "mySecretPassword");
         editor.apply();
        

        This can be easily accessed by an attacker using root privileges or ADB.

        Mitigation: Encrypt sensitive data before storing it. Use Android’s EncryptedSharedPreferences to ensure data is encrypted at rest.

         SharedPreferences encryptedPrefs = EncryptedSharedPreferences.create(
             "secure_prefs",
             masterKeyAlias,
             context,
             EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
             EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
         );
         SharedPreferences.Editor editor = encryptedPrefs.edit();
         editor.putString("password", "mySecretPassword");
         editor.apply();
        
      3. M3: Insecure Communication:

        Insecure communication occurs when apps transmit sensitive data without proper encryption (e.g., using HTTP instead of HTTPS). It makes the data vulnerable to man-in-the-middle (MITM) attacks.

        Example: Sending Data over HTTP

        If an app sends sensitive information using HTTP, it can be intercepted:

         URL url = new URL("http://example.com/login");
         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
         connection.setRequestMethod("POST");
         connection.setDoOutput(true);
        
         OutputStream os = connection.getOutputStream();
         os.write("username=admin&password=admin123".getBytes());
         os.close();
        

        This sends plaintext credentials over an insecure connection.

        Mitigation: Use HTTPS and ensure SSL pinning to avoid MITM attacks:

         URL url = new URL("https://example.com/login");
         // Ensure SSL Pinning is implemented to validate certificates.
        
      4. M4: Insecure Authentication:

        Insecure authentication involves weak or easily bypassed authentication mechanisms, such as using easily guessable passwords, weak password policies, or insecure token management.

        Example: Weak Password Policy

        An app allowing users to create weak passwords (e.g., "12345") without requiring complexity could be easily compromised.

        Mitigation: Enforce strong password policies:

         if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$")) {
             throw new IllegalArgumentException("Password must be 8 characters long, contain one uppercase, one lowercase letter, and one number.");
         }
        
      5. M5: Insufficient Cryptography:

        This vulnerability occurs when an app uses weak cryptographic algorithms or incorrectly implements cryptography, making sensitive data susceptible to attack.

        Example: Hardcoded Cryptographic Keys

        Storing cryptographic keys in the app’s source code can expose them to attackers during reverse engineering.

         String encryptionKey = "myHardcodedKey123";
         Cipher cipher = Cipher.getInstance("AES");
         SecretKeySpec keySpec = new SecretKeySpec(encryptionKey.getBytes(), "AES");
         cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        

        Mitigation: Keys should never be hardcoded. Use secure key storage mechanisms, such as the Android Keystore:

         KeyGenerator keyGen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
         keyGen.init(new KeyGenParameterSpec.Builder(
             "KeyAlias",
             KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
             .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
             .build());
        
      6. M6: Insecure Authorization:

        Insecure authorization occurs when an app’s backend doesn’t correctly verify that users are authorized to access specific resources or functionalities.

        Example: Bypassing Authorization

        If an API endpoint doesn’t properly check the user’s authorization, an attacker can access restricted resources by modifying requests.

         GET /api/user/1 HTTP/1.1
         Host: example.com
         Authorization: Bearer [user_token]
        

        Changing the user ID in the request (e.g., /user/2) might allow access to another user’s data if authorization checks are not properly implemented.

        Mitigation: Always validate the current user’s authorization on the server side, regardless of client inputs.

      7. M7: Poor Code Quality:

        Poorly written or poorly maintained code often leads to vulnerabilities such as buffer overflows, integer overflows, or improper memory management.

        Example: Buffer Overflow in C/C++ Code

        If your app uses native code, poor memory handling could introduce vulnerabilities.

         void vulnerableFunction(char *input) {
             char buffer[10];
             strcpy(buffer, input);  // If input > 10 bytes, it will overflow buffer
         }
        

        Mitigation: Use safe functions (e.g., strncpy instead of strcpy) and adopt proper input validation.

         strncpy(buffer, input, sizeof(buffer) - 1);
         buffer[sizeof(buffer) - 1] = '\0';
        
      8. M8: Code Tampering:

        Attackers may attempt to tamper with an app’s code (e.g., modifying APKs) to change functionality or bypass security features.

        Example: Verifying APK Integrity

        A developer might implement an integrity check to detect if the APK has been tampered with:

         Signature[] signatures = context.getPackageManager()
             .getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
        
         if (!knownSignature.equals(signatures[0].toCharsString())) {
             throw new SecurityException("App integrity check failed.");
         }
        

        Mitigation: Use APK signing, checksum verification, and code obfuscation to make tampering more difficult. Consider using ProGuard to obfuscate your code.

      9. M9: Reverse Engineering:

        Reverse engineering occurs when attackers decompile the app’s APK to reveal the source code, business logic, and security mechanisms. This can lead to vulnerabilities if sensitive information is exposed.

        Example: Using ProGuard for Code Obfuscation

        To protect your app from reverse engineering, you can use ProGuard to obfuscate your code:

         -keep class com.example.myapp.** { *; }
        

        This will scramble the method names and make it harder for attackers to understand the app’s logic after decompilation.

      10. M10: Extraneous Functionality:

        Sometimes, developers leave behind hidden features or debug functionalities that can be exploited by attackers (e.g., hardcoded admin features or test backdoors).

        Example: Hardcoded Debug Backdoor

        During development, a developer might add a secret debug menu that allows privileged access:

        if (BuildConfig.DEBUG) {
            openDebugMenu();
        }
        

        If not removed in production, this could provide attackers with elevated privileges or sensitive data.

        Mitigation: Always remove debug and test code from production releases.

Conclusion

Android pentesting is a multi-layered process requiring both static and dynamic analysis. From insecure data storage to improper authentication mechanisms, testing for common vulnerabilities requires thorough knowledge of the Android platform, tools, and methodologies. By leveraging techniques like intercepting traffic, bypassing root detection, and reverse engineering code, you can uncover hidden risks within Android applications. Moreover, referencing the OWASP Mobile Top 10 will ensure that you address the most critical security concerns during your assessments.

For successful pentesting, always follow ethical guidelines and ensure proper authorization before conducting any tests. As technology evolves, staying updated with the latest security practices and tools will enable you to stay ahead in mastering Android pentesting.

0
Subscribe to my newsletter

Read articles from Noah Mugaya directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Noah Mugaya
Noah Mugaya