frida绕过ssl pinning抓取https

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校验的步骤如下:

  1. 安装python3.x,并在python环境中安装frida:
pip install frida
pip install frida-tools

在这里插入图片描述

  1. 下载frida-server,并使用adb命令push到/data/local/tmp目录下,并运行:
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的版本号必须要一致,否则会提示如下错误: 注意:此处的fridaserverfrida的版本号必须要一致,否则会提示如下错误:

在这里插入图片描述
当然也可以下载相应的gadget包并放到相应的目录下面,可以消除上图中的错误。

frida-server下载地址:https://github.com/frida/frida/releases
在这里插入图片描述

  1. 执行如下命令,即可hook并绕过app对ssl pin的检测:
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

参考链接:
https://www.cnblogs.com/Eeyhan/p/12916162.html

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Frida逆向与抓包实战是一本关于移动端应用逆向和抓包技术的实践指南。本书主要介绍了Frida这一强大的逆向工具的使用方法,并结合实际案例进行讲解。 首先,Frida是一款强大的动态分析工具,可以在运行中的应用程序中注入自定义的JavaScript代码,从而实现应用程序的行为监控与控制。本书以Frida为基础,详细介绍了如何使用Frida进行Android和iOS应用程序的逆向分析。读者可以学习到如何使用Frida的API来动态修改应用程序的行为,如动态调试、函数替换、Hook等。 其次,本书还介绍了抓包技术在移动应用逆向中的应用。通过抓包技术,读者可以捕获应用程序与服务器之间的通信数据,分析应用程序的网络请求和响应,了解应用程序的数据传输方式和协议。本书讲解了常用的抓包工具和技术,如使用Fiddler、Charles等工具进行HTTPS抓包,分析加密通信数据等。 本书还通过实例演示了如何使用Frida和抓包技术进行实际的应用分析。例如,通过使用Frida获取应用程序的敏感数据并进行修改,探测应用程序中的漏洞,发现应用程序的安全问题等。通过抓包技术,读者可以分析应用程序的通信过程,了解应用程序与服务器之间的交互,发现潜在的数据泄漏风险等。 综上所述,Frida逆向与抓包实战是一本介绍了Frida工具的基本原理和实际应用的实践指南。通过学习本书,读者可以了解到Frida的使用方法以及如何利用抓包技术进行移动应用逆向分析,并能够应用这些技术进行实际的应用分析与调试。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值