Introduction
SSL (Secure Sockets Layer) pinning is a security mechanism employed by mobile applications to prevent man-in-the-middle (MitM) attacks by ensuring that the application only trusts specific, pre-defined server certificates or public keys. While crucial for enhancing security, SSL pinning poses a significant challenge for penetration testers who need to intercept and analyze network traffic to identify vulnerabilities. Frida, a dynamic instrumentation toolkit, offers a powerful and flexible solution to bypass SSL pinning in Android applications, enabling comprehensive security assessments. This guide provides a detailed, step-by-step walkthrough for leveraging Frida to overcome SSL pinning during Android application pentesting.
Prerequisites
Before diving into the bypass techniques, ensure you have the following tools and knowledge:
- A rooted Android device or an emulator (e.g., Android Studio AVD, Genymotion) with root access.
- ADB (Android Debug Bridge) installed and configured on your host machine.
- Python 3 installed on your host machine.
- Basic familiarity with the command line, Android application structure, and JavaScript.
- A proxy tool like Burp Suite or OWASP ZAP configured to intercept HTTPS traffic.
Frida Setup and Verification
First, you need to set up Frida on both your host machine and the Android device.
1. Install Frida Tools on Host Machine
Use pip to install frida-tools:
pip install frida-tools
2. Install Frida Server on Android Device
-
Determine your device’s architecture. Connect your device and run:
adb shell getprop ro.product.cpu.abiCommon architectures include
arm64-v8a,armeabi-v7a,x86_64, orx86. -
Download the appropriate Frida server binary from the Frida releases page. Look for
frida-server-<version>-android-<architecture>.xz. For example,frida-server-16.1.4-android-arm64.xz. -
Extract the downloaded file:
unxz frida-server-<version>-android-<architecture>.xz -
Push the
frida-serverbinary to your device’s/data/local/tmp/directory:adb push frida-server /data/local/tmp/ -
Set executable permissions and run the Frida server:
adb shellsu -c "chmod 755 /data/local/tmp/frida-server"adb shellsu -c "/data/local/tmp/frida-server &"Verify Frida server is running and accessible from your host:
frida-ps -UThis command should list the running processes on your Android device.
Understanding SSL Pinning
SSL pinning works by embedding a list of trusted certificates or public keys directly within the application code during development. When the application attempts to establish an HTTPS connection, it verifies the server’s certificate against this embedded list. If the certificate does not match any entry in the list, the connection is aborted, even if the certificate is otherwise trusted by the operating system’s trust store. This prevents a proxy’s self-signed certificate (like Burp’s CA certificate) from being trusted by the application, thus blocking traffic interception.
Bypassing SSL Pinning with Frida
Frida allows us to hook into the application’s runtime and modify its behavior. For SSL pinning, we target the functions responsible for certificate validation, forcing them to always return ‘true’ or to trust our proxy’s certificate.
Method 1: Generic Frida SSL Bypass Script
Many Android apps use common libraries like OkHttp, Apache HttpClient, or standard Android APIs for network communication. Generic Frida scripts target the underlying Java methods that perform certificate validation. One widely used script attempts to hook various classes and methods associated with trust management.
Create a JavaScript file, for instance, frida-ssl-bypass.js, with the following content:
Java.perform(function () { console.log("[*] Starting Android SSL Pinning Bypass"); var CertificateFactory = Java.use("java.security.cert.CertificateFactory"); var FileInputStream = Java.use("java.io.FileInputStream"); var BufferedInputStream = Java.use("java.io.BufferedInputStream"); var X509Certificate = Java.use("java.security.cert.X509Certificate"); var KeyStore = Java.use("java.security.KeyStore"); var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory"); var SSLContext = Java.use("javax.net.ssl.SSLContext"); // Bypass OkHTTPv3 try { var okhttp3_CertificatePinner = Java.use("okhttp3.CertificatePinner"); okhttp3_CertificatePinner.check.overload("java.lang.String", "java.util.List").implementation = function (str, list) { console.log("[+] OkHTTPv3 Bypass: " + str); return; }; okhttp3_CertificatePinner.check.overload("java.lang.String", "java.security.cert.Certificate").implementation = function (str, cert) { console.log("[+] OkHTTPv3 Bypass: " + str); return; }; console.log("[+] Successfully hooked OkHTTPv3 CertificatePinner"); } catch (e) { console.log("[-] OkHTTPv3 CertificatePinner not found, skipping"); } // Bypass TrustManager try { var TrustManager = Java.use('javax.net.ssl.X509TrustManager'); var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier'); var SSLSession = Java.use('javax.net.ssl.SSLSession'); var HandshakeCompletedListener = Java.use('javax.net.ssl.HandshakeCompletedListener'); var Certificate = Java.use('java.security.cert.Certificate'); var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl'); TrustManagerImpl.verifyChain.implementation = function(chain, authType, host) { console.log('[+] TrustManagerImpl.verifyChain called for: ' + host); return chain; }; console.log('[+] Successfully hooked TrustManagerImpl.verifyChain'); } catch (e) { console.log('[-] TrustManagerImpl not found, skipping'); } // Bypass various TrustManagers (more generic) var TrustManagers = [ 'javax.net.ssl.X509TrustManager', 'javax.net.ssl.TrustManager', 'com.android.org.conscrypt.TrustManagerImpl', 'com.android.org.conscrypt.Platform$JdkInternalSystemTrustManager', 'io.netty.handler.ssl.util.InsecureTrustManagerFactory$1', 'android.security.net.config.NetworkSecurityConfig$TrustManagerImpl' ]; for (var i = 0; i < TrustManagers.length; i++) { try { var className = TrustManagers[i]; var TrustManagerClass = Java.use(className); TrustManagerClass.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function (chain, authType) { console.log("[+] Bypassing checkServerTrusted for " + className); // Always trust return; }; TrustManagerClass.checkClientTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function (chain, authType) { console.log("[+] Bypassing checkClientTrusted for " + className); // Always trust return; }; console.log("[+] Successfully hooked " + className); } catch (e) { // console.log("[-] " + className + " not found, skipping"); } } // Bypass HostnameVerifier try { var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier'); HostnameVerifier.verify.implementation = function(hostname, session) { console.log("[+] Bypassing HostnameVerifier for " + hostname); return true; // Always trust }; console.log("[+] Successfully hooked HostnameVerifier"); } catch (e) { console.log("[-] HostnameVerifier not found, skipping"); } console.log("[*] Android SSL Pinning Bypass Finished");});
Usage Steps:
-
Configure your proxy (e.g., Burp Suite) to listen on a specific port (e.g., 8080) and ensure your Android device’s Wi-Fi settings are configured to use this proxy.
-
Identify the target application’s package name. You can use
adb shell pm list packages -3to list user-installed packages. -
Run Frida with the bypass script. Replace
<package_name>with the actual package name (e.g.,com.example.app):frida -U -l frida-ssl-bypass.js -f <package_name> --no-pauseThe
-fflag spawns the application and hooks it from the start.--no-pauseensures the app starts immediately without waiting for user input. -
Interact with the application. You should now see its network traffic flowing through your configured proxy.
Method 2: Using Objection for Automated Bypass
Objection is a runtime mobile exploration toolkit powered by Frida. It provides a higher-level abstraction for common pentesting tasks, including SSL pinning bypass, making it very efficient.
1. Install Objection
pip install objection
2. Run Objection and Bypass SSL Pinning
Spawn the target application with Objection:
objection -g <package_name> explore --startup-command "android sslpinning disable"
Alternatively, if the app is already running, attach to it:
objection -g <package_name> explore
Once in the Objection console, run:
android sslpinning disable
Objection will automatically inject a Frida script to bypass SSL pinning. This method is often quicker and can bypass many common implementations without manual script creation.
Troubleshooting Common Issues
-
Frida server not running or accessible: Double-check step 2 in Frida setup. Ensure
frida-serverhas executable permissions and is running in the background. Checkadb logcat | grep fridafor errors. -
Application crashes upon hooking: Some applications implement anti-Frida or anti-tampering measures. You might need more advanced techniques to bypass these or use an obfuscated Frida server. Also, ensure your Frida server version matches your
frida-toolsversion. -
SSL pinning still active after script injection: The application might be using a less common or custom SSL pinning implementation not covered by the generic script. In such cases, you’ll need to reverse engineer the application (e.g., using Jadx-GUI or Ghidra) to identify the specific SSL/TLS methods being called and write a custom Frida hook for them.
-
Proxy not receiving traffic: Verify your proxy settings on both the host and the Android device. Ensure the proxy’s CA certificate is installed and trusted on the Android device (though for SSL pinning bypass, the app itself is what’s trusting the certificate, not just the OS).
Conclusion
Bypassing SSL pinning is a fundamental skill for Android application penetration testers. Frida offers an incredibly versatile and powerful framework to achieve this, whether through generic scripts or automated tools like Objection. While challenges may arise with custom implementations, understanding the underlying principles and having a solid methodology will equip you to tackle most scenarios. Always remember to use these techniques ethically and only on applications you have explicit permission to test.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →