Android SSL pinning is a security feature where an application hardcodes specific SSL certificates or public keys. When the app tries to connect to its backend server, it checks if the server’s certificate matches the one it expects. If there’s a mismatch, the connection fails, preventing man-in-the-middle attacks.
Here’s how an Android app, specifically one that uses SSL pinning, behaves when you try to intercept its traffic with Burp Suite.
First, let’s set up Burp Suite. We’ll use the default configuration, which listens on 127.0.0.1:8080.
# Burp Suite running, default config
java -jar burpsuite_community.jar
Next, we need to configure the Android device or emulator to use Burp Suite as its proxy. This is usually done in the Wi-Fi settings for the network the device is connected to.
Proxy Settings:
- IP Address:
192.168.1.100(Replace with your machine’s IP address) - Port:
8080
Now, if you try to access an HTTPS URL in the app, you’ll see a connection error. The app will likely display a message like "Connection failed" or "Unable to connect." This is because the app’s pinned certificate doesn’t match the certificate Burp Suite is presenting.
To bypass SSL pinning, we need to install Burp Suite’s CA certificate on the Android device and tell the app to trust user-installed certificates.
Step 1: Install Burp Suite’s CA Certificate on Android
- On your Android device, open a browser and navigate to
http://burpsuite(orhttp://<your-machine-ip>:8080). - Click on the "CA Certificate" link to download the certificate.
- The device will prompt you to name the certificate. A common name is "Burp".
- The certificate will be installed in the
Credentials storageunderVPN and app user.
Step 2: Configure Android to Trust User-Installed Certificates
This step is crucial and varies significantly depending on the Android version.
-
Android 7.0 (Nougat) and newer: Apps are configured by default not to trust user-installed CA certificates for network traffic. You need to create a network security configuration file within the app’s
res/xmldirectory. This is typically done by the app developer. If you are testing an app you don’t control, this method won’t work directly unless the app is designed for debugging. However, for rooted devices or emulators, you can often achieve system-wide trust.If you have root access or are on an emulator, you can manually place the Burp CA certificate into the system’s trust store. This usually involves:
- Copying the downloaded
cacert.cerfile to/sdcard/Download/. - Using
adb shellandsuto get root privileges. - Copying the certificate to
/system/etc/security/cacerts/(or a similar path depending on the Android version and ROM). - Setting the correct permissions:
chmod 644 /system/etc/security/cacerts/<hash_of_cert_name>.0 - Rebooting the device.
- Copying the downloaded
-
Android 6.0 (Marshmallow) and older: User-installed certificates were trusted by default. Simply installing the Burp CA certificate as described in Step 1 was often sufficient.
Step 3: Configure the App to Trust User-Installed Certificates (If Applicable)
For apps targeting Android 7.0+ that don’t have a custom network security configuration, you might be able to use a tool like Frida to dynamically patch the app’s behavior at runtime.
Here’s a sample Frida script to bypass SSL pinning:
Java.perform(function() {
var trustManager = Java.use('javax.net.ssl.X509TrustManager');
var trustManagerImpl = Java.registerClass({
// Implement the X509TrustManager interface
implements: [trustManager],
methods: {
checkClientTrusted: function(chain, authType) {
console.log("Client trusted");
},
checkServerTrusted: function(chain, authType) {
console.log("Server trusted");
},
getAcceptedIssuers: function() {
return [];
}
}
});
var nullTrustManager = Java.use('android.app.trust.TrustManager');
nullTrustManager.$init.overload('android.content.Context', 'android.app.trust.TrustManager$Callback');
var originalTrustManager = null;
var trustManagerInstance = null;
Java.enumerateLoadedClasses({
onMatch: function(className) {
if (className.includes('OkHttpClient') || className.includes('SSLSocketFactory')) {
console.log("Found potential SSL client: " + className);
try {
var SSLSocketFactory = Java.use(className);
// Attempt to bypass OkHttp's default trust manager
if (SSLSocketFactory.trustManager() && SSLSocketFactory.trustManager().implementation) {
console.log("Found OkHttp TrustManager, bypassing...");
SSLSocketFactory.trustManager.implementation = function() {
return trustManagerImpl.$new();
};
}
// Attempt to bypass default SSLSocketFactory
if (SSLSocketFactory.sslSocketFactory() && SSLSocketFactory.sslSocketFactory().implementation) {
console.log("Found SSLSocketFactory, bypassing...");
SSLSocketFactory.sslSocketFactory.implementation = function() {
return trustManagerImpl.$new();
};
}
} catch (e) {
// console.error("Error bypassing " + className + ": " + e.message);
}
}
},
onComplete: function() {}
});
// For apps that use a custom TrustManager directly
try {
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var sslContextInstance = SSLContext.getInstance('TLS');
sslContextInstance.init(null, [trustManagerImpl.$new()], null);
var sslSocketFactory = sslContextInstance.getSocketFactory();
var defaultSSLSocketFactory = Java.use('javax.net.ssl.SSLSocketFactory');
defaultSSLSocketFactory.getDefault.implementation = function() {
console.log("Bypassing default SSLSocketFactory");
return sslSocketFactory;
};
defaultSSLSocketFactory.getSocketFactory.implementation = function() {
console.log("Bypassing default getSocketFactory");
return sslSocketFactory;
};
} catch (e) {
// console.error("Error bypassing SSLContext: " + e.message);
}
});
To run this Frida script:
-
Install Frida on your machine and the Frida server on your Android device.
-
Start Burp Suite and configure your device’s proxy.
-
Install Burp’s CA certificate on the device.
-
Run the Frida script against the target app:
frida -U -f com.example.targetapp -l bypass.js --no-pause(Replace
com.example.targetappwith the actual package name andbypass.jswith the script filename.)
Once these steps are completed and the app successfully trusts the Burp CA certificate, you should see traffic in Burp Suite’s HTTP history. The app will now establish a connection with Burp Suite, allowing you to inspect and manipulate its requests and responses.
The next error you’ll hit is likely related to application-specific logic or authorization checks that are not dependent on SSL certificate validation.