Обходим SSL Pinning на Android

Обходим SSL Pinning на Android

LOLZTEAM

Подробный гайд по обходу SSL Pinning с помощью Frida!

Статья носит образовательный характер, мы ни к чему не призываем и не обязываем. Информация представлена исключительно в ознакомительных целях.

Немного теории

По умолчанию, устанавливая SSL соединение по протоколу HTTPS, клиент проверяет сертификат сервера по двум пунктам:

  • что цепочку SSL сертификата можно проследить от вашего личного SSL сертификата через промежуточные и до корневого сертификата доверенного центра сертификации;
  • что Ваш SSL сертификат соответствует запрошенному имени хоста.

Но клиент не проверяет, точно ли данный сертификат является именно тем сертификатом, который использует ваш сервер. Сопоставление клиентом SSL сертификатов, которые находятся в хранилище доверенных сертификатов устройства, и тех, которые используются на удаленном сервере, открывает потенциальную дыру в безопасности.

Решение этой проблемы - SSL pinning – внедрение SSL сертификата, который используется на сервере, в код мобильного приложения. В этом случае приложение будет игнорировать хранилище сертификатов устройства, полагаясь только на свое хранилище и позволяя создать защищенное SSL соединение с хостом, подписанным только сертификатом, что хранится в самом приложении. 

Мы же с вами разберем, как можно обойти это ограничение, чтобы снимать сертификаты на приложениях.

Приступим

  • Для начала скачаем Python - https://www.python.org/downloads/.
  • Запускаем, ставим галочку на "Add Python 3.8 to PATH" и дальше на "Install Now".
  • Далее для того, чтобы Python нормально заработал, переходим в Параметры->Приложения и возможности->Псевдонимы выполнения приложения и снимаем тумблеры.
  • Проверяем, что Python установился, в cmd этой командой:
python --version

Теперь установим эмулятор Memu

  • Переходим на сайт https://www.memuplay.com/ и качаем свежую версию.
  • Устанавливаем себе в удобную папку эмулятор и, не забыв нажать "Decline", когда нам предложат, установить антивирус McAfee 
  • Запускаем Multi-MEmu и в настройках виртуальной машины включаем root.

Установка и настройка BURPSuite

  • Скачиваем с официального сайта BURP Suite - https://portswigger.net/burp, версию Community.
  • Переходим в "Proxy" и "Options", нажимаем "add".
  • Дальше нажимаем "OК".
  • Запускаем эмулятор. Затем устанавливаем приложение, на котором вы хотите снять сертификат.
  • В эмуляторе переходим "Настройки - WiFi - Наша_WiFi_Cеть - Расширенные настройки" и добавляем туда наш прокси, который мы выбрали выше.
  • Дальше идем в браузер пишем:
http://burpsuite
  • или наш прокси, который мы выбрали.
  • После того как скачали, идем в файловый менеджер, переименовываем с cacert.der на cacert.crt и устанавливаем его.

Теперь переходим к Frida

  • Открываем cmd и пишем туда по очереди:
1 . pip install frida
2 . pip install objection
3 . pip install frida-tools
  • Дальше качаем на сайте свежую версию adbtool - тык и распаковываем в удобную папку, в моем случае это C:\adb.
  • Сохраняем скрипт (ищи его в конце статьи) под именем fridascript.js в папке adb.
  • Переходим в эмулятор "Настройки - О планшете", кликаем по "Номеру сборки", пока вы не станете разработчиком.
  • Теперь идем в пункт настроек "Для разработчиков" и включаем "Отладку по USB".
  • Открываем cmd в папке adb.
  • И в открывшемся cmd пишем:
adb connect 127.0.0.1:21503
  • Проверим что устройство подключилась к adb , вводим еще одну команду:
adb devices
  • Дальше нам надо скачать Frida-server в соответствие с архитектурой нашего устройства, для этого впишем в cmd еще одну команду:
adb shell getprop ro.product.cpu.abi
adb push C:\adb\тут ваша версия /data/local/tmp/

adb shell chmod 777 /data/local/tmp/тут ваша версия
  •  Теперь нам надо запустить frida-server:
