These are the droids you’re looking for.
In 1969, with roughly 36 kilobytes of ROM and 2 kilobytes of RAM, the Apollo Guidance Computer landed three astronauts on the surface of the moon. This was an amazing feat enabled by, at the time, cutting-edge technology. Now, let’s compare those specifications with those of the device that your mom somehow beat Candy Crush with:
That is…
Despite the seemingly highly contested nature of the great blue vs. green text bubble war, Android is actually the leading mobile operating system worldwide, claiming 71.65% of the market share with over three billion active devices monthly. Google Play, the main app store for Android devices, saw $45 billion in consumer spending last year. With great revenue comes great bounties.
Android applications are files bundled as Android Package Kit (.apk) packages and can be recognized in a program’s scope by their reverse domain naming convention. Security assessments can be conducted by reviewing the code of an unpacked APK or by capturing the HTTP traffic an application generates.
Preface
Be aware that neither I nor Bugcrowd is liable for any malfunctions, failures, damage, loss/theft of data, or other technical issues that may occur with your device as a result of following this tutorial. Proceed at your own risk.
Also be aware that the names and locations of settings may vary between devices and versions. Pay attention to any prompts on a device itself when proceeding through these steps.
When selecting an application to practice these instructions on, consider using the SSL Pinning Demo application, as it allows you to send requests that use different types of security measures. With this functionality, you can quickly discover what you have successfully bypassed.
This will be, like, a lot. Since there are so many variables to Android hacking, you may have to go through some trial and error to determine which instructions apply to your specific device. These hurdles can potentially deter others from engaging with a specific program or application, leaving a less-tested attack surface for you.
Pro tip: Make all tools globally available by adding them to your system’s PATH environment variable, and make sure to restart your terminal so the updates take effect.
Pro tip: As per usual, replace all placeholder values, enclosed in angle brackets (<>), with the value appropriate to you.
Android Studio
To start, you will need to download and install Android Studio for your operating system.
Android Studio is the official integrated development environment (IDE) for developing Android applications.
The installation of Android Studio comes with several software development kits (SDKs), command-line tool packages, and the Android Emulator that can create a variety of Android Virtual Devices (AVDs) at specified API levels.
AVDs
System images that include Google Play in their build are signed with a release key and don’t allow root access, making certificate injection impossible. To capture HTTPS traffic generated by an application with Caido, avoid selecting any Google Play builds when creating an AVD. Also avoid Automated Test Device (ATD) builds, as they do not include all the components we will need.
Instead, use images listed as any of the following:
– Google APIs
– Android Open Source Project (AOSP)
– Default Android System Image
– Base versions (_Android x.x.x ()_)
Android Debug Bridge (adb)
The Android Debug Bridge (adb) tool, included in the Platform-Tools package, allows you to interface with an Android device using your computer’s terminal.
Pro tip: Configure your environment variables to make the command-line tools globally accessible.
To use adb
with your Android device, either physical or virtual, you will need to enable the Developer options in your device’s settings and then enable the USB debugging option.
Source: https://developer.android.com/studio/debug/dev-options
Once USB debugging is enabled:
- If you are using a physical device, connect your Android device to your computer over USB and verify the connection by running the command
adb devices
in your terminal. If the device is connected, it will be listed in the output of the command. - If you are using a virtual device, verify the connection by running the command
adb devices
in your terminal. If the device is connected, it will be listed in the output of the command.
Pro tip: For physical devices, if the command output lists the device as unauthorized, disconnect and reconnect the device, and then accept the Allow USB debugging? permission prompt on your device.
Configuring your device
If you are using a physical device, ensure the device is on the same Wi-Fi network as the computer running the HTTP proxy tool.
To configure your device to send its traffic through your HTTP proxy tool:
- Navigate to the device’s Wi-Fi settings and select the network SSID.
- Access the Advanced settings and select the Manual option from the Proxy dropdown menu.
- Set the Proxy hostname to 127.0.0.1 and the Proxy port to 8080. Adjust accordingly if you have changed the default listening address of your HTTP proxy tool.
- Click Save to set the configuration.
- Forward traffic from port 8080 on your device to port 8080 on your computer with
adb reverse tcp:8080 tcp:8080
Acquiring APKs
You can acquire APKs by downloading them from repositories such as apkmirror.com or apkpure.com.
To extract an APK from an application already installed on your device:
- Initialize a command-line interface on your Android device with:
adb shell
- Find the application’s base.apk package by listing all file paths of installed packages and filtering the results by the application’s name:
pm list packages -f | grep -i <application-name>
- Copy the location (excluding the =
<package-name>
portion of the output) and exit the device command-line interface using CTRL+D or by typing and entering exit. - Pull the base.apk from the device to your computer with:
adb pull </path/to/package>==/base.apk
Unpacking and repacking APKs
To unpack an APK into its individual files and resources, you will need to download and install Apktool for your operating system.
As another security measure, Android won’t install an APK unless it is digitally signed. So to repack an APK, you will also need to download and install the Java Development Kit (JDK) for your operating system for the keytool tool.
To create a new directory containing the decompiled contents of a package, run the following command in the same directory as the APK:
apktool d -o <new-directory> <new-package-name>.apk
Certificates
Secure Sockets Layer/Transport Layer Security (SSL/TLS) certificates serve as a form of identification for a server. They contain key information such as the domain name, controlling organization, and public key of the server.
When a client, such as your browser or application, wants to establish a secure, encrypted connection with a server, the server will present their certificate to prove their identity. Once the server’s identity has been verified, applications can be sure that they are communicating with the intended server, and the two entities generate a symmetric encryption key for the session.
But how do you know the SSL/TLS certificate itself is legitimate?
SSL/TLS certificates are cryptographically signed and validated by the certificates of trusted entities known as Certificate Authorities (CAs). Root CAs sit at the top of the certificate hierarchy. They consist of just a small number of organizations that have undergone a thorough vetting process to ensure they can be trusted. Root CA certificates are self-signed, and they sign the certificates of Intermediary CAs, which in turn sign server SSL/TLS certificates.
When a client receives a server’s SSL/TLS certificate, it verifies each certificate’s signature as it traverses up the chain. If the Root CA certificate is in a client’s system store and all certificates are valid, the client can confirm the server’s SSL/TLS certificate is authentic. Then, the client will generate a secret value and encrypt it with the server’s public key. Once the server decrypts the secret value with its private key, both entities now possess the same secret value, which is then used to derive a symmetric session key.
CA certificates can also be self-signed by an entity instead of being signed by a higher, trusted third-party CA. To identify a self-signed certificate, compare the Issuer and Subject fields. For example, the CA certificate of the HTTP proxy tool Caido is self-signed since the fields match:
When HTTP proxy tools like Caido and Burp Suite are used, they will form two separate TCP/TLS connections: one with the client and another with the server. This positions the proxy tool as an intermediary between the two, meaning it holds the symmetric keys of both connections. This is how you are able to encrypt and decrypt data as it is passed through.
However, when a client makes a connection request, the domain name of the SSL/TLS certificate must match the request. HTTP proxy tools handle this by dynamically generating certificates that match the server’s domain name. By adding the CA certificate of the proxy as a trusted entity, these certificates are signed with a signature that the client trusts.
Clients have two different stores of certificates:
- System-store certificates—This store contains a set of pre-installed trusted Root and Intermediary CA certificates.
- User-store certificates—These certificates are added by end users.
Although there are other formats, CA certificates come in two main encoding formats. Both have their own extensions and shared ones:
- Privacy-Enhanced Mail (PEM)—PEM certificates are Base64-encoded ASCII text files and can be recognized by their —–BEGIN CERTIFICATE—– header. They can have an extension of .pem, .crt, or .cer.
- Distinguished Encoding Rules (DERs)—DER certificates are in binary format. They can have an extension of .dem, .crt, or .cer.
Adding a user certificate
If you want to proxy HTTPS traffic generated by your mobile browser, navigate to http://127.0.0.1:8080/ca.crt to download the CA certificate of your HTTP proxy tool. You will then need to add it to the device’s user store.
If you are using a physical device:
- After downloading the certificate, you will be presented with a prompt window. Provide an arbitrary Certificate name and select Wi-Fi in the Used for dropdown menu.
- Click OK and navigate to a website using your device’s browser. You will now see the traffic in the HTTP history table of your proxy tool.
If you are using a virtual device:
- Search for and select CA certificate in the emulated device’s settings.
- Select CA certificate in the Install a certificate screen.
- Click INSTALL ANYWAY when presented with the Your data won’t be private warning to proceed.
- Drag and drop the CA certificate to the emulated device.
- Click This week to refresh the Files list and click on the ca.crt file.
- Navigate to a website using your device’s browser. You will now see the traffic in the HTTP history of your proxy tool.
Certificate pinning
Some applications will only trust system-store or explicitly defined certificates. This security technique is known as certificate pinning. This is an issue since we want the application to trust the user-supplied CA certificate of our HTTP proxy tool, enabling it to inspect, modify, and forward the traffic it generates.
To bypass this security mechanism:
- You will either need root-level permissions to add a certificate to the system store.
- Or you will need to unpack the APK, make modifications, and repack it back into a functioning application.
Android certificate naming
Android requires PEM format CA certificates that follow a specific naming convention.
If your HTTP proxy tool CA certificate is in the DER format, you will need to convert it to PEM with the following:
openssl x509 -inform DER -in <certificate-name>.der -out <new-certificate-name>.pem
To generate the hash of the certificate’s subject field, which is what Android expects as the file name, run:
openssl x509 -inform PEM -subject_hash_old -in <certificate-file> -noout
Next, rename the certificate using the hash with an extension of .0:
cp <certificate-file> <hash>.0
Adding a system certificate
Since there are variations between Android versions, we will demonstrate how to install a system certificate using an AVD. This method will work with Android 13 (API level 33) and below.
System certificates are stored in /system/etc/security/cacerts/, which requires root privileges. To add a certificate to the system store:
1. List your available devices:
adb devices
2. Launch the desired AVD with write permissions:
emulator -avd <avd> -writable-system
3. In a new terminal, restart the adbd process on the emulator to gain root privileges:
adb root
4. Disable secure boot verification:
adb shell avbctl disable-verification
5. Reboot the device:
adb reboot
6. Gain root permissions again:
adb root
7. Remount the partitions as read-write:
adb remount
8. Push the renamed Caido certificate to the system store:
adb push </path/to/hashed-certificate-name.0> /system/etc/security/cacerts
9. Set the proper permissions:
adb shell chmod 664 -v /system/etc/security/cacerts/<hashed-certificate-name.0>
10. Reboot the device:
adb reboot
To verify that the certificate was added, list the contents of the directory and find the certificate:
adb shell ls /system/etc/security/cacerts
Or navigate to your device’s settings and search for and select Trusted credentials. It will be included in the list under the SYSTEM tab.
network_security_config.xml
Introduced in Android 7.0 (API level 24), the network_security_config.xml file lets developers customize network security settings for their applications. This includes specifying which certificates are trusted.
Simply modifying this file, or adding one if it doesn’t exist, may be enough to make the application compatible with your HTTP proxy tool.
- Open the /res/xml/network_security_config.xml file or create one if it doesn’t exist.
2. Replace or write the content of the file to:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- Base configuration that applies to all connections if not overridden. -->
<base-config>
<!-- Define which certificates should be trusted as root CAs (trust anchors). -->
<trust-anchors>
<!-- Trust the pre-installed system certificates. -->
<certificates src="system" />
<!-- Trust user-installed certificates (like Caido's CA) and allow them to override certificate pinning. -->
<certificates src="user" overridePins="true" />
</trust-anchors>
</base-config>
</network-security-config>
3. Ensure that the main configuration file AndroidManifest.xml references the network_security_config.xml file via the android:networkSecurityConfig="@xml/network_security_config"
attribute in the <application>
tag. If you created a new network_security_config.xml file, you will have to explicitly add this.
4. From the directory of the unpacked APK, repack it with:
apktool b -o <repacked>.apk
5. Generate a signing key:
keytool -genkey -v -keystore custom.keystore -alias <aliasname> -keyalg RSA -keysize 2048 -validity 10000
6. Align the APK:
zipalign -p 4 <repacked>.apk <aligned>.apk
7. Sign the APK:
apksigner sign --ks custom.keystore <aligned>.apk
8. If the application is already installed on the device, uninstall it:
adb uninstall <application-name>
9. Install the modified APK:
adb install <aligned>.apk
Frida
If you are still unable to successfully proxy an application’s traffic, certificate pinning may be implemented in the codebase itself. You will need to download and install the Frida CLI tools.
Frida allows you to hook custom scripts into running Android applications and modify the processes that are checking the TLS/SSL certificates.
Since certain Frida operations may not work with unrooted devices, you will also need the Frida Gadget library. Once the library is injected into an APK, it can execute the commands sent to it by the CLI tools. The download you need will depend on the architecture of your device, which you can check with:
adb shell getprop ro.product.cpu.abi
Then, choose the appropriate Frida Gadget library download:
For armeabi-v7a or armeabi: android-arm.so.xz
For arm64-v8a: android-arm64.so.xz
For x86: android-x86.so.xz
For x86_64: android-x86_64.so.xz
Pro tip: The provided links will download v16.6.6. View the latest releases in the Frida repository.
Once downloaded, extract the library and rename it to:
libfrida-gadget.so
In Android development, “activity” is the term used to refer to a specific page/screen of an application. You will need to insert the Frida Gadget library into the main activity stated in the AndroidManifest.xml configuration file. In the following instructions, the unpacked APK of the SSL Pinning Demo application is used to demonstrate the steps:
- Open the AndroidManifest.xml file in a text editor. It will be similar to the following:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="33" android:compileSdkVersionCodename="13" package="tech.httptoolkit.pinning_demo" platformBuildVersionCode="33" platformBuildVersionName="13">
<uses-permission android:name="android.permission.INTERNET"/>
<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:extractNativeLibs="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplication">
<activity android:exported="true" android:name="tech.httptoolkit.pinning_demo.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
2. The application tag will contain an android:extractNativeLibs
attribute. For the Frida Gadget library to function properly, set the value of this attribute to “true”:
android:extractNativeLibs="true"
3. Next, search for the activity tag with a nested intent-filter tag that contains:
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
4. Within this activity tag will be an android:name attribute that stores the full name of the package that serves the main activity of the application upon launch:
tech.httptoolkit.pinning_demo.MainActivity
Pro tip: Packages can be recognized by their ending syntax of <Keyword>Activity (e.g., MainActivity, SplashActivity, WindowActivity,
and LauncherActivity
).
5. Recursively search through the unpacked APK for the package name tech.httptoolkit.pinning_demo.MainActivity
to locate its corresponding .smali file.
6. Open the smali/tech/httptoolkit/pinning_demo/MainActivity.smali file and locate the .method public constructor <init>()V
initialization function:
.method public constructor <init>()V
.locals 0
.line 51
invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V
return-void
.end method
7. Modify this function class definition to include the Frida Gadget script and increment the value of its .locals
property to account for the change:
.method public constructor <init>()V
.locals 1
const-string v0, "frida-gadget"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
.line 51
invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V
return-void
.end method
8. Next, create a lib directory in the unpacked APK folder, an architecture-specific subdirectory, and move the libfrida-gadget.so file into it (example: /unpacked/lib/x86-64/libfrida-gadget.so
).
9. From the directory of the unpacked APK, repack it with:
apktool b -o <unpacked>.apk ./
10. Align the APK:
zipalign -p 4 <repacked>.apk <aligned>.apk
11. Sign the APK:
apksigner sign --ks custom.keystore <aligned>.apk
12. Uninstall the original application from the device:
adb uninstall tech.httptoolkit.pinning_demo
13. Install the modified APK:
adb install <aligned>.apk
14. Next, open the SSL Pinning Demo application on your device. The screen will be blank, as it is awaiting the script that will hook into the application’s initialization. Supply it with:
frida -U gadget --codeshare fdciabdul/frida-multiple-bypass
15. Depending on the script used, you will now be able to make additional requests that were previously blocked when we only modified the network_security_config.xml
file and see traffic in the HTTP history table of your proxy tool.
Various HTTP libraries and their versions will require certain scripts to successfully bypass them.
When sourcing files online, make sure to evaluate the code for any malicious operations before executing it.
- Frida Codeshare is Frida’s official repository of scripts that can be called using the –codeshare command-line argument:
frida -U gadget --codeshare <author>/<file>
- You can also write them yourself or source them from alternative repositories. To specify a file, use the -l command-line argument followed by the file’s location:
frida -U gadget -l <file>
Conclusion
Now, you’re ready to hunt for bugs in Android applications! This knowledge expands your testing capabilities and therefore your money-making potential.
I always enjoy our time together. Make sure to check back in with Bugcrowd later, as we may cover how to set up for iOS testing next…
Love,
Ninjeeter