大家好!本文我将详细为大家解释如何使用frida框架,绕过Android应用程序的SSL pinning。
以下是本文将涵盖的内容:
Frida和SSL pinning简介
要求
设置和安装
Frida服务器设置
设置BurpSuite
推送代理的CA证书:
脚本注入绕过SSL pinning
步骤概述
疑难解答
Frida是什么?
Frida官网上是这么说的:
它是针对本地APP的类似油猴插件的东西,用更专业的术语来说,它是一个动态代码检测toolkit。它可以让你注入JavaScript代码片段或者你自己的库到Windows中的APP中,也可以注入到macOS,GNU/Linux,iOS,Android和QNX的APP中。Frida还提供了一些构建在Frida之上的简单工具。这些工具你可以直接使用,也可以根据自己的需求来调整,或者是作为如何使用API的示例。
简而言之,Frida就是一个让你可以注入脚本到本地APP(此案例我们将注入到安卓APP中)中的工具,从而修改APP的行为(在这里例子中,我们可以绕过ssl pinning并执行中间人攻击,即使APP使用的是HTTPS/SSL连接),并且实时的进行动态测试。
如今,大多数应用程序已在其移动应用中实现了SSL pinning。这是为什么呢?让我们思考一个问题,假设我们要在设备和服务器之间安全地交换一些数据。SSL传输层加密将使数据传输安全可靠?在数据传输之前,如果服务器的SSL证书与请求的主机名和受信任的根证书匹配,则客户端会检查该证书。
它不能确保提供的证书是服务器为请求的主机名提供的实际证书。因此,依赖设备的可信存储证书不会使数据传输“安全”。
证书锁定(Certificate pinning)是远程服务器在应用程序本身中信任的硬编码证书,因此它将忽略设备证书存储,并将信任自己的硬编码证书,进一步的应用程序将使用该硬编码证书“安全地”与远程服务器通信。
当我们对大多数移动应用程序的HTTP请求进行动态分析时,SSL pinning绕过是需要完成的主要步骤,因为现如今组织对数据隐私和通过网络的数据安全传输变得更加重视,像一些来自中间人攻击的威胁也成为了他们重点关注的对象。
Frida是一个框架,它将脚本注入到原生应用中,以在运行时操作应用程序的逻辑,这是一种更为动态的方法,可用于移动应用的渗透测试任务。
在开始使用之前我们需要进行一些设置,第一次设置可能需要花点时间,但在此之后就会变得很轻松。如果你在任何一个步骤都出现了问题,都可以参考文章末尾的“疑难解答”部分。建议将所有下载的内容保存在一个文件夹中。
我们需要一个已root的设备或模拟器,因为我们需要将脚本注入到设备的根目录。我使用的是genymotion。Genymotion非常易于设置和使用,你可以在此处下载它。
一旦完成了genymotion的安装,我们需要安装一个Android设备(Android 7+)。我将使用具有以下配置的“Google pixel XL”设备。
II. Python frida 包安装:
从这里安装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的平台工具。
从此处下载我们将推送到设备用于注入目标应用的注入脚本。
或者可以将此代码另存为fridascript.js,保存在与adb相同的文件夹中。
/*
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以在设备上运行命令。但首先转到settings >> Developer options,并在设备中启用调试模式,以便adb可以与设备通信。
转到已提取平台工具的文件夹,然后运行以下命令将设备连接到adb
//adb connect <ip of device:port>
adb connect 192.168.1.190:5555
如果设备中出现弹出窗口,请单击“允许Allow”。
检查设备是否已连接到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 &
现在,我们需要找出目标应用程序的ID。我们将列出设备上所有正在运行的服务,包括你的应用程序进程。
打开一个新的终端,并键入以下命令。
frida-ps -U
IV. 找到你应用程序的包名称。
最后,我们将使用以下命令将fridascript.js hook到原生应用程序中:
//frida -U -f <your_application_package_name> -l <path_to_fridascript.js_on_your_computer> --no-paus
frida -U -f com.twitter.android -l D:\frida\fridascript.js --no-paus
如果一切顺利,那么目标应用程序的所有流量都将被BurpSuite拦截。
1. 在genymotion上下载并安装设备
2. 安装frida和objection工具
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
3. 下载adb平台工具
4. 下载frida注入脚本
5. 将设备连接到adb
//adb connect <ip of device:port>
6. 下载frida服务器以获取支持Android设备的arch版本
7. 找出设备的arch版本
adb shell getprop ro.product.cpu.abi
8. 在设备中安装目标应用程序。
9. 将frida-server推送到设备:
//adb push <path of frida-server folder><space></data/local/tmp>
10. 授予frida-server权限:
adb shell chmod 777 /data/local/tmp/frida-server
11. 设置burpsuite
12. 推送代理的CA证书
// adb push <path to cacert.der> /data/local/tmp/cert-der.crt
13. 将fridascript.js推送到设备:
//adb push <path to fridascript.js folder> /data/local/tmp
14. 检查并运行设备中的frida服务器
adb shell /data/local/tmp/frida-server &
15. 列出设备上所有正在运行的进程:
frida-ps -U
16. 找到你应用程序的包名称
17. 将fridascript.js hook到目标应用程序中
//frida -U -f <your_application_package_name> -l <path_to_fridascript.js_on_your_computer> --no-paus
18. 在BurpSuite中拦截流量。
1. ADB 守护程序无法连接
如果发生如下错误:
adb devices
adb server is out of date. killing...
cannot bind 'tcp:5037'
ADB server didn't ACK
*failed to start daemon*
error:
i. 打开 environment System properties>>Advanced>>Environment Variables
ii. 单击路径并删除C:/Android条目或指向adb工具的路径
iii. 将所有平台工具复制到genymotion>>tools文件夹中
iv. 创建新路径并添加genymotion>>tools文件夹的路径。
2. frida/ pip 不被识别为内部或外部命令
i. 打开 environment System properties>>Advanced>>Environment Variables
ii. 创建新路径并添加Python>>script文件夹的路径
3. 将应用程序安装到设备时出现 Arm translation error。
i. 从此处下载arm translation文件
ii. 将文件拖放到设备模拟器中,或是在使用物理设备时从恢复中刷新此文件
iii. 重启设备后,你将能够拖放安装目标应用程序
4.Failed to spawn:spawn Android apps 时不支持 argv 选项
检查计算机上的fridascript.js路径。路径可能不正确。你必须给出fridascript.js文件的绝对路径。
5. frida 服务器已启动但无法列出服务
断开并重新连接设备中的wifi。
*参考来源:medium,FB小编secist编译,转载请注明来自FreeBuf.COM