记录一次绕过 Android 服务端的证书校验的详细过程
前言
本来想挑一个 APP 抓包练练手,因为基础不是很好,想提升实战水平,结果一不小心挑了个不寻常的(对于我而言,大佬勿喷),但因为自己比较固执,不死心,花了几天时间总算搞定了,但还是有些问题,希望有懂行大佬指点一下。
该 APP 使用了 org.conscrypt
库,据了解,这一个封装基于 OpenSSL
的库,在 Github
上也有 1.3k Star
但是网上并没有相关的文章,很少,最终还是通过翻阅源码找到一个关键的 So
层函数作为 Hook
点将私钥导出。
本文章 Hook
脚本均参考了网上的文章以及借助 ChatGPT
所编写,并且经过许多次调试,因为自己不是特别熟悉 frida JS API
,还需要多练,多实战,因此写了这篇文章记录自己的过程,以分享自己的思路,给有需要的人一些参考,避免踩坑。
详细过程
设置代理
目前手机已 root
,已安装 Burp
证书至系统,当然用 JustTrustMe
也可以干掉客户端的证书校验,比较简单也没检测 VPN
,随后开启热点,使用安卓端 proxifier
开启 VPN 让指定 APP 走 Burp
:
设置 Burp
代理:
指定 APP
:
发现服务端的证书校验
进入 APP
,发现一切正常:
在输入框中随便输入,点击加入,服务端返回 400,并且是 No required SLL certifucate was sent
:
解包寻找 APK 中的证书
使用 Jadx-gui
对 APK
进行反编译,发现资源部分有几个关键证书:
但这些 grp_sp.bks
、hmsincas.bks
、hmsrootcas.bks
都是 SDK
相关的证书,而 trust.crt
有点可疑,使用 XCA
对 trust.crt
进行查看:
trust.crt
包含多个公钥证书,还有一些 CA 证书,应该是证书信任链,不是客户端证书,因此解包寻找证书无果。
尝试大佬的 frida 自吐脚本和 r0capture
自吐脚本
于是我参考了这位大佬的文章:https://xz.aliyun.com/t/12993
,使用其中的 frida 自吐脚本尝试 Hook
看有没有发现,脚本链接:https://github.com/WithSecureLabs/android-keystore-audit/blob/master/frida-scripts/tracer-keystore.js
这里我用的是 JsHook
,使用 frida
还是非常方便的:
开启 frida-server
服务及端口转发,复制自吐脚本,并以 spawn
模式启动 App
:
发现啥也没有:
尝试手动抛出异常打印堆栈:
也没发现,不过有一行看起来跟证书相关的类,这里先记一下:
r0capture 通杀脚本
一句话启动:
还是无果,内容还是加密的,证书也未导出,看调用堆栈可知,使用了 org.conscrypt
库,搜了一下发现是 Google
开发的一个基于 OpenSSL
封装的 SSL/TLS
加密库,有点用,先记着。
反编译 Hook 证书
用了大佬们的脚本都无果,其实到这有点想放弃了,不过还没仔细看代码,根据上文的堆栈信息查找与证书有关的类名:
发现有个函数返回了证书,尝试 hook
它试试,jadx-gui
很方便,可以右键直接复制 Hook
代码:
结果打印了一个证书,从 X509 Extend Usage
中的 Web Client Authentication
看以及关键字眼 android
,可以判断这个就是客户端证书:
·
将其 dump 出来:
有个问题,这证书从哪来的? 只能先抛开不谈,现在证书有了,私钥呢?常规 APP 一般不都打包成 bks
、p12
、jks
这类的文件然后设置个密码,但这 APP
不走寻找路,于是我尝试了各种 Hook
,如下图,涉及私钥和证书的 Java
层方法都尝试过:
以及 javax.net.ssl.*
org.conscrypt
库的一些 Java
层的关键方法,要么 Hook
不到(这里可能是 Hook 时机不对或者没调用,很多都没 Hook 到),要么为 null
,心态崩了,但我还是不想放弃,于是去找 native
层。
寻找 So 层 Hook 点
下载 org.conscrypt
的源码:https://github.com/google/conscrypt,使用 VScode
打开寻找关键词,尝试 Hook
,最终找到了一处:
其中 keyJavaBytes
根据语义以及函数名可以判断这个跟私钥有关,但是我发现这个函数在 Java
层有被调用,尝试 Hook
他们却没反应:
先暂时不管,直接尝试 Hook
这个函数,打印 jbyteArray
的内存数据,找到 APP
加载的 So
文件名为:libconscrypt_jni.so
,frida
脚本如下:
这里我尝试用很多中办法都没法得到 jbyteArray
的长度,调用 JNI
的 GetArrayLength
方法会导致闪退,具体原因未知,只能预先 dump 大小为 0x1000,有需要也可以更大,将其 dump 至 /sdcard/Download
下,替换上方的 hook
函数:
私钥如下:
导入 XCA
,查看之前的证书,可以发现私钥对应上了:
使用 XCA
直接导出为 p12
:
导入至 burp
:
发包,成功:
不知道这种方法能不能对使用了 org.conscrypt
库的 App
通杀,后续研究一下。
参考链接
https://xz.aliyun.com/t/12993
https://bbs.kanxue.com/thread-280089.htm
https://bbs.kanxue.com/thread-281584.htm