|
本帖最后由 wangqiang 于 2022-4-7 10:47 编辑
干货 | Android HTTPS认证的N种方式和对抗方法总结
Ch3nYe HACK学习呀
2022-04-06 13:38
转载自https://mp.weixin.qq.com/s?__biz=MzI5MDU1NDk2MA==&mid=2247504370&idx=1&sn=87aff9bc4e97d4f1d7cf06b6a36cdb1c&chksm=ec1c84cddb6b0ddba3f0449b31b19c06301d1024c5fc1623b3dcaf01654bd73a887c6c6859dd&mpshare=1&scene=23&srcid=0406Riyk19EdvCe1TVYVBvUt&sharer_sharetime=1649223739786&sharer_shareid=ee83a55e0b955b99e8343acbb61916b7#rd
0x0 前言本文将通过一个Demo APP实现Android中各种HTTPS证书认证,并尝试通过各种方式绕过证书校验和证书绑定。
目的是自我总结与知识点回顾,如果你正在学习这方面的知识,那这篇文章能帮助你从实践中体会Android APP中对HTTPS的防抓包技术及其对抗技术。
a. 前置知识阅读本文之前需要的前置知识:- HTTPS
- Android 开发技能(一点点)
- Frida Hook
- Android 代理抓包技能
b. 设备环境:- RedmiK305G Android10(root) with Magisk
- 代理端BurpSuite Pro v2.0.11 & Fiddler v5.0
- PC Windows 10
- 虚拟机 Kali Linux 2021
- frida 14.2.16
c. 简单配置简单介绍一下我的证书配置方法,并不适合所有人,根据自己的设备配置,总而言之目的就是将代理软件的证书信任为系统证书。
- 将Fiddler 证书导入Android 手机,安装为用户证书
- 将BurpSuite 证书导入Android 手机,安装为用户证书
- Magisk 开启Always Trust User Certificates 模块
- 手机和PC在同一局域网下
- PC开启代理软件,配置好监听地址和端口
- 手机在WIFI网络中设置代理
d. Demo APP建议阅读下文代码片段时参考APP源码
APP 源码:https://github.com/Ch3nYe/httpstest
APP Demo 截图:
0x1 HTTP 直连本文中使用的https访问组件是okhttp3,直接访问http协议的url就可以了。不需要进行任何多余的配置,只需要配置好代理,http流量会被代理软件抓到。
- /*
- * http协议
- */
- button_http_connect.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void run() {
- OkHttpClient mClient = client.newBuilder().build();
- Request request = new Request.Builder()
- .url("http://www.vulnweb.com/")
- .build();
- Message message = new Message();
- message.what = 1;
- try (Response response = mClient.newCall(request).execute()) {
- message.obj = "http connect access vulnweb.com success";
- Log.d(TAG, "http connect access vulnweb.com success return code:"+response.code());
- } catch (IOException e) {
- message.obj = "http connect access vulnweb.com failed";
- Log.d(TAG, "http connect access vulnweb.com failed");
- e.printStackTrace();
- }
- mHandler.sendMessage(message);
- }
- }).start();
- }
- });
复制代码
成功访问时,APP界面上会显示http connect access vulnweb.com success
AS(AndroidStudio)中查看日志会看到打印类似 2021-04-30 21:25:38.888 8351-8516/com.example.httpstest D/[+]MainActivity: http connect access vulnweb.com success return code:200
上述代码中的message对象的目的是:使用Binder服务从子线程,将HTTP/HTTPS请求结果发送到主线程以改变UI。处理函数Handler的实现如下:
- // 注册Handler处理从thread中返回的url请求结果
- @SuppressLint("HandlerLeak") final Handler mHandler = new Handler(){
- public void handleMessage(Message msg) {
- // 处理消息
- super.handleMessage(msg);
- switch (msg.what) {
- case 1:
- textView.setText((CharSequence) msg.obj); break;
- }
- }
- };
复制代码
0x2 HTTPS 忽略证书验证
正常人不会忽略证书验证,写这个功能纯粹是为了实验而实验。
- <div>/*</div><div>* https协议
- * 忽略证书验证
- */
- button_https_connect_without_ca.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable(){
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void run() {
- OkHttpClient mClient = client.newBuilder().sslSocketFactory(HttpsTrustAllCerts.createSSLSocketFactory(),new HttpsTrustAllCerts()).hostnameVerifier(new HttpsTrustAllCerts.TrustAllHostnameVerifier()).build();
- Request request = new Request.Builder()
- .url("https://www.baidu.com/?q=trustAllCerts")
- .build();
- Message message = new Message();
- message.what = 1;
- try (Response response = mClient.newCall(request).execute()) {
- message.obj = "https connect without ca success";
- Log.d(TAG, "https connect without ca success return code:"+response.code());
- } catch (IOException e) {
- message.obj = "https connect without ca failed";
- Log.d(TAG, "https connect without ca failed");
- e.printStackTrace();
- }
- mHandler.sendMessage(message);
- }
- }).start();
- }
- });</div>
复制代码
HttpsTrustAllCerts对象实现如下,重写checkClientTrusted、checkServerTrusted方法,使其验证逻辑为空,
重写域名验证器TrustAllHostnameVerifier 的verify方法,总是返回true,达到信任所有证书的效果:
- public class HttpsTrustAllCerts implements X509TrustManager {
- @SuppressLint("TrustAllX509TrustManager")
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
- @SuppressLint("TrustAllX509TrustManager")
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // 验证服务端证书需要重写该函数
- }
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0]; //返回长度为0的数组,相当于return null
- }
- public static SSLSocketFactory createSSLSocketFactory() { // SSLSocketFactory 创建器
- SSLSocketFactory sSLSocketFactory = null;
- try {
- SSLContext sc = SSLContext.getInstance("TLS");
- sc.init(null, new TrustManager[]{new HttpsTrustAllCerts()},new SecureRandom());
- sSLSocketFactory = sc.getSocketFactory();
- } catch (Exception e) {
- }
- return sSLSocketFactory;
- }
- public static class TrustAllHostnameVerifier implements HostnameVerifier { // 域名验证器
- @Override
- public boolean verify(String s, SSLSession sslSession) {
- return true;
- }
- }
- }
复制代码
忽略证书校验的https请求和使用http协议的请求报文一样,可以通过直接设置网络代理抓包解密明文。
0x3 HTTPS 系统证书校验
OkHttp3框架发起HTTPS请求时,默认就是使用的系统信任库证书链对服务端返回的证书进行验证,实现如下:
- /*
- * https协议
- * 默认证书链校验,只信任系统CA(根证书)
- *
- * tips: OKHTTP默认的https请求使用系统CA验证服务端证书(Android7.0以下还信任用户证书,Android7.0开始默认只信任系统证书)
- */
- button_https_connect_with_system_ca.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable(){
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void run() {
- Request request = new Request.Builder()
- .url("https://www.baidu.com/?q=defaultCerts")
- .build();
- Message message = new Message();
- message.what = 1;
- try (Response response = client.newCall(request).execute()) {
- message.obj = "https connect with system ca success";
- Log.d(TAG, "https connect with system ca success return code:"+response.code());
- } catch (IOException e) {
- message.obj = "https connect with system ca failed";
- Log.d(TAG, "https connect with system ca failed");
- e.printStackTrace();
- }
- mHandler.sendMessage(message);
- }
- }).start();
- }
- });
复制代码
此时需要安装代理软件的证书到系统证书目录,前面说过我本机已经配置两个抓包软件的证书到系统证书列表了,所以仍然可以抓包解密明文。
0x4 SSL PINNING(代码校验)
SSL PINNING 就是说通过客户端检查服务端证书是否真的是服务端证书来判断是否被中间人攻击。
由于客户端需要验证服务端证书的正确性,那大原则上就是说客户端必须要有能判断正确性的依据。对于Android APP来说通常有两种方式:下面的代码段也是通过这两种方式进行了证书验证。这样代理软件充当服务端的时候发给APP的证书就不能通过SSL PINNING验证。证书的获取方式可以参考代码中的注释。- <div>/*</div><div>* https协议 SSL Pinning
- * 证书公钥绑定:验证证书公钥 baidu.com 使用CertificatePinner
- * 证书文件绑定:验证证书文件 bing.com 使用SSLSocketFactory
- */
- button_SSL_PINNING_with_key.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable(){
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void run() {
- final String CA_DOMAIN = "www.baidu.com";
- //获取目标公钥: openssl s_client -connect <a href="http://www.baidu.com:443" target="_blank">www.baidu.com:443</a> -servername <a href="http://www.baidu.com" target="_blank">www.baidu.com</a> | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
- final String CA_PUBLIC_KEY = "sha256//558pd1Y5Vercv1ZoSqOrJWDsh9sTMEolM6T8csLucQ=";
- //只校验公钥
- CertificatePinner pinner = new CertificatePinner.Builder()
- .add(CA_DOMAIN, CA_PUBLIC_KEY)
- .build();
- OkHttpClient pClient = client.newBuilder().certificatePinner(pinner).build();
- Request request = new Request.Builder()
- .url("https://www.baidu.com/?q=SSLPinningCode")
- .build();
- Message message = new Message();
- message.what = 1;
- try (Response response = pClient.newCall(request).execute()) {
- message.obj = "https SSL_PINNING_with_key access baidu.com success";
- Log.d(TAG, "https SSL_PINNING_with_key access baidu.com success return code:"+response.code());
- } catch (IOException e) {
- message.obj = "https SSL_PINNING_with_key access baidu.com failed";
- Log.d(TAG, "https SSL_PINNING_with_key access baidu.com failed");
- e.printStackTrace();
- }
- try {
- // 获取证书输入流
- // 获取证书 openssl s_client -connect bing.com:443 -servername bing.com | openssl x509 -out bing.pem
- InputStream openRawResource = getApplicationContext().getResources().openRawResource(R.raw.bing); //R.raw.bing是bing.com的正确证书,R.raw.bing2_so是hostname=bing.com的so.com的证书,可视为用作测试的虚假bing.com证书
- Certificate ca = CertificateFactory.getInstance("X.509").generateCertificate(openRawResource);
- // 创建 Keystore 包含我们的证书
- KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
- keyStore.load(null, null);
- keyStore.setCertificateEntry("ca", ca);
- // 创建一个 TrustManager 仅把 Keystore 中的证书 作为信任的锚点
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // 建议不要使用自己实现的X509TrustManager,而是使用默认的X509TrustManager
- trustManagerFactory.init(keyStore);
- // 用 TrustManager 初始化一个 SSLContext
- sslContext = SSLContext.getInstance("TLS"); //定义:public static SSLContext sslContext = null;
- sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
- OkHttpClient pClient2 = client.newBuilder().sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagerFactory.getTrustManagers()[0]).build();
- Request request2 = new Request.Builder()
- .url("https://www.bing.com/?q=SSLPinningCAfile")
- .build();
- try (Response response2 = pClient2.newCall(request2).execute()) {
- message.obj += "\nhttps SSL_PINNING_with_CA_file access bing.com success";
- Log.d(TAG, "https SSL_PINNING_with_CA_file access bing.com success return code:"+response2.code());
- } catch (IOException e) {
- message.obj += "\nhttps SSL_PINNING_with_CA_file access bing.com failed";
- Log.d(TAG, "https SSL_PINNING_with_CA_file access bing.com failed");
- e.printStackTrace();
- }
- } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException | KeyManagementException e) {
- e.printStackTrace();
- }
- mHandler.sendMessage(message);
- }
- }).start();
- }
- });</div>
复制代码
此时可以使用Frida对上述证书绑定进行动作Hook,阻断绑定,hook代码在0x-1附录。
0x5 SSL PINNING(配置文件)
通过res/xml/network_security_config.xml配置文件对证书进行校验是官方推荐使用的方法,配置方式还是可以为两种(同上)xml 配置如下所示:
- <network-security-config xmlns:tools="http://schemas.android.com/tools">
- <!--允许http访问-->
- <base-config cleartextTrafficPermitted="true"
- tools:ignore="InsecureBaseConfiguration" />
- <!--证书校验-->
- <domain-config>
- <domain includeSubdomains="true">sogou.com</domain>
- <trust-anchors>
- <!--获取证书: openssl s_client -connect sogou.com:443 -servername sogou.com | openssl x509 -out sogou.pem-->
- <certificates src="@raw/sogou"/>
- </trust-anchors>
- </domain-config>
- <!--公钥校验-->
- <domain-config>
- <domain includeSubdomains="true">zhihu.com</domain>
- <!--zhihu.com公钥校验
- 获取公钥: openssl s_client -connect zhihu.com:443 -servername zhihu.com | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
- -->
- <pin-set expiration="2099-01-01"
- tools:ignore="MissingBackupPin">
- <pin digest="SHA-256">vzXV96/gpZMyyNNhyTdjtX0/NUVYTtmYqWcVVaUtTdQ=</pin>
- </pin-set>
- </domain-config>
- </network-security-config>
复制代码
这样配置好以后就可以对上述指定的域名进行https访问,将会自动对证书进行校验,请求代码:
- /*
- * https协议 SSL PINNING
- * 证书绑定验证 配置在 @xml/network_security_config 中
- * sogou.com 使用 sogou.pem 验证证书
- * so.com 使用 sha256 key 验证
- */
- button_SSL_PINNING_with_CA.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable(){
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void run() {
- OkHttpClient pClient = client.newBuilder().build();
- Request request = new Request.Builder()
- .url("https://www.sogou.com/web?query=SSLPinningXML")
- .build();
- Request request2 = new Request.Builder()
- .url("https://www.zhihu.com/")
- .build();
- Message message = new Message();
- message.what = 1;
- try (Response response = pClient.newCall(request).execute()) {
- message.obj = "https SSL_PINNING_with_CA, config in xml with CA.pem file access sogou.com success";
- Log.d(TAG, "https SSL_PINNING_with_CA, config in xml with CA.pem file access sogou.com success return code:"+response.code());
- } catch (IOException e) {
- message.obj = "https SSL_PINNING_with_CA, config in xml with CA.pem file access sogou.com failed";
- Log.d(TAG, "https SSL_PINNING_with_CA, config in xml with CA.pem file access sogou.com failed");
- e.printStackTrace();
- }
- try (Response response = pClient.newCall(request2).execute()) {
- message.obj += "\nhttps SSL_PINNING_with_CA, config in xml with key access zhihu.com success";
- Log.d(TAG, "https SSL_PINNING_with_CA, config in xml with key access zhihu.com success return code:"+response.code());
- } catch (IOException e) {
- message.obj += "\nhttps SSL_PINNING_with_CA, config in xml with key access zhihu.com failed";
- Log.d(TAG, "https SSL_PINNING_with_CA, config in xml with key access zhihu.com failed");
- e.printStackTrace();
- }
- mHandler.sendMessage(message);
- }
- }).start();
- }
- });
复制代码
该证书绑定实现,绕过方式同0x4 SSL PINNING(代码校验)可以使用frida hook unpinning。
0x6 HTTPS 双向验证
双向验证,顾名思义就是客户端验证服务器端证书的正确性,服务器端也验证客户端的证书正确性,所以大原则上客户端要持有服
务器端证书,服务端也要持有客户端的证书,对于Android APP来说打包发布的时候既要内置一个服务端证书也要生成一个客户端证
书给服务器存储起来。这种双向认证非常可以做到非常高的安全性,但是同时服务端要想保持所有服务端的证书比较困难,因此这种
方式只适用于某些点对点的高安全性需求的通信场合,对于Android APP来说可能是某类高机密性的内网业务才会使用这种双向HTTPS认证。
接下来我们需要实现一个server模拟HTTPS双向认证。首先通过以下命令生成一对证书。
服务端证书:
- openssl genrsa -out server-key.key 2048
- openssl req -new -out server-req.csr -key server-key.key
- openssl x509 -req -in server-req.csr -out server-cert.cer -signkey server-key.key -CAcreateserial -days 3650<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码
客户端证书:
- openssl genrsa -out client-key.key 2048
- openssl req -new -out client-req.csr -key client-key.key
- openssl x509 -req -in client-req.csr -out client-cert.cer -signkey client-key.key -CAcreateserial -days 3650
复制代码
生成客户端带密码的p12证书(这步很重要,双向认证的话,浏览器访问时候要导入该证书才行;可能某些Android系统版本请求的时候需要把它转成bks来请求双向认证,我的设备用p12格式是可行的):
openssl pkcs12 -export -clcerts -in client-cert.cer -inkey client-key.key -out client.p12
这里你也可以选择使用我生成好的证书,需要使用的证书都在源码certs目录,我的client.p12密码是clientpassword,server证书的密码是serverpassword。
服务端代码:
- import os
- import sys
- import ssl
- from http.server import HTTPServer, BaseHTTPRequestHandler
- #服务端证书和私钥
- serverCerts = "%s\\certs\\server-cert.cer" % os.getcwd()
- serverKey = "%s\\certs\\server-key.key" % os.getcwd()
- #客户端证书
- clientCerts = "%s\\certs\\client-cert.cer" % os.getcwd()
- class RequestHandler(BaseHTTPRequestHandler):
- def _writeheaders(self):
- self.send_response(200)
- self.send_header('Content-type','text/plain')
- self.end_headers()
- def do_GET(self):
- self._writeheaders()
- self.wfile.write("OK".encode("utf-8"))
- def main():
- if (len(sys.argv) != 2):
- port = 443
- else:
- port = sys.argv[1]
- server_address = ("0.0.0.0", int(port))
- server = HTTPServer(server_address, RequestHandler)
- #双向校验
- server.socket = ssl.wrap_socket(server.socket, certfile = serverCerts, server_side = True,
- keyfile = serverKey,
- cert_reqs = ssl.CERT_REQUIRED,
- ca_certs = clientCerts,
- do_handshake_on_connect = False
- )
- print("Starting server, listen at: %s:%s" % server_address)
- server.serve_forever()
- if __name__ == "__main__":
- main()
复制代码
使用python启动server,在windows上运行可能报错,大概率是由于防火墙禁止启用443端口。
OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。
所以我的方案是在VMware虚拟机中启动这个server,然后再宿主机配置hosts,添加主机域名
<虚拟机IP> www.test.com
宿主机安装client.p12证书(windows双击安装好方便),然后使用浏览器访问 www.test.com
然后你就选这个,就可以访问了,访问成功会返回OK字样的空白页。服务端日志:
尽管输出ERROR但是还是访问成功了,错误原因应该是证书为自签名证书,客户端并不想认可这个没娘的证书。
如果你能做到这里说明你已经正确实现了HTTPS双向认证,接下来我们要在Android APP上复现。
- /*
- * 双向校验
- * 因该测试是自建服务器并自签名,所以需要先在res/xml/network_security_config中配置信任服务端证书
- */
- button_https_twoway.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable(){
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void run() {
- X509TrustManager trustManager = null;
- try {
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- trustManagerFactory.init((KeyStore) null);
- TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
- if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
- throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
- }
- trustManager = (X509TrustManager) trustManagers[0];
- } catch (Exception e) {
- e.printStackTrace();
- }
- OkHttpClient mClient = client.newBuilder().sslSocketFactory(Objects.requireNonNull(ClientSSLSocketFactory.getSocketFactory(getApplicationContext())), Objects.requireNonNull(trustManager)).hostnameVerifier(new HostnameVerifier() {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
- return hv.verify("www.test.com", session);
- }
- }).build();
- Request request = new Request.Builder()
- .url("https://www.test.com/?q=TwoWayVerify")
- .build();
- Message message = new Message();
- message.what = 1;
- try (Response response = mClient.newCall(request).execute()) {
- Log.d("TestReq", response.peekBody(2048).string());
- message.obj = "请求成功: " + response.peekBody(2048).string();
- mHandler.sendMessage(message);
- } catch (IOException e) {
- message.obj = e.getLocalizedMessage();
- mHandler.sendMessage(message);
- e.printStackTrace();
- }
- }
- }).start();
- }
- });
- network_security_config.xml 中添加配置:
- <!--证书校验-->
- <domain-config>
- <domain includeSubdomains="true"><a href="http://www.test.com" target="_blank">www.test.com</a></domain>
- <trust-anchors>
- <certificates src="@raw/server_cert"
- tools:ignore="NetworkSecurityConfig" />
- </trust-anchors>
- </domain-config>
- server_cert就是server_cert.cer。到这里完成了客户端PIN服务端证书,然后还要在客户端这边写把客户端证书给服务端验证的代码逻辑,即ClientSSLSocketFactory的实现:
- public class ClientSSLSocketFactory {
- private static final String KEY_STORE_PASSWORD = "clientpassword"; // 证书密码
- private static InputStream client_input;
- public static SSLSocketFactory getSocketFactory(Context context) {
- try {
- //客户端证书
- client_input = context.getResources().getAssets().open("client.p12");
- SSLContext sslContext = SSLContext.getInstance("TLS");
- KeyStore keyStore = KeyStore.getInstance("PKCS12");
- keyStore.load(client_input, KEY_STORE_PASSWORD.toCharArray());
- KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());
- sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
- return sslContext.getSocketFactory();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- client_input.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return null;
- }
- }
复制代码
代码写完了,现在我们来缕一缕:
client app包含server-cert.cer 对服务端证书PIN,这个过程需要验证服务端证书的签发单位是否为合法CA Issuer,但是我们的
证书是自签名的,所以就算是不使用代理还是不能通过SSL PINNING,大概率是报错:
Caused by: java.security.cert.CertificateException:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
所以,一开始我们就需要用frida hook启动app,这样跳过app端的证书绑定,才可以继续后面的步骤。
接下来需要配置代理,给代理软件加客户端证书,这里我们使用BurpSuite,Fidller在这个场景不能用:
选择client.p12证书文件,如果你使用我生成的证书文件密码是clientpassword。
此时确认以下条件:
- [x] 服务端能通过PC浏览器访问
- [x] APP 中 client.p12 证书装载成功
- [x] APP 通过frida hook spawn模式启动
- [x] BurpSuite 加载 client.p12 证书成功
- [x] PC 代理软件未开启
- [x] PC hosts 中将 www.test.com 域名定向到正确IP
确定没问题以后,点击 HTTPS 双向验证 按钮访问。
最终效果:
APP 页面上显示:请求成功: 200
碎碎念:
可以把server-cert.cer 连带 server-key.key 导出一份可以装载的证书,这样就可以把这个证书加到系统证书列表中,应该可以通过SSL PINNING。
如果能把android 系统中hosts在/system/etc/hosts 是只读文件系统,我remount以后修改这个文件系统就会崩溃,随意没有尝试在android手机上直接将域名定向到server ip地址。
如果上述两点能正确实现,那就可以在局域网下,完成一个正经的HTTPS双向认证了。
0x7 WebView 忽略证书验证WebView
正常应该做成一个跳转页的,但是我为了图省事,就做了个小框在最下面,只是为了看是否访问成功。
- /*
- * https协议
- * WebView 不进行证书校验
- */
- button_webview_ssl_without_ca.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MyWebViewClient mWebViewClient = new MyWebViewClient();
- mWebViewClient.setCheckflag("trustAllCerts");
- mWebview.setWebViewClient(mWebViewClient);
- mWebview.loadUrl("https://www.baidu.com/?q=WebView_without_CAcheck");
- }
- });
复制代码
这样就做到了在遇到SSL错误时继续访问而中断访问,也不发出任何提醒。这样只需要配置好代理,甚至不需要安装代理证书就可以抓包了。
0x8 WebView 系统证书验证
很遗憾,WebView没有自定义SSL PINNING的实现方法,只能通过network_security_config.xml配置证书绑定。但这确实是一个很好的
现象,在我看来把安全相关的业务逻辑交给普通开发者简直就是白给,这么做反而是提升安全性的最佳实践。
- private class MyWebViewClient extends WebViewClient {
- private String checkflag="checkCerts"; // 是否忽略证书校验
- public void setCheckflag(String checkflag) {
- this.checkflag = checkflag;
- }
- @Override
- public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- if("trustAllCerts".equals(checkflag)){
- handler.proceed();
- }else {
- handler.cancel();
- Toast.makeText(MainActivity.this, "证书异常,停止访问", Toast.LENGTH_SHORT).show();
- }
- }
- }
复制代码
baidu.com未在network_security_config.xml中配置证书绑定,所以访问 https://www.baidu.com/ 时只使用系统证书进行校验。
所以只需要将代理软件的证书加入系统证书列表就可以抓包解密明文了。
0x9 WebView SSL PINNING
- /*
- * https协议 SSL PINNING WebView
- * 通过network_security_config.xml中定义的证书和密钥进行绑定
- */
- button_webview_ssl_pinning.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MyWebViewClient mWebViewClient = new MyWebViewClient();
- mWebViewClient.setCheckflag("checkCerts");
- mWebview.setWebViewClient(mWebViewClient);
- mWebview.loadUrl("https://www.sogou.com/web?query=WebView_SSLPinningXML"); // 证书文件校验
- // mWebview.loadUrl("https://www.zhihu.com/"); // 证书公钥校验
- }
- });
复制代码
sogou.com和zhihu.com都通过network_security_config.xml做了证书绑定,所以直接访问的过程中就会触发SSL PINNING的验证。
WebView SSL PINNING还不能通过0x-1附录的hook 代码unpinning,如果你有能unpinning的方法请务必告诉我。
0x-1 附录Frida Hook Code:
- usage: frida -U -f com.example.httpstest -l ./frida_multiple_unpinning.js --no-pause
- <font face="Tahoma">/* Android ssl certificate pinning bypass script for various methods</font>
- <font face="Tahoma"> by Maurizio Siddu modify by Ch3nYe</font>
- <font face="Tahoma"> Run with:</font>
- <font face="Tahoma"> frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause</font>
- <font face="Tahoma">*/</font>
- <font face="Tahoma">setTimeout(function() {</font>
- <font face="Tahoma"> Java.perform(function () {</font>
- <font face="Tahoma"> console.log('');</font>
- <font face="Tahoma"> console.log('======');</font>
- <font face="Tahoma"> console.log('[#] Android Bypass for various Certificate Pinning methods [#]');</font>
- <font face="Tahoma"> console.log('======');</font>
- <font face="Tahoma"> var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');</font>
- <font face="Tahoma"> var SSLContext = Java.use('javax.net.ssl.SSLContext');</font>
- <font face="Tahoma"> // TrustManager (Android < 7) //</font>
- <font face="Tahoma"> ////////////////////////////////</font>
- <font face="Tahoma"> var TrustManager = Java.registerClass({</font>
- <font face="Tahoma"> // Implement a custom TrustManager</font>
- <font face="Tahoma"> name: 'dev.asd.test.TrustManager',</font>
- <font face="Tahoma"> implements: [X509TrustManager],</font>
- <font face="Tahoma"> methods: {</font>
- <font face="Tahoma"> checkClientTrusted: function (chain, authType) {},</font>
- <font face="Tahoma"> checkServerTrusted: function (chain, authType) {},</font>
- <font face="Tahoma"> getAcceptedIssuers: function () {return []; }</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> });</font>
- <font face="Tahoma"> // Prepare the TrustManager array to pass to SSLContext.init()</font>
- <font face="Tahoma"> var TrustManagers = [TrustManager.$new()];</font>
- <font face="Tahoma"> // Get a handle on the init() on the SSLContext class</font>
- <font face="Tahoma"> var SSLContext_init = SSLContext.init.overload(</font>
- <font face="Tahoma"> '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Override the init method, specifying the custom TrustManager</font>
- <font face="Tahoma"> SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Trustmanager (Android < 7) request');</font>
- <font face="Tahoma"> SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] TrustManager (Android < 7) pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font><font face="Tahoma">
- </font>
- <font face="Tahoma"> // OkHTTPv3 (quadruple bypass) //</font>
- <font face="Tahoma"> /////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass OkHTTPv3 {1}</font>
- <font face="Tahoma"> var okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');</font>
- <font face="Tahoma"> okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OkHTTPv3 {1}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] OkHTTPv3 {1} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass OkHTTPv3 {2}</font>
- <font face="Tahoma"> // This method of CertificatePinner.check could be found in some old Android app</font>
- <font face="Tahoma"> var okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');</font>
- <font face="Tahoma"> okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OkHTTPv3 {2}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] OkHTTPv3 {2} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass OkHTTPv3 {3}</font>
- <font face="Tahoma"> var okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');</font>
- <font face="Tahoma"> okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OkHTTPv3 {3}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch(err) {</font>
- <font face="Tahoma"> console.log('[-] OkHTTPv3 {3} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass OkHTTPv3 {4}</font>
- <font face="Tahoma"> var okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');</font>
- <font face="Tahoma"> okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OkHTTPv3 {4}: ' + a);</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch(err) {</font>
- <font face="Tahoma"> console.log('[-] OkHTTPv3 {4} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font><font face="Tahoma">
- </font>
- <font face="Tahoma"> // Trustkit (triple bypass) //</font>
- <font face="Tahoma"> //////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Trustkit {1}</font>
- <font face="Tahoma"> var trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');</font>
- <font face="Tahoma"> trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Trustkit {1}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Trustkit {1} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Trustkit {2}</font>
- <font face="Tahoma"> var trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');</font>
- <font face="Tahoma"> trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Trustkit {2}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Trustkit {2} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Trustkit {3}</font>
- <font face="Tahoma"> var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');</font>
- <font face="Tahoma"> trustkit_PinningTrustManager.checkServerTrusted.implementation = function () {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Trustkit {3}');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Trustkit {3} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font><font face="Tahoma">
- </font>
- <font face="Tahoma"> // TrustManagerImpl (Android > 7) //</font>
- <font face="Tahoma"> ////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');</font>
- <font face="Tahoma"> TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing TrustManagerImpl (Android > 7): ' + host);</font>
- <font face="Tahoma"> return untrustedChain;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] TrustManagerImpl (Android > 7) pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Appcelerator Titanium //</font>
- <font face="Tahoma"> ///////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');</font>
- <font face="Tahoma"> appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Appcelerator PinningTrustManager');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Appcelerator PinningTrustManager pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // OpenSSLSocketImpl Conscrypt //</font>
- <font face="Tahoma"> /////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');</font>
- <font face="Tahoma"> OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] OpenSSLSocketImpl Conscrypt pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma">
- </font>
- <font face="Tahoma"> // OpenSSLEngineSocketImpl Conscrypt //</font>
- <font face="Tahoma"> ///////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');</font>
- <font face="Tahoma"> OpenSSLSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font><font face="Tahoma">
- </font>
- <font face="Tahoma"> // OpenSSLSocketImpl Apache Harmony //</font>
- <font face="Tahoma"> //////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');</font>
- <font face="Tahoma"> OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // PhoneGap sslCertificateChecker (<a href="https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin" target="_blank">https://github.com/EddyVerbrugge ... ker-PhoneGap-Plugin</a>) //</font>
- <font face="Tahoma"> //////////////////////////////////////////////////////////////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');</font>
- <font face="Tahoma"> phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] PhoneGap sslCertificateChecker pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) //</font>
- <font face="Tahoma"> ////////////////////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass IBM MobileFirst {1}</font>
- <font face="Tahoma"> var WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');</font>
- <font face="Tahoma"> WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {1} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass IBM MobileFirst {2}</font>
- <font face="Tahoma"> var WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');</font>
- <font face="Tahoma"> WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {2} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) //</font>
- <font face="Tahoma"> ///////////////////////////////////////////////////////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass IBM WorkLight {1}</font>
- <font face="Tahoma"> var worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');</font>
- <font face="Tahoma"> worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + a);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {1} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass IBM WorkLight {2}</font>
- <font face="Tahoma"> var worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');</font>
- <font face="Tahoma"> worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + a);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {2} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass IBM WorkLight {3}</font>
- <font face="Tahoma"> var worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');</font>
- <font face="Tahoma"> worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + a);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {3} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass IBM WorkLight {4}</font>
- <font face="Tahoma"> var worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');</font>
- <font face="Tahoma"> worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {4} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Conscrypt CertPinManager //</font>
- <font face="Tahoma"> //////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');</font>
- <font face="Tahoma"> conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Conscrypt CertPinManager: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Conscrypt CertPinManager pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma">
- </font>
- <font face="Tahoma"> // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager //</font>
- <font face="Tahoma"> ///////////////////////////////////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');</font>
- <font face="Tahoma"> cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] CWAC-Netsecurity CertPinManager pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Worklight Androidgap WLCertificatePinningPlugin //</font>
- <font face="Tahoma"> /////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');</font>
- <font face="Tahoma"> androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font><font face="Tahoma">
- </font>
- <font face="Tahoma"> // Netty FingerprintTrustManagerFactory //</font>
- <font face="Tahoma"> //////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');</font>
- <font face="Tahoma"> //NOTE: sometimes this below implementation could be useful</font>
- <font face="Tahoma"> //var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory');</font>
- <font face="Tahoma"> netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Netty FingerprintTrustManagerFactory');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Netty FingerprintTrustManagerFactory pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Squareup CertificatePinner [OkHTTP<v3] (double bypass) //</font>
- <font face="Tahoma"> ////////////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Squareup CertificatePinner {1}</font>
- <font face="Tahoma"> var Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');</font>
- <font face="Tahoma"> Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Squareup CertificatePinner {1}: ' + a);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Squareup CertificatePinner {1} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Squareup CertificatePinner {2}</font>
- <font face="Tahoma"> var Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');</font>
- <font face="Tahoma"> Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Squareup CertificatePinner {2}: ' + a);</font>
- <font face="Tahoma"> return;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Squareup CertificatePinner {2} pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) //</font>
- <font face="Tahoma"> /////////////////////////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Squareup OkHostnameVerifier {1}</font>
- <font face="Tahoma"> var Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');</font>
- <font face="Tahoma"> Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Squareup OkHostnameVerifier {1}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Squareup OkHostnameVerifier pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass Squareup OkHostnameVerifier {2}</font>
- <font face="Tahoma"> var Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');</font>
- <font face="Tahoma"> Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Squareup OkHostnameVerifier {2}: ' + a);</font>
- <font face="Tahoma"> return true;</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Squareup OkHostnameVerifier pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Android WebViewClient (double bypass) //</font>
- <font face="Tahoma"> ///////////////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass WebViewClient {1} (deprecated from Android 6)</font>
- <font face="Tahoma"> var AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');</font>
- <font face="Tahoma"> AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Android WebViewClient {1}');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Android WebViewClient {1} pinner not found');</font>
- <font face="Tahoma"> //console.log(err)</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> // Bypass WebViewClient {2}</font>
- <font face="Tahoma"> var AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');</font>
- <font face="Tahoma"> AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Android WebViewClient {2}');</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Android WebViewClient {2} pinner not found');</font>
- <font face="Tahoma"> //console.log(err)</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Apache Cordova WebViewClient //</font>
- <font face="Tahoma"> //////////////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');</font>
- <font face="Tahoma"> CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Apache Cordova WebViewClient');</font>
- <font face="Tahoma"> obj3.proceed();</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Apache Cordova WebViewClient pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> // Boye AbstractVerifier //</font>
- <font face="Tahoma"> ///////////////////////////</font>
- <font face="Tahoma"> try {</font>
- <font face="Tahoma"> var boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');</font>
- <font face="Tahoma"> boye_AbstractVerifier.verify.implementation = function (host, ssl) {</font>
- <font face="Tahoma"> console.log('[+] Bypassing Boye AbstractVerifier: ' + host);</font>
- <font face="Tahoma"> };</font>
- <font face="Tahoma"> } catch (err) {</font>
- <font face="Tahoma"> console.log('[-] Boye AbstractVerifier pinner not found');</font>
- <font face="Tahoma"> //console.log(err);</font>
- <font face="Tahoma"> }</font>
- <font face="Tahoma"> });</font>
- <font face="monospace">}, 0);</font>
复制代码
参考文章:
Android HTTPS防抓包策略与对抗方法总结
https://curz0n.github.io/2020/08/15/android-ssl-and-intercept/
Android : 关于HTTPS、TLS/SSL认证以及客户端证书导入方法
https://www.cnblogs.com/blogs-of-lxl/p/10136582.html
Android+Nginx一步步配置https单向/双向认证请求
https://blog.csdn.net/jjzhoujun2010/article/details/101442325
推荐阅读:
实战 | 记一次Fastadmin后台getshell的渗透记录
实战 | 记一次微信小程序渗透实战记录
干货|2021最新渗透测试面试题合集!!!
干货 | 80篇+网络安全面试经验帖
干货 | 学习网络安全,推荐6个我常用的安全知识在线手册
干货 | 个人报CNVD和CNNVD披露漏洞教程
|
|