标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2024-3171]   作者: 浩丶轩 发表于: [2022-09-03]

本文共 [479] 位读者顶过

0x00 前言

做APP测试过程中,使用burp无法抓到数据包或提示网络错误可能是因为APP启用了SSL Pinning,刚好最近接触到apk就是这种情况,于是便有了本文。

0x01 SSL Pinning原理

SSL Pinning即证书锁定,将服务器提供的SSL/TLS证书内置到移动端开发的APP客户端中,当客户端发起请求时,通过比对内置的证书和服务器端证书的内容,以确定这个连接的合法性。

0x02 环境

Win10[出自:jiwo.org]
安卓模拟器(夜神模拟器)
Burp
Frida(Python 3.7)
adb工具
apk(途牛apk)

0x03 利用Frida绕过SSL Pinning

绕过原理:
客户端请求时会将内置的证书与服务端的证书做一次性校验,通过hook的方式将此次校验的结果返回true或者干脆不让其做校验即可以绕过。当安卓APP初始化SSLContext时,我们使用frida劫持SSLContext.init方法,使用我们自己创建的TrustManager , 把它作为实参传入SSLContext.init方法的第二个参数( SSLContext.init(KeyManager,TrustManager,SecuRandom) 。这样就能使得APP信任我们的CA,以上操作都是通过一个js脚本注入实现的。


1. 利用adb连接安卓模拟器

这里我们使用的是夜神模拟器,它默认使用Android 5版本的,就是因为这个点,这里踩坑踩了很久,夜神的Android版本低会导致下面在启用Frida-server时报错,因此这里需要使用Android 7以上。
Android低版本报错如下


夜神模拟器创建高版本Android 7并启动


利用adb连接模拟器,夜神模拟器adb连接默认是连接本机的62001端口,可是这里因为是新建的可能端口会有所变化,不过也还是在62001附近,可以使用

netstat -ano

查看一下本机端口,我这里是62041端口,如下所示代表连接成功

adb connect 127.0.0.1:62025 #连接设备

adb devices #查看设备   

 设置burp证书

先在burp里设置本机代理


访问代理地址并下载burp证书


将下载的burp证书导入到模拟器中/data/local/tmp目录下,并重命名为cert-der.crt(此名称在接下来的fridascript.js脚本中使用,如果该名字命名为其他则脚本中相对应的地方也需要进行替换)


adb push cacert.der /data/local/tmp/cert-der.crt

3. 模拟器设置代理

在安卓模拟器设置->wlan选择对应网络设置代理


 Frida设置

Python frida包安装

Win10需安装Python3.7环境,终端安装Frida和frida-tools

pip3 install Frida

pip3 install frida-tools

frida-server设置

查看安卓设备的arch版本并下载对应的frida-server包

adb shell getprop ro.product.cpu.abi

这里是x86的因此下载frida-server-12.9.7-android-x86.xz


下载完成以后解压重命名文件为frida-server并将其上传到安卓模拟器的/data/local/tmp/目录下


adb push frida-server /data/local/tmp


设置frida-server权限


adb shell chmod 777 /data/local/tmp/frida-server


运行frida-server


# 进入模拟器:/data/local/tmp/目录运行

cd /data/local/tmp/

./frida-server

# 直接运行

adb shell /data/local/tmp/frida-server &

如果运行正常则不会有任何输出


在模拟器里运行途牛旅游app,并使用frida-ps -U命令列出设备上运行的服务,找到途牛应用程序的包名


下载注入脚本,保存为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);


脚本里的30行其中对应的就是burp证书的信息
将fridascript.js注入到目标应用程序中


frida -U -f com.tuniu.app.ui -l C:\Users\xxx\Desktop\fridascript.js --no-pause


-f选项表示强制启动一个应用程序,-l选项表示加载指定脚本,–no-pause选项表示不中断应用程序的启动,如下所示代表运行成功


一旦frida服务运行成功,目标程序的流量都将被burp拦截



评论

暂无
发表评论
 返回顶部 
热度(479)
 关注微信