Network Security
🔥 Advanced

Certificate Pinning Bypass

Certificate pinning is a security mechanism that restricts which certificates are trusted for a particular connection. Bypassing it is essential for intercepting HTTPS traffic during mobile app pentesting.

What is Certificate Pinning?

Certificate pinning associates a host with an expected X.509 certificate or public key. Once a certificate or public key is pinned, any other certificates (even valid CA-signed ones) will be rejected by the application.

Types of Certificate Pinning

Certificate Pinning

Pins the entire certificate. If the certificate changes (e.g., renewal), the pin must be updated.

More brittle, easier to detect

Public Key Pinning

Pins only the public key (SPKI). The same key can be used across certificate renewals.

More flexible, harder to bypass

Android Bypass Techniques

1. Frida Universal Bypass

The most reliable method for bypassing certificate pinning on Android:

android_ssl_bypass.js
javascript
// Universal Android SSL Pinning Bypass
Java.perform(function() {
    // TrustManagerImpl bypass
    var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
    TrustManagerImpl.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
        console.log('[+] Bypassing TrustManagerImpl.verifyChain for: ' + host);
        return untrustedChain;
    };
    
    // OkHttp3 CertificatePinner bypass
    try {
        var CertificatePinner = Java.use('okhttp3.CertificatePinner');
        CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(hostname, peerCertificates) {
            console.log('[+] Bypassing OkHttp3 CertificatePinner for: ' + hostname);
            return;
        };
    } catch(e) {
        console.log('[-] OkHttp3 not found');
    }
    
    // Retrofit/OkHttp bypass
    try {
        var OkHttpClient = Java.use('okhttp3.OkHttpClient$Builder');
        OkHttpClient.certificatePinner.implementation = function(certificatePinner) {
            console.log('[+] Bypassing OkHttpClient.certificatePinner');
            return this;
        };
    } catch(e) {
        console.log('[-] OkHttpClient not found');
    }
    
    // Apache HTTP client (legacy)
    try {
        var HttpsURLConnection = Java.use('javax.net.ssl.HttpsURLConnection');
        HttpsURLConnection.setDefaultHostnameVerifier.implementation = function(hostnameVerifier) {
            console.log('[+] Bypassing HttpsURLConnection hostname verifier');
            return;
        };
    } catch(e) {}
});

Run with Frida:

bash
frida -U -f com.target.app -l android_ssl_bypass.js --no-pause

2. Objection Bypass

Quick bypass using objection:

bash
# Start objection
objection -g com.target.app explore

# Inside objection shell:
android sslpinning disable

# Or spawn with bypass enabled
objection -g com.target.app explore --startup-command "android sslpinning disable"

3. Network Security Config (Android 7+)

Modify the app to trust user certificates by editing the APK:

bash
# Decompile APK
apktool d target.apk -o target_decompiled

# Create/edit res/xml/network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>

# Add to AndroidManifest.xml in <application> tag:
# android:networkSecurityConfig="@xml/network_security_config"

# Rebuild and sign
apktool b target_decompiled -o target_patched.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my.keystore target_patched.apk alias_name
zipalign -v 4 target_patched.apk target_final.apk

iOS Bypass Techniques

1. Frida iOS Bypass

ios_ssl_bypass.js
javascript
// iOS Universal SSL Pinning Bypass
if (ObjC.available) {
    // Bypass NSURLSession
    var NSURLSession = ObjC.classes.NSURLSession;
    Interceptor.attach(NSURLSession['- URLSession:didReceiveChallenge:completionHandler:'].implementation, {
        onEnter: function(args) {
            console.log('[+] Intercepting NSURLSession challenge');
            var completionHandler = new ObjC.Block(args[4]);
            var NSURLSessionAuthChallengeUseCredential = 0;
            completionHandler.implementation = function(disposition, credential) {
                console.log('[+] Accepting credential');
                completionHandler(NSURLSessionAuthChallengeUseCredential, null);
            };
        }
    });
    
    // Bypass AFNetworking
    try {
        var AFSecurityPolicy = ObjC.classes.AFSecurityPolicy;
        AFSecurityPolicy['- setSSLPinningMode:'].implementation = function(mode) {
            console.log('[+] Bypassing AFNetworking pinning mode');
            this.setSSLPinningMode_(0);
        };
        AFSecurityPolicy['- setAllowInvalidCertificates:'].implementation = function(allow) {
            console.log('[+] Allowing invalid certificates');
            this.setAllowInvalidCertificates_(1);
        };
    } catch(e) {
        console.log('[-] AFNetworking not found');
    }
    
    // Bypass TrustKit
    try {
        var TrustKit = ObjC.classes.TrustKit;
        TrustKit['+ setUpSharedInstanceWithConfiguration:'].implementation = function(config) {
            console.log('[+] Bypassing TrustKit initialization');
            return;
        };
    } catch(e) {
        console.log('[-] TrustKit not found');
    }
}

2. Objection iOS Bypass

bash
# Connect to iOS app
objection -g com.target.app explore

# Disable SSL pinning
ios sslpinning disable

# Hook specific pinning methods
ios sslpinning disable --quiet

3. SSL Kill Switch 2 (Cydia)

On jailbroken devices, install SSL Kill Switch 2 from Cydia to globally disable certificate validation.

bash
# Add repository in Cydia:
https://repo.rpetri.ch/beta/

# Or manually install deb:
dpkg -i com.nablac0d3.sslkillswitch2_0.14.deb
killall -9 SpringBoard

Bypassing Specific Implementations

Library Platform Bypass Method
OkHttp3 Android Hook CertificatePinner.check()
Retrofit Android Hook OkHttp (uses OkHttp internally)
AFNetworking iOS Hook AFSecurityPolicy methods
TrustKit iOS Hook TSKPinVerifier
Flutter Both Patch ssl_x509.cc in libflutter.so
React Native Both Hook native HTTP client (OkHttp/NSURLSession)

Proxy Configuration

Before Bypassing

Always configure your proxy (Burp Suite, mitmproxy) and install its CA certificate on the device before attempting to bypass pinning.

Android CA Install

bash
# Export Burp CA as DER
# Convert to PEM
openssl x509 -inform DER -in cacert.der -out cacert.pem

# Get hash
openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1

# Rename and push
mv cacert.pem 9a5ba575.0
adb root
adb remount
adb push 9a5ba575.0 /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/9a5ba575.0

iOS CA Install

bash
# 1. Export Burp CA
# 2. Host on local server:
python3 -m http.server 8080

# 3. On iOS device:
# Navigate to http://YOUR_IP:8080/cert.der
# Install profile in Settings

# 4. Trust certificate:
# Settings > General > About > 
# Certificate Trust Settings > 
# Enable "Burp Certificate"

Troubleshooting

Bypass not working?

  • • Check if the app uses a custom HTTP library
  • • Try multiple bypass scripts in combination
  • • Look for obfuscated pinning code
  • • Check if the app has root/jailbreak detection

App crashes after bypass?

  • • The bypass script might be too aggressive
  • • Try a more targeted approach for specific libraries
  • • Check Frida console for errors
  • • App might have integrity checks