adb shell /data/local/tmp/тут ваша версия & 
  • Не закрывая cmd, мы запускаем новый cmd таким же способом, как и выше (из папки adb), и пишем:
frida-ps -U
  • И ищем то приложение, с которого нам нужно снять сертификат.
  • Теперь заинжектим скрип fridascript.js в приложение:
frida -U -l fridascript.js --no-paus -f тут ваше приложения
  • Мои поздравления! Вы отснифали андроид приложение!

На этом все! Надеюсь, было полезно!

Обещанный скрипт, который вам необходимо поставить.
/*  Android ssl certificate pinning bypass script for various methods
    by Maurizio Siddu
   
    Run with:
    frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause
*/

setTimeout(function() {
    Java.perform(function () {
        console.log('');
        console.log('======');
        console.log('[#] Android Bypass for various Certificate Pinning methods [#]');
        console.log('======');


        var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
        var SSLContext = Java.use('javax.net.ssl.SSLContext');
   
   
        // TrustManager (Android < 7)
        var 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 []; }
            }
        });
   
        // Prepare the TrustManager array to pass to SSLContext.init()
        var TrustManagers = [TrustManager.$new()];
        // Get a handle on the init() on the SSLContext class
        var SSLContext_init = SSLContext.init.overload(
            '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
        try {
            // 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);
            };
   
        } catch (err) {
            console.log('[-] TrustManager (Android < 7) pinner not found');
            //console.log(err);
        }

     
   
        // OkHTTPv3 (double bypass)
        try {
            var okhttp3_Activity = Java.use('okhttp3.CertificatePinner');
            okhttp3_Activity.check.overload('java.lang.String', 'java.util.List').implementation = function (str) {
                console.log('[+] Bypassing OkHTTPv3 {1}: ' + str);
                return true;
            };
            // This method of CertificatePinner.check could be found in some old Android app
            okhttp3_Activity.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (str) {
                console.log('[+] Bypassing OkHTTPv3 {2}: ' + str);
                return true;
            };
   
        } catch (err) {
            console.log('[-] OkHTTPv3 pinner not found');
            //console.log(err);
        }

   
   
        // Trustkit (triple bypass)
        try {
            var trustkit_Activity = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
            trustkit_Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str) {
                console.log('[+] Bypassing Trustkit {1}: ' + str);
                return true;
            };
            trustkit_Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str) {
                console.log('[+] Bypassing Trustkit {2}: ' + str);
                return true;
            };
            var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
            trustkit_PinningTrustManager.checkServerTrusted.implementation = function () {
                console.log('[+] Bypassing Trustkit {3}');
            };
   
        } catch (err) {
            console.log('[-] Trustkit pinner not found');
            //console.log(err);
        }
   
   
 
        // TrustManagerImpl (Android > 7)
        try {
            var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
            TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
                console.log('[+] Bypassing TrustManagerImpl (Android > 7): ' + host);
                return untrustedChain;
            };
           
        } catch (err) {
            console.log('[-] TrustManagerImpl (Android > 7) pinner not found');
            //console.log(err);
        }   
 
 
       
        // Appcelerator Titanium
        try {
            var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
            appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () {
                console.log('[+] Bypassing Appcelerator PinningTrustManager');
            };

        } catch (err) {
            console.log('[-] Appcelerator PinningTrustManager pinner not found');
            //console.log(err);
        }



        // OpenSSLSocketImpl Conscrypt
        try {
            var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
            OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) {
                console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt');
            };
       
        } catch (err) {
            console.log('[-] OpenSSLSocketImpl Conscrypt pinner not found');
            //console.log(err);       
        }


        // OpenSSLEngineSocketImpl Conscrypt
        try {
            var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
            OpenSSLSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (str1, str2) {
                console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + str2);
            };
       
        } catch (err) {
            console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found');
            //console.log(err);
        }



        // OpenSSLSocketImpl Apache Harmony
        try {
            var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
            OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) {
                console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony');
            };

        } catch (err) {
            console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found');
            //console.log(err);     
        }



        // PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin)
        try {
            var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
            phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (str) {
                console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + str);
                return true;
            };
   
        } catch (err) {
            console.log('[-] PhoneGap sslCertificateChecker pinner not found');
            //console.log(err);
        }



        // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass)
        try {
            var WLClient_Activity = Java.use('com.worklight.wlclient.api.WLClient');
            WLClient_Activity.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) {
                console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert);
                return;
            };
            WLClient_Activity.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) {
                console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert);
                return;
            };

        } catch (err) {
            console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey pinner not found');
            //console.log(err);
        }



        // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass)
        try {
            var worklight_Activity = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
            worklight_Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (str) {
                console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + str);               
                return;
            };
            worklight_Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str) {
                console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + str);
                return;
            };
            worklight_Activity.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (str) {
                console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + str);
                return;
            };
            worklight_Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str) {
                console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + str);
                return true;
            };

        } catch (err) {
            console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning pinner not found');
            //console.log(err);
        }



        // Conscrypt CertPinManager
        try {
            var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
            conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (str) {
                console.log('[+] Bypassing Conscrypt CertPinManager: ' + str);
                return true;
            };
   
        } catch (err) {
            console.log('[-] Conscrypt CertPinManager pinner not found');
            //console.log(err);
        }



        // CWAC-Netsecurity (unofficial back-port pinner for Android < 4.2) CertPinManager
        try {
            var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
            cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (str) {
                console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + str);
                return true;
            };
   
        } catch (err) {
            console.log('[-] CWAC-Netsecurity CertPinManager pinner not found');
            //console.log(err);
        }



        // Worklight Androidgap WLCertificatePinningPlugin
        try {
            var 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 (str) {
                console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + str);
                return true;
            };
   
        } catch (err) {
            console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found');
            //console.log(err);
        }



        // Netty FingerprintTrustManagerFactory
        try {
            var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
            //NOTE: sometimes this below implementation could be useful 
            //var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory');
            netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) {
                console.log('[+] Bypassing Netty FingerprintTrustManagerFactory');
            };

        } catch (err) {
            console.log('[-] Netty FingerprintTrustManagerFactory pinner not found');
            //console.log(err);
        }



        // Squareup CertificatePinner [OkHTTP < v3] (double bypass)
        try {
            var Squareup_CertificatePinner_Activity = Java.use('com.squareup.okhttp.CertificatePinner');
            Squareup_CertificatePinner_Activity.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (str1, str2) {
                console.log('[+] Bypassing Squareup CertificatePinner {1}: ' + str1);
                return;
            };

            Squareup_CertificatePinner_Activity.check.overload('java.lang.String', 'java.util.List').implementation = function (str1, str2) {
                console.log('[+] Bypassing Squareup CertificatePinner {2}: ' + str1);
                return;
            };
       
        } catch (err) {
            console.log('[-] Squareup CertificatePinner pinner not found');
            //console.log(err);
        }



        // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass)
        try {
            var Squareup_OkHostnameVerifier_Activity = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
            Squareup_OkHostnameVerifier_Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str1, str2) {
                console.log('[+] Bypassing Squareup OkHostnameVerifier {1}: ' + str1);
                return true;
            };
           
            Squareup_OkHostnameVerifier_Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str1, str2) {
                console.log('[+] Bypassing Squareup OkHostnameVerifier {2}: ' + str1);
                return true;
            };
           
        } catch (err) {
            console.log('[-] Squareup OkHostnameVerifier pinner not found');
            //console.log(err);
        }


       
        // Android WebViewClient
        try {
            var AndroidWebViewClient_Activity = Java.use('android.webkit.WebViewClient');
            AndroidWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
                console.log('[+] Bypassing Android WebViewClient');
            };
           
        } catch (err) {
            console.log('[-] Android WebViewClient pinner not found');
            //console.log(err);
        }



        // Apache Cordova WebViewClient
        try {
            var 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 pinner not found');
            //console.log(err):
        }



        // Boye AbstractVerifier
        try {
            var 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 pinner not found');
            //console.log(err):
        }

     
    });
   
}, 0);


Больше интересных статей на нашем форуме: https://lolz.guru/articles/

Подписывайтесь на канал и делитесь ссылкой на статью с друзьями!

Report Page