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.
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.
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.
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 ()_)
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.
adb
Source: https://developer.android.com/studio/debug/dev-options
Once USB debugging is enabled:
adb devices
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.
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:
adb reverse tcp:8080 tcp:8080
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:
adb shell
pm list packages -f | grep -i <application-name>
<package-name>
adb pull </path/to/package>==/base.apk
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
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:
Although there are other formats, CA certificates come in two main encoding formats. Both have their own extensions and shared ones:
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:
If you are using a virtual device:
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:
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
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:
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:
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:
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.
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.
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.
android:networkSecurityConfig="@xml/network_security_config"
<application>
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
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:
<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
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).
MainActivity, SplashActivity, WindowActivity,
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:
.locals
.locals 1
const-string v0, "frida-gadget"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
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).
/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:
11. Sign the APK:
12. Uninstall the original application from the device:
adb uninstall tech.httptoolkit.pinning_demo
13. Install the modified 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.
network_security_config.xml
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 -U gadget --codeshare <author>/<file>
frida -U gadget -l <file>
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