赞
踩
Charles,burp suite,fiddler等https抓包软件的实现思路,都是通过导入根证书+https代理的方式实现的。
一般而言,导入根证书、使用https代理即可实现大部分https抓包需求,但是有些app带有ssl pinning验证,此时需要利用hook机制,来绕过ssl pinning验证。
网页版app都是使用浏览器的接口,一旦浏览器信任该证书(或者强制浏览器信任),作为上层的web应用是没法拒绝信任该证书的,而非web端的app可以有自己的判断和处理。因此,ssl pinning的目标都是一些非web版app,他们可以严格的校验证书链是否可信任。frida通过hook android(或者ios),绕过了系统的某些校验接口,让代理端被客户端信任,实现https代理和流量劫持。
废话不多说(实际上都是前人帖子的总结,也没得说)。
frida绕过ssl pinning校验的步骤如下:
pip install frida
pip install frida-tools
adb push frida-server /data/local/tmp
chmod 777 ./frida-server
./frida-server
注意:此处的 f r i d a − s e r v e r 和 f r i d a 的版本号必须要一致,否则会提示如下错误: \color{red}注意:此处的frida-server和frida的版本号必须要一致,否则会提示如下错误: 注意:此处的frida−server和frida的版本号必须要一致,否则会提示如下错误:
当然也可以下载相应的gadget包并放到相应的目录下面,可以消除上图中的错误。
frida-server下载地址:https://github.com/frida/frida/releases
frida -U -f packagename -l ./ssl.js -no-pause
比如:
frida -U -f me.ele.napos -l d:\adbtest\ssl.js -no-pause
ssl.js内容:
Java.perform(function() { /* hook list: 1.SSLcontext 2.okhttp 3.webview 4.XUtils 5.httpclientandroidlib 6.JSSE 7.network\_security\_config (android 7.0+) 8.Apache Http client (support partly) 9.OpenSSLSocketImpl 10.TrustKit 11.Cronet */ // Attempts to bypass SSL pinning implementations in a number of // ways. These include implementing a new TrustManager that will // accept any SSL certificate, overriding OkHTTP v3 check() // method etc. var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier'); var SSLContext = Java.use('javax.net.ssl.SSLContext'); var quiet_output = false; // Helper method to honor the quiet flag. function quiet_send(data) { if (quiet_output) { return; } send(data) } // Implement a new TrustManager // ref: https://gist.github.com/oleavr/3ca67a173ff7d207c6b8c3b0ca65a9d8 // Java.registerClass() is only supported on ART for now(201803). 所以android 4.4以下不兼容,4.4要切换成ART使用. /* 06-07 16:15:38.541 27021-27073/mi.sslpinningdemo W/System.err: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing 06-07 16:15:38.542 27021-27073/mi.sslpinningdemo W/System.err: at android.net.http.X509TrustManagerExtensions.<init>(X509TrustManagerExtensions.java:73) at mi.ssl.MiPinningTrustManger.<init>(MiPinningTrustManger.java:61) 06-07 16:15:38.543 27021-27073/mi.sslpinningdemo W/System.err: at mi.sslpinningdemo.OkHttpUtil.getSecPinningClient(OkHttpUtil.java:112) at mi.sslpinningdemo.OkHttpUtil.get(OkHttpUtil.java:62) at mi.sslpinningdemo.MainActivity$1$1.run(MainActivity.java:36) */ var X509Certificate = Java.use("java.security.cert.X509Certificate"); var TrustManager; try { TrustManager = Java.registerClass({ name: 'org.wooyun.TrustManager', implements: [X509TrustManager], methods: { checkClientTrusted: function(chain, authType) {}, checkServerTrusted: function(chain, authType) {}, getAcceptedIssuers: function() { // var certs = [X509Certificate.$new()]; // return certs; return []; } } }); } catch (e) { quiet_send("registerClass from X509TrustManager >>>>>>>> " + e.message); } // Prepare the TrustManagers array to pass to SSLContext.init() var TrustManagers = [TrustManager.$new()]; try { // Prepare a Empty SSLFactory var TLS_SSLContext = SSLContext.getInstance("TLS"); TLS_SSLContext.init(null, TrustManagers, null); var EmptySSLFactory = TLS_SSLContext.getSocketFactory(); } catch (e) { quiet_send(e.message); } send('Custom, Empty TrustManager ready'); // 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'); // Override the init method, specifying our new TrustManager SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) { quiet_send('Overriding SSLContext.init() with the custom TrustManager'); SSLContext_init.call(this, null, TrustManagers, null); }; /*** okhttp3.x unpinning ***/ // Wrap the logic in a try/catch as not all applications will have // okhttp as part of the app. try { var CertificatePinner = Java.use('okhttp3.CertificatePinner'); quiet_send('OkHTTP 3.x Found'); CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() { quiet_send('OkHTTP 3.x check() called. Not throwing an exception.'); } } catch (err) { // If we dont have a ClassNotFoundException exception, raise the // problem encountered. if (err.message.indexOf('ClassNotFoundException') === 0) { throw new Error(err); } } // Appcelerator Titanium PinningTrustManager // Wrap the logic in a try/catch as not all applications will have // appcelerator as part of the app. try { var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager'); send('Appcelerator Titanium Found'); PinningTrustManager.checkServerTrusted.implementation = function() { quiet_send('Appcelerator checkServerTrusted() called. Not throwing an exception.'); } } catch (err) { // If we dont have a ClassNotFoundException exception, raise the // problem encountered. if (err.message.indexOf('ClassNotFoundException') === 0) { throw new Error(err); } } /*** okhttp unpinning ***/ try { var OkHttpClient = Java.use("com.squareup.okhttp.OkHttpClient"); OkHttpClient.setCertificatePinner.implementation = function(certificatePinner) { // do nothing quiet_send("OkHttpClient.setCertificatePinner Called!"); return this; }; // Invalidate the certificate pinnet checks (if "setCertificatePinner" was called before the previous invalidation) var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner"); CertificatePinner.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(p0, p1) { // do nothing quiet_send("okhttp Called! [Certificate]"); return; }; CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(p0, p1) { // do nothing quiet_send("okhttp Called! [List]"); return; }; } catch (e) { quiet_send("com.squareup.okhttp not found"); } /*** WebView Hooks ***/ /* frameworks/base/core/java/android/webkit/WebViewClient.java */ /* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */ var WebViewClient = Java.use("android.webkit.WebViewClient"); WebViewClient.onReceivedSslError.implementation = function(webView, sslErrorHandler, sslError) { quiet_send("WebViewClient onReceivedSslError invoke"); //执行proceed方法 sslErrorHandler.proceed(); return; }; WebViewClient.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function(a, b, c, d) { quiet_send("WebViewClient onReceivedError invoked"); return; }; WebViewClient.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function() { quiet_send("WebViewClient onReceivedError invoked"); return; }; /*** JSSE Hooks ***/ /* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */ /* public final TrustManager[] getTrustManager() */ /* TrustManagerFactory.getTrustManagers maybe cause X509TrustManagerExtensions error */ // var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory"); // TrustManagerFactory.getTrustManagers.implementation = function(){ // quiet_send("TrustManagerFactory getTrustManagers invoked"); // return TrustManagers; // } var HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ /* public void setDefaultHostnameVerifier(HostnameVerifier) */ HttpsURLConnection.setDefaultHostnameVerifier.implementation = function(hostnameVerifier) { quiet_send("HttpsURLConnection.setDefaultHostnameVerifier invoked"); return null; }; /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ /* public void setSSLSocketFactory(SSLSocketFactory) */ HttpsURLConnection.setSSLSocketFactory.implementation = function(SSLSocketFactory) { quiet_send("HttpsURLConnection.setSSLSocketFactory invoked"); return null; }; /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ /* public void setHostnameVerifier(HostnameVerifier) */ HttpsURLConnection.setHostnameVerifier.implementation = function(hostnameVerifier) { quiet_send("HttpsURLConnection.setHostnameVerifier invoked"); return null; }; /*** Xutils3.x hooks ***/ //Implement a new HostnameVerifier var TrustHostnameVerifier; try { TrustHostnameVerifier = Java.registerClass({ name: 'org.wooyun.TrustHostnameVerifier', implements: [HostnameVerifier], method: { verify: function(hostname, session) { return true; } } }); } catch (e) { //java.lang.ClassNotFoundException: Didn't find class "org.wooyun.TrustHostnameVerifier" quiet_send("registerClass from hostnameVerifier >>>>>>>> " + e.message); } try { var RequestParams = Java.use('org.xutils.http.RequestParams'); RequestParams.setSslSocketFactory.implementation = function(sslSocketFactory) { sslSocketFactory = EmptySSLFactory; return null; } RequestParams.setHostnameVerifier.implementation = function(hostnameVerifier) { hostnameVerifier = TrustHostnameVerifier.$new(); return null; } } catch (e) { quiet_send("Xutils hooks not Found"); } /*** httpclientandroidlib Hooks ***/ try { var AbstractVerifier = Java.use("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier"); AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String', '[Ljava.lang.String', 'boolean').implementation = function() { quiet_send("httpclientandroidlib Hooks"); return null; } } catch (e) { quiet_send("httpclientandroidlib Hooks not found"); } /*** android 7.0+ network_security_config TrustManagerImpl hook apache httpclient partly ***/ var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl"); // try { // var Arrays = Java.use("java.util.Arrays"); // //apache http client pinning maybe baypass // //https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#471 // TrustManagerImpl.checkTrusted.implementation = function (chain, authType, session, parameters, authType) { // quiet_send("TrustManagerImpl checkTrusted called"); // //Generics currently result in java.lang.Object // return Arrays.asList(chain); // } // // } catch (e) { // quiet_send("TrustManagerImpl checkTrusted nout found"); // } try { // Android 7+ TrustManagerImpl TrustManagerImpl.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) { quiet_send("TrustManagerImpl verifyChain called"); // Skip all the logic and just return the chain again :P //https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2017/november/bypassing-androids-network-security-configuration/ // https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#L650 return untrustedChain; } } catch (e) { quiet_send("TrustManagerImpl verifyChain nout found below 7.0"); } // OpenSSLSocketImpl try { var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl'); OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, authMethod) { quiet_send('OpenSSLSocketImpl.verifyCertificateChain'); } quiet_send('OpenSSLSocketImpl pinning') } catch (err) { quiet_send('OpenSSLSocketImpl pinner not found'); } // Trustkit try { var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier"); Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(str) { quiet_send('Trustkit.verify1: ' + str); return true; }; Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(str) { quiet_send('Trustkit.verify2: ' + str); return true; }; quiet_send('Trustkit pinning') } catch (err) { quiet_send('Trustkit pinner not found') } try { //cronet pinner hook //weibo don't invoke var netBuilder = Java.use("org.chromium.net.CronetEngine$Builder"); //https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/CronetEngine.Builder.html#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean) netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.implementation = function(arg) { //weibo not invoke console.log("Enables or disables public key pinning bypass for local trust anchors = " + arg); //true to enable the bypass, false to disable. var ret = netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true); return ret; }; netBuilder.addPublicKeyPins.implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) { console.log("cronet addPublicKeyPins hostName = " + hostName); //var ret = netBuilder.addPublicKeyPins.call(this,hostName, pinsSha256,includeSubdomains, expirationDate); //this 是调用 addPublicKeyPins 前的对象吗? Yes,CronetEngine.Builder return this; }; } catch (err) { console.log('[-] Cronet pinner not found') } });
当然,除了上述步骤,可能还需要:导入根证书,设置代理等。上述过程中若遇到如下错误:
则需要执行:pip install contextvars
可能会用的命令:
显示cpu信息:
cat /proc/cupinfo
adb shell getprop ro.product.cpu.abi
查看frida可以ssl pin的进程:
frida-ps -U
tcpdump命令抓包:
tcpdump -i wlan0 -s 0 -w /sdcard/test.pcap
为了方便操作,可能要安装RE管理器等软件:
http://www.liulan.net/az/22446.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。