diff --git a/android-certificate-unpinning.js b/android-certificate-unpinning.js index 4dc10eb..9deebc2 100644 --- a/android-certificate-unpinning.js +++ b/android-certificate-unpinning.js @@ -1,545 +1,412 @@ -/* - * This script combines, fixes & extends a long list of other scripts, most notably including: - * - * - https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/ - * - https://codeshare.frida.re/@avltree9798/universal-android-ssl-pinning-bypass/ - * - https://pastebin.com/TVJD63uM - */ +const NO_OP = () => {}; +const RETURN_TRUE = () => true; + +const PINNING_FIXES = { + // --- Native HttpsURLConnection + + 'javax.net.ssl.HttpsURLConnection': [ + { + methodName: 'setDefaultHostnameVerifier', + replacement: () => NO_OP + }, + { + methodName: 'setSSLSocketFactory', + replacement: () => NO_OP + }, + { + methodName: 'setHostnameVerifier', + replacement: () => NO_OP + }, + ], + + // --- Native SSLContext + + 'javax.net.ssl.SSLContext': [ + { + methodName: 'init', + overload: ['[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'], + replacement: (targetMethod) => { + const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); + + // Implement a custom TrustManager + const TrustManager = Java.registerClass({ + name: `com.httptoolkit.android.TrustManager`, + implements: [X509TrustManager], + methods: { + checkClientTrusted: function (chain, authType) { }, + checkServerTrusted: function (chain, authType) { }, + getAcceptedIssuers: function () { return []; } + } + }); + + const trustManagersOverride = [TrustManager.$new()]; + + // When constructor is called, replace the trust managers argument with our own trust manager: + return (keyManager, _providedTrustManagers, secureRandom) => { + return targetMethod.call(this, keyManager, trustManagersOverride, secureRandom); + } + } + } + ], + + // --- Native TrustManagerImpl + + 'com.android.org.conscrypt.TrustManagerImpl': [ + { + methodName: 'checkTrustedRecursive', + replacement: () => () => Java.use('java.util.ArrayList').$new() + }, + { + methodName: 'verifyChain', + replacement: () => (untrustedChain) => untrustedChain + } + ], + + // --- Native Conscrypt OpenSSLSocketImpl + + 'com.android.org.conscrypt.OpenSSLSocketImpl': [ + { + methodName: 'verifyCertificateChain', + replacement: () => NO_OP + } + ], + + 'com.android.org.conscrypt.OpenSSLEngineSocketImpl': [ + { + methodName: 'verifyCertificateChain', + overload: ['[Ljava.lang.Long;', 'java.lang.String'], + replacement: () => NO_OP + } + ], + + // --- Native Conscrypt CertPinManager + + 'com.android.org.conscrypt.CertPinManager': [ + { + methodName: 'isChainValid', + overload: ['java.lang.String', 'java.util.List'], + replacement: () => RETURN_TRUE + } + ], + + // --- Native pinning configuration loading (used for configuration by many libraries) + + 'android.security.net.config.NetworkSecurityConfig': [ + { + methodName: '$init', + overloads: '*', + replacement: () => { + const PinSet = Java.use('android.security.net.config.PinSet'); + const EMPTY_PINSET = PinSet.EMPTY_PINSET.value; + return function () { + // Always ignore the 2nd 'pins' PinSet argument entirely: + arguments[2] = EMPTY_PINSET; + this.$init(...arguments); + } + } + } + ], + + // --- Native WebViewClient + + 'android.webkit.WebViewClient': [ + { + methodName: 'onReceivedSslError', + overload: ['android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError'], + replacement: () => NO_OP + }, + { + methodName: 'onReceivedSslError', + overload: ['android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError'], + replacement: () => NO_OP + } + ], + + // --- OkHttp v3 + + 'okhttp3.CertificatePinner': [ + { + methodName: 'check', + overload: ['java.lang.String', 'java.util.List'], + replacement: () => NO_OP + }, + { + methodName: 'check', + overload: ['java.lang.String', 'java.security.cert.Certificate'], + replacement: () => NO_OP + }, + { + methodName: 'check', + overload: ['java.lang.String', '[Ljava.security.cert.Certificate;'], + replacement: () => NO_OP + }, + { + methodName: 'check$okhttp', + replacement: () => NO_OP + }, + ], + + // --- SquareUp OkHttp (< v3) + + 'com.squareup.okhttp.CertificatePinner': [ + { + methodName: 'check', + overload: ['java.lang.String', 'java.security.cert.Certificate'], + replacement: () => NO_OP + }, + { + methodName: 'check', + overload: ['java.lang.String', 'java.util.List'], + replacement: () => NO_OP + } + ], + + 'com.squareup.okhttp.internal.tls.OkHostnameVerifier': [ + { + methodName: 'verify', + overload: ['java.lang.String', 'java.security.cert.X509Certificate'], + replacement: () => RETURN_TRUE + }, + { + methodName: 'verify', + overload: ['java.lang.String', 'javax.net.ssl.SSLSession'], + replacement: () => RETURN_TRUE + } + ], + + // --- Trustkit + + 'com.datatheorem.android.trustkit.pinning.OkHostnameVerifier': [ + { + methodName: 'verify', + overload: ['java.lang.String', 'javax.net.ssl.SSLSession'], + replacement: () => RETURN_TRUE + }, + { + methodName: 'verify', + overload: ['java.lang.String', 'java.security.cert.X509Certificate'], + replacement: () => RETURN_TRUE + } + ], + + 'com.datatheorem.android.trustkit.pinning.PinningTrustManager': [ + { + methodName: 'checkServerTrusted', + replacement: () => NO_OP + } + ], + + // --- Appcelerator + + 'appcelerator.https.PinningTrustManager': [ + { + methodName: 'checkServerTrusted', + replacement: NO_OP + } + ], + + // --- Apache Harmony version of OpenSSLSocketImpl (v similar to Conscrypt above) + + 'org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl': [ + { + methodName: 'verifyCertificateChain', + replacement: () => NO_OP + } + ], + + // --- PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin) + + 'nl.xservices.plugins.sslCertificateChecker': [ + { + methodName: 'execute', + overload: ['java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext'], + replacement: () => RETURN_TRUE + } + ], + + // --- IBM WorkLight + + 'com.worklight.wlclient.api.WLClient': [ + { + methodName: 'pinTrustedCertificatePublicKey', + getMethod: (WLClientCls) => WLClientCls.getInstance().pinTrustedCertificatePublicKey, + overload: ['java.lang.String'], + replacement: () => NO_OP + }, + { + methodName: 'pinTrustedCertificatePublicKey', + getMethod: (WLClientCls) => WLClientCls.getInstance().pinTrustedCertificatePublicKey, + overload: ['[Ljava.lang.String;'], + replacement: () => NO_OP + } + ], + + 'com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning': [ + { + methodName: 'verify', + overload: ['java.lang.String', 'javax.net.ssl.SSLSocket'], + replacement: () => NO_OP + }, + { + methodName: 'verify', + overload: ['java.lang.String', 'java.security.cert.X509Certificate'], + replacement: () => NO_OP + }, + { + methodName: 'verify', + overload: ['java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;'], + replacement: () => NO_OP + }, + { + methodName: 'verify', + overload: ['java.lang.String', 'javax.net.ssl.SSLSession'], + replacement: () => RETURN_TRUE + } + ], + + 'com.worklight.androidgap.plugin.WLCertificatePinningPlugin': [ + { + methodName: 'execute', + overload: ['java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext'], + replacement: () => RETURN_TRUE + } + ], + + // --- // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager + + 'com.commonsware.cwac.netsecurity.conscrypt.CertPinManager': [ + { + methodName: 'isChainValid', + overload: ['java.lang.String', 'java.util.List'], + replacement: () => RETURN_TRUE + } + ], + + // --- Netty + + 'io.netty.handler.ssl.util.FingerprintTrustManagerFactory': [ + { + methodName: 'checkTrusted', + replacement: () => NO_OP + } + ], + + // --- Apache Cordova WebViewClient + + 'org.apache.cordova.CordovaWebViewClient': [ + // Very similar to native Android WebViewClient + { + methodName: 'onReceivedSslError', + overload: ['android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError'], + replacement: () => (a, b, c) => c.proceed() + } + ], + + // --- Boye AbstractVerifier + + 'ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier': [ + { + methodName: 'verify', + replacement: () => NO_OP + } + ], + + // --- Appmattus + + 'com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor': [ + { + methodName: 'intercept', + replacement: () => (a) => a.proceed(a.request()) + } + ], + + 'com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyTrustManager': [ + { + methodName: 'checkServerTrusted', + overload: ['[Ljava.security.cert.X509Certificate;', 'java.lang.String'], + replacement: () => NO_OP + }, + { + methodName: 'checkServerTrusted', + overload: ['[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'java.lang.String'], + replacement: () => () => Java.use('java.util.ArrayList').$new() + } + ] + +}; + +const getJavaClassIfExists = (clsName) => { + try { + return Java.use(clsName); + } catch { + return undefined; + } +} setTimeout(function () { Java.perform(function () { - console.log("---"); - console.log("Unpinning Android app..."); + if (DEBUG_MODE) console.debug('=== Disablig all recognized unpinning libraries ==='); - /// -- Generic hook to protect against SSLPeerUnverifiedException -- /// + Object.keys(PINNING_FIXES).forEach((targetClass) => { + const Cls = getJavaClassIfExists(targetClass); + if (!Cls) { + // We skip patches for any classes that don't seem to be present. This is common + // as not all libraries we handle are necessarily used. + if (DEBUG_MODE) console.debug(`[ ] ${targetClass} *`); + } - // In some cases, with unusual cert pinning approaches, or heavy obfuscation, we can't - // match the real method & package names. This is a problem! Fortunately, we can still - // always match built-in types, so here we spot all failures that use the built-in cert - // error type (notably this includes OkHttp), and after the first failure, we dynamically - // generate & inject a patch to completely disable the method that threw the error. - try { - const UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException'); - UnverifiedCertError.$init.implementation = function (str) { - console.log(' --> Unexpected SSL verification failure, adding dynamic patch...'); + const patches = PINNING_FIXES[targetClass]; - try { - const stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace(); - const exceptionStackIndex = stackTrace.findIndex(stack => - stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException" - ); - const callingFunctionStack = stackTrace[exceptionStackIndex + 1]; + let patchApplied = false; - const className = callingFunctionStack.getClassName(); - const methodName = callingFunctionStack.getMethodName(); + patches.forEach(({ methodName, getMethod, overload, replacement }) => { + const namedTargetMethod = getMethod + ? getMethod(targetClass) + : targetClass[methodName]; - console.log(` Thrown by ${className}->${methodName}`); + const methodDescription = `${methodName}${ + overload + ? '(' + overload.map((argType) => { + // Simplify arg names to just the class name for simpler logs: + const argClassName = argType.split('.').slice(-1)[0]; + if (argType.startsWith('[L')) return `${argClassName}[]`; + else return argClassName; + }).join(', ') + ')' + : '' + }` - const callingClass = Java.use(className); - const callingMethod = callingClass[methodName]; + const targetMethodImplementations = !namedTargetMethod + ? [] // Method not found + : !overload + ? [namedTargetMethod] // No overload specified + : overload === '*' + ? namedTargetMethod.overloads // Targetting _all_ overloads + // Or targetting a specific overload: + : [namedTargetMethod.overload(...overload)]; - if (callingMethod.implementation) return; // Already patched by Frida - skip it - - console.log(' Attempting to patch automatically...'); - const returnTypeName = callingMethod.returnType.type; - - callingMethod.implementation = function () { - console.log(` --> Bypassing ${className}->${methodName} (automatic exception patch)`); - - // This is not a perfect fix! Most unknown cases like this are really just - // checkCert(cert) methods though, so doing nothing is perfect, and if we - // do need an actual return value then this is probably the best we can do, - // and at least we're logging the method name so you can patch it manually: - - if (returnTypeName === 'void') { - return; - } else { - return null; - } - }; - - console.log(` [+] ${className}->${methodName} (automatic exception patch)`); - } catch (e) { - console.log(' [ ] Failed to automatically patch failure'); + if (targetMethodImplementations.length === 0) { + // We skip patches for any methods that don't seem to be present. This is + // rarer, but happens due to methods that only appear in certain library + // versions or whose signatures have changed over time. + if (DEBUG_MODE) console.debug(`[ ] ${targetClass} ${methodDescription}`); + return; } - return this.$init(str); - }; - console.log('[+] SSLPeerUnverifiedException auto-patcher'); - } catch (err) { - console.log('[ ] SSLPeerUnverifiedException auto-patcher'); - } - - /// -- Specific targeted hooks: -- /// - - // HttpsURLConnection - try { - const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); - HttpsURLConnection.setDefaultHostnameVerifier.implementation = function (hostnameVerifier) { - console.log(' --> Bypassing HttpsURLConnection (setDefaultHostnameVerifier)'); - return; // Do nothing, i.e. don't change the hostname verifier - }; - console.log('[+] HttpsURLConnection (setDefaultHostnameVerifier)'); - } catch (err) { - console.log('[ ] HttpsURLConnection (setDefaultHostnameVerifier)'); - } - try { - const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); - HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) { - console.log(' --> Bypassing HttpsURLConnection (setSSLSocketFactory)'); - return; // Do nothing, i.e. don't change the SSL socket factory - }; - console.log('[+] HttpsURLConnection (setSSLSocketFactory)'); - } catch (err) { - console.log('[ ] HttpsURLConnection (setSSLSocketFactory)'); - } - try { - const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); - HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) { - console.log(' --> Bypassing HttpsURLConnection (setHostnameVerifier)'); - return; // Do nothing, i.e. don't change the hostname verifier - }; - console.log('[+] HttpsURLConnection (setHostnameVerifier)'); - } catch (err) { - console.log('[ ] HttpsURLConnection (setHostnameVerifier)'); - } - - // SSLContext - try { - const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); - const SSLContext = Java.use('javax.net.ssl.SSLContext'); - - const TrustManager = Java.registerClass({ - // Implement a custom TrustManager - name: 'dev.asd.test.TrustManager', - implements: [X509TrustManager], - methods: { - checkClientTrusted: function (chain, authType) { }, - checkServerTrusted: function (chain, authType) { }, - getAcceptedIssuers: function () { return []; } + try { + targetMethodImplementations.forEach((targetMethod) => { + targetMethod.implementation = replacement(targetMethod); + if (DEBUG_MODE) console.debug(`[+] ${patchName} ${methodDescription}`); + }) + patchApplied = true; + } catch (e) { + // In theory, errors like this should never happen - it means the patch is broken + // (e.g. an expected method doesn't exist at all) + console.warn(`[!] ERROR: ${patchName} failed: ${e}`); } }); - // Prepare the TrustManager array to pass to SSLContext.init() - const TrustManagers = [TrustManager.$new()]; + console.log(`[!] Matched class ${targetClass} but could not patch any methods`); + }); - // Get a handle on the init() on the SSLContext class - const SSLContext_init = SSLContext.init.overload( - '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom' - ); - - // Override the init method, specifying the custom TrustManager - SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) { - console.log(' --> Bypassing Trustmanager (Android < 7) request'); - SSLContext_init.call(this, keyManager, TrustManagers, secureRandom); - }; - console.log('[+] SSLContext'); - } catch (err) { - console.log('[ ] SSLContext'); - } - - // TrustManagerImpl (Android > 7) - try { - const array_list = Java.use("java.util.ArrayList"); - const TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl'); - - // This step is notably what defeats the most common case: network security config - TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) { - console.log(' --> Bypassing TrustManagerImpl checkTrusted '); - return array_list.$new(); - } - - TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) { - console.log(' --> Bypassing TrustManagerImpl verifyChain: ' + host); - return untrustedChain; - }; - console.log('[+] TrustManagerImpl'); - } catch (err) { - console.log('[ ] TrustManagerImpl'); - } - - // OkHTTPv3 (quadruple bypass) - try { - // Bypass OkHTTPv3 {1} - const okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner'); - okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { - console.log(' --> Bypassing OkHTTPv3 (list): ' + a); - return; - }; - console.log('[+] OkHTTPv3 (list)'); - } catch (err) { - console.log('[ ] OkHTTPv3 (list)'); - } - try { - // Bypass OkHTTPv3 {2} - // This method of CertificatePinner.check could be found in some old Android app - const okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner'); - okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) { - console.log(' --> Bypassing OkHTTPv3 (cert): ' + a); - return; - }; - console.log('[+] OkHTTPv3 (cert)'); - } catch (err) { - console.log('[ ] OkHTTPv3 (cert)'); - } - try { - // Bypass OkHTTPv3 {3} - const okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner'); - okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) { - console.log(' --> Bypassing OkHTTPv3 (cert array): ' + a); - return; - }; - console.log('[+] OkHTTPv3 (cert array)'); - } catch (err) { - console.log('[ ] OkHTTPv3 (cert array)'); - } - try { - // Bypass OkHTTPv3 {4} - const okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner'); - okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) { - console.log(' --> Bypassing OkHTTPv3 ($okhttp): ' + a); - return; - }; - console.log('[+] OkHTTPv3 ($okhttp)'); - } catch (err) { - console.log('[ ] OkHTTPv3 ($okhttp)'); - } - - // Trustkit (triple bypass) - try { - // Bypass Trustkit {1} - const trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier'); - trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) { - console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a); - return true; - }; - console.log('[+] Trustkit OkHostnameVerifier(SSLSession)'); - } catch (err) { - console.log('[ ] Trustkit OkHostnameVerifier(SSLSession)'); - } - try { - // Bypass Trustkit {2} - const trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier'); - trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) { - console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a); - return true; - }; - console.log('[+] Trustkit OkHostnameVerifier(cert)'); - } catch (err) { - console.log('[ ] Trustkit OkHostnameVerifier(cert)'); - } - try { - // Bypass Trustkit {3} - const trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager'); - trustkit_PinningTrustManager.checkServerTrusted.implementation = function () { - console.log(' --> Bypassing Trustkit PinningTrustManager'); - }; - console.log('[+] Trustkit PinningTrustManager'); - } catch (err) { - console.log('[ ] Trustkit PinningTrustManager'); - } - - // Appcelerator Titanium - try { - const appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager'); - appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () { - console.log(' --> Bypassing Appcelerator PinningTrustManager'); - }; - console.log('[+] Appcelerator PinningTrustManager'); - } catch (err) { - console.log('[ ] Appcelerator PinningTrustManager'); - } - - // OpenSSLSocketImpl Conscrypt - try { - const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl'); - OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) { - console.log(' --> Bypassing OpenSSLSocketImpl Conscrypt'); - }; - console.log('[+] OpenSSLSocketImpl Conscrypt'); - } catch (err) { - console.log('[ ] OpenSSLSocketImpl Conscrypt'); - } - - // OpenSSLEngineSocketImpl Conscrypt - try { - const OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl'); - OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) { - console.log(' --> Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b); - }; - console.log('[+] OpenSSLEngineSocketImpl Conscrypt'); - } catch (err) { - console.log('[ ] OpenSSLEngineSocketImpl Conscrypt'); - } - - // OpenSSLSocketImpl Apache Harmony - try { - const OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl'); - OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) { - console.log(' --> Bypassing OpenSSLSocketImpl Apache Harmony'); - }; - console.log('[+] OpenSSLSocketImpl Apache Harmony'); - } catch (err) { - console.log('[ ] OpenSSLSocketImpl Apache Harmony'); - } - - // PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin) - try { - const phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker'); - phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) { - console.log(' --> Bypassing PhoneGap sslCertificateChecker: ' + a); - return true; - }; - console.log('[+] PhoneGap sslCertificateChecker'); - } catch (err) { - console.log('[ ] PhoneGap sslCertificateChecker'); - } - - // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) - try { - // Bypass IBM MobileFirst {1} - const WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient'); - WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) { - console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string): ' + cert); - return; - }; - console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string)'); - } catch (err) { - console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string)'); - } - try { - // Bypass IBM MobileFirst {2} - const WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient'); - WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) { - console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string array): ' + cert); - return; - }; - console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string array)'); - } catch (err) { - console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string array)'); - } - - // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) - try { - // Bypass IBM WorkLight {1} - const worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); - worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) { - console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket): ' + a); - return; - }; - console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)'); - } catch (err) { - console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)'); - } - try { - // Bypass IBM WorkLight {2} - const worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); - worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) { - console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (cert): ' + a); - return; - }; - console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)'); - } catch (err) { - console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)'); - } - try { - // Bypass IBM WorkLight {3} - const worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); - worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) { - console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (string string): ' + a); - return; - }; - console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)'); - } catch (err) { - console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)'); - } - try { - // Bypass IBM WorkLight {4} - const worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); - worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) { - console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession): ' + a); - return true; - }; - console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)'); - } catch (err) { - console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)'); - } - - // Conscrypt CertPinManager - try { - const conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager'); - conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { - console.log(' --> Bypassing Conscrypt CertPinManager: ' + a); - return true; - }; - console.log('[+] Conscrypt CertPinManager'); - } catch (err) { - console.log('[ ] Conscrypt CertPinManager'); - } - - // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager - try { - const cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager'); - cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { - console.log(' --> Bypassing CWAC-Netsecurity CertPinManager: ' + a); - return true; - }; - console.log('[+] CWAC-Netsecurity CertPinManager'); - } catch (err) { - console.log('[ ] CWAC-Netsecurity CertPinManager'); - } - - // Worklight Androidgap WLCertificatePinningPlugin - try { - const androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin'); - androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) { - console.log(' --> Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a); - return true; - }; - console.log('[+] Worklight Androidgap WLCertificatePinningPlugin'); - } catch (err) { - console.log('[ ] Worklight Androidgap WLCertificatePinningPlugin'); - } - - // Netty FingerprintTrustManagerFactory - try { - const netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory'); - netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) { - console.log(' --> Bypassing Netty FingerprintTrustManagerFactory'); - }; - console.log('[+] Netty FingerprintTrustManagerFactory'); - } catch (err) { - console.log('[ ] Netty FingerprintTrustManagerFactory'); - } - - // Squareup CertificatePinner [OkHTTP Bypassing Squareup CertificatePinner (cert): ' + a); - return; - }; - console.log('[+] Squareup CertificatePinner (cert)'); - } catch (err) { - console.log('[ ] Squareup CertificatePinner (cert)'); - } - try { - // Bypass Squareup CertificatePinner {2} - const Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner'); - Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { - console.log(' --> Bypassing Squareup CertificatePinner (list): ' + a); - return; - }; - console.log('[+] Squareup CertificatePinner (list)'); - } catch (err) { - console.log('[ ] Squareup CertificatePinner (list)'); - } - - // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) - try { - // Bypass Squareup OkHostnameVerifier {1} - const Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier'); - Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) { - console.log(' --> Bypassing Squareup OkHostnameVerifier (cert): ' + a); - return true; - }; - console.log('[+] Squareup OkHostnameVerifier (cert)'); - } catch (err) { - console.log('[ ] Squareup OkHostnameVerifier (cert)'); - } - try { - // Bypass Squareup OkHostnameVerifier {2} - const Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier'); - Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) { - console.log(' --> Bypassing Squareup OkHostnameVerifier (SSLSession): ' + a); - return true; - }; - console.log('[+] Squareup OkHostnameVerifier (SSLSession)'); - } catch (err) { - console.log('[ ] Squareup OkHostnameVerifier (SSLSession)'); - } - - // Android WebViewClient (double bypass) - try { - // Bypass WebViewClient {1} (deprecated from Android 6) - const AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient'); - AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) { - console.log(' --> Bypassing Android WebViewClient (SslErrorHandler)'); - }; - console.log('[+] Android WebViewClient (SslErrorHandler)'); - } catch (err) { - console.log('[ ] Android WebViewClient (SslErrorHandler)'); - } - try { - // Bypass WebViewClient {2} - const AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient'); - AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) { - console.log(' --> Bypassing Android WebViewClient (WebResourceError)'); - }; - console.log('[+] Android WebViewClient (WebResourceError)'); - } catch (err) { - console.log('[ ] Android WebViewClient (WebResourceError)'); - } - - // Apache Cordova WebViewClient - try { - const CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient'); - CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) { - console.log(' --> Bypassing Apache Cordova WebViewClient'); - obj3.proceed(); - }; - } catch (err) { - console.log('[ ] Apache Cordova WebViewClient'); - } - - // Boye AbstractVerifier - try { - const boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier'); - boye_AbstractVerifier.verify.implementation = function (host, ssl) { - console.log(' --> Bypassing Boye AbstractVerifier: ' + host); - }; - } catch (err) { - console.log('[ ] Boye AbstractVerifier'); - } - - // Appmattus - try { - const appmatus_Activity = Java.use('com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor'); - appmatus_Activity['intercept'].implementation = function (a) { - console.log(' --> Bypassing Appmattus (Transparency)'); - return a.proceed(a.request()); - }; - console.log('[+] Appmattus (CertificateTransparencyInterceptor)'); - } catch (err) { - console.log('[ ] Appmattus (CertificateTransparencyInterceptor)'); - } - - try { - const CertificateTransparencyTrustManager = Java.use( - 'com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyTrustManager' - ); - CertificateTransparencyTrustManager['checkServerTrusted'].overload( - '[Ljava.security.cert.X509Certificate;', - 'java.lang.String' - ).implementation = function (x509CertificateArr, str) { - console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)'); - }; - CertificateTransparencyTrustManager['checkServerTrusted'].overload( - '[Ljava.security.cert.X509Certificate;', - 'java.lang.String', - 'java.lang.String' - ).implementation = function (x509CertificateArr, str, str2) { - console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)'); - return Java.use('java.util.ArrayList').$new(); - }; - console.log('[+] Appmattus (CertificateTransparencyTrustManager)'); - } catch (err) { - console.log('[ ] Appmattus (CertificateTransparencyTrustManager)'); - } - - console.log("Unpinning setup completed"); - console.log("---"); }); - -}, 0); +}); \ No newline at end of file