原文链接:https://medium.com/@ved_wayal/hail-frida-the-universal-ssl-pinning-bypass-for-android-e9e1d733d29
大家好,在这篇文章中,我将解释如何使用frida框架绕过任何Android应用程序的SSL pinning,我会尝试更详细地解释其中的细节。
本文将介绍:
介绍Frida和SSL pinning
要求
设置和安装
Frida服务器设置
设置BurpSuite
配置代理的CA证书
脚本注入绕过SSL pinning
总结
故障排除
Frida框架是SSL pinning绕过的最后一站。
根据frida 网站的描述:
对于应用程序来说,这是Greasemonkey,或者,在更多技术术语中,它是一个动态代码检测工具包。它允许你将JavaScript或你自己的库中的代码注入Windows,macOS,GNU/Linux,iOS,Android和QNX上的应用程序。Frida还为你提供了一些基于Frida API构建的简单工具。这些可以按原样使用,根据你的需要进行调整,或作为如何使用API的示例。
如今,大多数应用程序在其移动应用程序中实现SSL pinning技术。这是为什么?因为我们想要在我们的设备和服务器之间安全地交换一些数据,虽然,SSL传输层加密将使数据传输安全可靠?但是,有一个问题,在数据传输之前,如果服务器的SSL证书与请求的主机名和受信任的根证书匹配,则客户端会检查该证书。
它不能确保提供的证书是服务器为请求的主机名提供的实际证书。因此,依赖设备的可信存储证书不会使数据传输“安全”。
证书锁定是应用程序本身内远程服务器信任的硬编码证书,因此它将忽略设备证书存储,并将信任他自己的硬编码证书,进一步的应用程序将用于“安全地”与远程服务器通信。
当我们甚至开始对大多数移动应用程序的HTTP请求进行动态分析时,绕过SSL pinning是需要完成的主要步骤,因为我们更关注数据隐私以及通过网络从中间人(MiTM)攻击等线程安全传输数据。
Frida是一个框架,它为本机应用程序注入脚本,以便在运行时操作应用程序的逻辑,这对于测试移动应用程序来说是更具动态性的。
这种设置第一次需要一些时间,因为需求的信息很多。一旦我们完成所有设置,从下次开始它将是一件很简单的事情。如果你安装过程中出现问题,博客末尾会出现“ 疑难解答 ”部分。
我们需要一个有rooted device或者是rooted emulator,因为我们需要将脚本注入设备的根目录。由于Genymotion易于设置和使用,所以,现在很多人都使用Genymotion,可以从下面下载。
https://www.genymotion.com/fun-zone/
一旦我们完成安装genymotion,我们需要安装一个Android设备。Android 7+版本将不错。我将使用具有以下配置的“ Google pixel XL”设备。
从这里安装Python for Windows。
我们需要为frida服务器安装一些python包。为此在终端中输入以下命令:
python -m pip install Frida
python -m pip install objection
python -m pip install frida-tools
or
pip install Frida
pip install objection
pip install frida-tools
从以下链接下载用于Windows的平台工具:
我们需要从下面下载注入脚本,我们将把这个脚本注入目标应用程序的设备
或者你可以将此代码保存为与adb相同的文件夹中的fridascript.js。
/*
Android SSL Re-pinning frida script v0.2 030417-pier
$ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
$ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause
https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 !
*/
setTimeout(function(){
Java.perform(function (){
console.log("");
console.log("[.] Cert Pinning Bypass/Re-Pinning");
var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
var FileInputStream = Java.use("java.io.FileInputStream");
var BufferedInputStream = Java.use("java.io.BufferedInputStream");
var X509Certificate = Java.use("java.security.cert.X509Certificate");
var KeyStore = Java.use("java.security.KeyStore");
var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
var SSLContext = Java.use("javax.net.ssl.SSLContext");
// Load CAs from an InputStream
console.log("[+] Loading our CA...")
var cf = CertificateFactory.getInstance("X.509");
try {
var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
}
catch(err) {
console.log("[o] " + err);
}
var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
var ca = cf.generateCertificate(bufferedInputStream);
bufferedInputStream.close();
var certInfo = Java.cast(ca, X509Certificate);
console.log("[o] Our CA Info: " + certInfo.getSubjectDN());
// Create a KeyStore containing our trusted CAs
console.log("[+] Creating a KeyStore for our CA...");
var keyStoreType = KeyStore.getDefaultType();
var keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
console.log("[+] Our TrustManager is ready...");
console.log("[+] Hijacking SSLContext methods now...")
console.log("[-] Waiting for the app to invoke SSLContext.init()...")
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
console.log("[+] SSLContext initialized with our custom TrustManager!");
}
});
},0);
我们需要将设备连接到adb上,可以在设备上运行命令。但首先转到设置--->开发人员选项并在设备中启用调试模式,以便adb可以与设备通信。
转到已提取平台工具的文件夹,然后运行以下命令将设备连接到adb
//adb connect <ip of device:port>
adb connect 192.168.1.190:5555
如果设备中出现弹出窗口,请单击“允许”。
要检查设备是否已连接到adb:adb devices
你可以看到设备的IP以及设备名称
我们需要根据我们设备的arch版本为我们的Android设备下载frida服务器软件包。
要查找设备的arch版本,请运行以下命令:adb shell getprop ro.product.cpu.abi
如果设备配置与上面提到的相同,请缩短下载时间:
frida-server-12.4.7-android-x86.xz
frida-server-12.4.7-android-x86_64.xz
安装必须在我们的设备中绕过SSL pinning的应用程序。打开应用程序并使其在后台运行。
我们需要在注入脚本之前将frida服务器运行到设备中。请按照以下步骤操作:
现在我们需要将我们的frida-server文件推送到设备中。复制adb文件夹中的“frida-server-12.4.7-android-x86.xz”
文件并运行以下命令
//adb push <path_of_frida_server_folder><space></data/local/tmp>
adb push C:\ADB\frida-server /data/local/tmp
adb shell chmod 777 /data/local/tmp/frida-server
按照这个很棒的指南在Android设备的burp中设置代理:
为了能够拦截流量,frida需要访问我们的Burpsuite CA证书。我们将在BurpSuite Setup中配置与步骤5相同证书。
将证书推送到设备并进入与frida-server相同的位置,将其命名为cert-der.crt(因为此名称和路径已在fridascript.js中提及以避免任何问题)
// adb push <path to cacert.der> /data/local/tmp/cert-der.crt
adb push cacert.der /data/local/tmp/cert-der.crt
我们将'fridascript.js'注入目标应用程序.
将fridascript.js复制到adb文件夹并运行以下命令将fridascript.js推送到设备中。
//adb push <path_to_fridascript.js_folder> /data/local/tmp
adb push C:\ADB\fridascript.js /data/local/tmp
adb shell /data/local/tmp/frida-server &
这将把frida-server运行到设备中。也许你不会在终端获得这个命令的任何输出。
现在,我们需要找出目标应用程序的ID。我们将列出设备上所有正在运行的服务,包括您的申请流程
打开新终端并输入以下命令:frida-ps -U
最后,我们将使用以下命令将fridascript.js注入到本机应用程序中:
//frida -U -f <your_application_package_name> <path_to_fridascript.js_on_your_computer> --no-paus
frida -U -f com.twitter.com D:\ADB\fridascript.js --no-paus
一旦所有事情顺利进行,目标应用程序的所有流量都将被拦截到BurpSuite中。只要我们拦截进入BurpSuite的流量,我们就需要保持frida服务器的运行。
安装frida和主要工具
python -m pip install Frida
python -m pip install frida-tools
python -m pip install objection
or
pip install Frida
pip install frida-tools
pip install objection
下载adb平台工具
将设备连接到adb
//adb connect <ip of device:port>
下载frida服务器以获取支持的Android设备的arch版本
找出设备的arch版本
adb shell getprop ro.product.cpu.abi
将frida-server推入设备:
//adb push <path folder="" frida-server="" of=""><space></data/local/tmp></space></path>
授予frida-server权限:
adb shell chmod 777 /data/local/tmp/frida-server
设置burpsuite
推送代理的CA证书
// adb push <path to cacert.der> /data/local/tmp/cert-der.crt
将fridascript.js推入设备:
//adb push <path to fridascript.js folder> /data/local/tmp
检查并运行设备中的frida服务器
adb shell /data/local/tmp/frida-server &
列出设备上所有正在运行的进程:
frida-ps -U
找到应用程序的包名
将fridascript.js注入到目标应用程序中
//frida -U -f <your_application_package_name> <path_to_fridascript.js_on_your_computer> — no-paus</your_application_package_name>
拦截BurpSuite的流量
如果你收到这样的错误:
adb devices
adb server is out of date. killing...
cannot bind 'tcp:5037'
ADB server didn't ACK
*failed to start daemon*
error:
i. 打开环境系统属性--->高级--->环境变量
ii.单击路径并删除 C:/Android或adb工具指向的路径
iii.将所有平台工具复制到genymotion--->tools文件夹中
。创建新路径并添加genymotion--->tools文件夹的路径.
i.打开环境系统属性--->高级--->环境变量
ii.创建新路径并添加Python--->script文件夹的路径
i.下载转换文件
ii.将文件拖放到设备模拟器中或从恢复中刷新此文件。重启设备,你就可以拖放安装目标应用程序
出现Android应用程序时不支持'argv'选项
检查计算机上的fridascript.js路径。路径可能不正确。
断开并重新连接设备中的wifi。