#准备工作

· 已root的安卓机(小于Android 10)
· adb —— 用于调试Android设备
· Frida —— 用于对apk内的部分验证代码进行Hook
· Burpsuite —— 用于抓包
· OpenSSL —— 用于生成证书及转换证书格式

#SSL单向认证绕过

*配置burp(在个人电脑上操作)

upload successful

*手机上配置wifi(在手机上操作)
手机上连接与电脑同一网段的wifi

upload successful

upload successful

*导出Burp证书
upload successful

Android 7.0+不再默认信任个人安装的证书。因此需要root手机后,将我们的根证书安装到系统内:假装是个系统自带的证书。

*电脑端操作为手机安装证书

1
2
3
4
5
6
openssl x509 -inform DER -in cacert.der -out cacert.pem   #导出的der证书转换为pem格式
openssl x509 -inform PEM -subject_hash_old -in cacert.pem|head -1 #打印hash,得到9a5ba575
cp burp.pem 9a5ba575.0
adb push 9a5ba575.0 /system/etc/security/cacerts/#将证书传到系统根证书目录
adb shell chmod 644 /system/etc/security/cacerts/9a5ba575.0
abd reboot

#使用自签名证书

某些情况下,Burpsuite导出的证书无法满足我们需求;或是出现无法抓包的玄学问题:考虑生成一个自签名证书导入Burpsuite。
*生成自签名根证书

1
2
3
4
5
mkdir certificates && cd certificates 
cp "C:\Program Files\OpenSSL-Win64\bin\cnf\openssl.cnf"
openssl req -x509 -days 730 -nodes -newkey rsa:2048 -outform der -keyout server.key -out ca.der -extensions v3_ca -config openssl.cnf #创建一个新的根证书
openssl rsa -in server.key -inform pem -out server.key.der -outform der #转为der格式
openssl pkcs8 -topk8 -in server.key.der -inform der -out server.key.pkcs8.der -outform der –nocrypt #将key转换为pkcs8格式

*把自签名证书导入burp

upload successful

upload successful

upload successful

在Burp内导入自签名证书后,挂上Burp的代理访问,Burp会自动使用我们刚才生成的根证书签发当前域名的证书。证书的签发者信息就是我们刚才在openssl req内所填写的。接着,我们需要让手机信任我们刚才签发的CA。

upload successful

*直接在手机上安装我们刚才生成的CA证书
*再使用adb将其转移到系统证书存储区

1
2
3
4
5
6
7
8
adb shell 
su
cd /data/misc/user/0/cacerts-added/   #进入证书安装路径
ls   #显示安装的证书
mount -o rw,remount /system   #重新挂载 /
chmod 777 /system    #给予权限
mv d58e1f78.0  /system/etc/security/cacerts/    #将证书复制到根目录
reboot

#SSL双向认证绕过

某些敏感接口的服务端会验证客户端是否合法。
需要在Burpsuite内导入客户端证书。
HTTPS双向认证流程:

C->S:发送相关连接信息
S->C:返回包含服务器公钥的证书
C->S:使用服务器公钥加密自己支持的加密方案,并将包含客户端公钥的证书一并发给服务器
S->C:使用客户端公钥加密自己支持的加密方案,并用双方的加密方案生成随机数R,加密后返回客户端
C->S:双方开始使用这个R来通信

*导出apk

1
2
3
4
5
6
7
adb shell
su
pm list package|grep kfc   #查看包名 返回com.yek.android.kfc.activitys
pm path com.yek.android.kfc.activitys   #查看路径名 返回/data/app/com.yek.android.kfc.activitys-JBrepCya_JjEEtgE2-JUxA==/base.apk
exit
exit
adb pull data/app/com.yek.android.kfc.activitys-JBrepCya_JjEEtgE2-JUxA==/base.apk  C:\Users\xxx\Desktop   #导出apk

*修改.apk后缀为.zip并解压
*从assets等资源目录找到后缀名为p12/pfx/pem等的证书文件
*如果是p12类型,可将其直接导入Burpsuite。(可能需要密码 通用123456)

upload successful

upload successful

*获取安装证书的密码
将apk拖入 jeb 搜索证书文件(本例为client.p12),或是PKCS12等关键字符。

upload successful

· 某些客户端也会验证服务器证书是否是指定的证书。
· 除逆向直接删除这部分逻辑外,更简便的方法是,使用Frida对客户端进行Hook,让客户端的所有验证都能通过。
· 使用Frida的优势在于不用逆向,基本上针对大部分此类App都是可用的。

*安装Frida

1
2
3
4
5
6
7
8
9
电脑端安装
*python版本3.7*
pip3 install frida
pip3 install frida-tools
手机端安装
adb shell
su
getprop ro.product.cpu.abi   #查看Android手机设备设置 返回arm64-v8a
frida -version   #在电脑端查看安装的frida版本 返回14.2.18

*下载对应frida-server并安装,注意版本号对应:
https://github.com/frida/frida/releases

upload successful

*下载后进行解压,解压后的文件重命名为frida-server并复制到手机

1
2
3
4
5
6
7
8
adb push firda-server /data/local/tmp #将frida-server放到手机的这个目录下
adb forward tcp:27042 tcp:27042  #转发端口
adb forward tcp:27043 tcp:27043
adb shell
su
cd /data/local/tmp
chmod 755 frida-server  #赋予可执行权限
./frida-server  #后台运行frida-server

*另起一个cmd窗口

1
frida-ps -U

upload successful

*使用Frida加载脚本,绕过服务端证书校验
*先保存为.txt格式 另存为.js 并选择编码UTF-8

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function AndroidMain(){
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var TrustManager;
try {

TrustManager = Java.registerClass({
name: 'org.wooyun.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function(chain, authType) {},
checkServerTrusted: function(chain, authType) {},
getAcceptedIssuers: function() {
return [];
}
}
});

var TrustManagers = [TrustManager.$new()];

var SSLContext = Java.use('javax.net.ssl.SSLContext');

SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom').implementation = function() {
console.log("执行替换")
this.init.overload('[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom').call(this, null, TrustManagers, null);

}

} catch (e) {
console.log("error: " + e.message);
}
}
setImmediate(function() {
send("script running..." + "-cusoto0oom0sc0ri0pt-");
//打印堆栈
if (ObjC.available) {
//
}else if(Java.available) {
Java.perform(function() {
AndroidMain();
});
}

});

upload successful

upload successful