mirror of
https://github.com/httptoolkit/frida-interception-and-unpinning.git
synced 2026-10-09 01:12:26 +02:00
Convert all core unpinning patches to a structured declarative format
This notably also adds a NetworkSecurityConfig hook en route, which disables even reading the pins from the config in the first place.
This commit is contained in:
+395
-528
@@ -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<v3] (double bypass)
|
||||
try {
|
||||
// Bypass Squareup CertificatePinner {1}
|
||||
const Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
|
||||
Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
|
||||
console.log(' --> 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);
|
||||
});
|
||||
Reference in New Issue
Block a user