【实战】某交友app的双向认证crack
0x0 前言
前几天刚总结了Android平台HTTPS的证书绑定和绕过方法([Android HTTPS认证的N种方式和对抗方法总结](Android HTTPS认证的N种方式和对抗方法总结 (ch3nye.top))),这就遇到了一个双向认证的APP,crack完了才发现2018年就有人搞过它了,不过当前版本和之前的代码逻辑有点变化,这里就简要记录一下思路。
环境:
RedmiK305G Android10 root with magisk
BurpSuite v2.0.11
frida 14.2.16
jadx v1.2.0
APP 版本v3.80.0
0x1 检查证书校验方式
手机添加代理证书到系统证书目录,抓包,抓到请求报文,响应总是400:
说明可能是做了双向认证。
查一下assets目录,发现client.p12证书,和我写的双向认证demo app中用的证书名字都一样,赶紧到反编译代码里搜一波:
到这里看一下代码逻辑就实锤了,就是双向认证。
要想抓包必须将客户端证书client.p12导入BurpSuite,所以要获取该客户端证书的密码。
0x2 获取客户端证书密码
从理论上来说,APP要使用客户端证书client.p12,就必须读取该证书文件,这个过程中需要输入证书密码,所以必然能在本地逆向出证书密码。
a.分析代码
去看看上述搜索到的代码逻辑,jadx对此处代码反编译不全,需要看smali,证书载入的逻辑在构造函数init中,代码片段:
const-string v5, "client.p12"
invoke-virtual {v0, v5}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
move-result-object v0
:try_end_50
.catch Ljava/lang/Exception; {:try_start_3c .. :try_end_50} :catch_ee
.line 10
:try_start_50
invoke-virtual {v1}, Ljava/lang/String;->toCharArray()[C
move-result-object v5
invoke-virtual {v4, v0, v5}, Ljava/security/KeyStore;->load(Ljava/io/InputStream;[C)V // 此处参数v5字符数组就是密钥
:try_end_57
.catch Ljava/lang/Exception; {:try_start_50 .. :try_end_57} :catch_57
.catchall {:try_start_50 .. :try_end_57} :catchall_5b
.line 11
:catch_57
:try_start_57
invoke-virtual {v0}, Ljava/io/InputStream;->close()V
:try_end_5a
.catch Ljava/lang/Exception; {:try_start_57 .. :try_end_5a} :catch_60
分析一下上述代码,密钥v5是从v1字符串转CharArray来的,向上翻找v1:
invoke-virtual {v1, v2}, Lcn/xxxxapp/android/net/XxxxNetworkSDK;->b(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
发现v1是从cn.xxxxapp.android.net.xxxxNetworkSDK中的方法b(String str)得到的。
再去翻看cn.xxxxapp.android.net.xxxxNetworkSDK.b(String str):
public String b(String str) {
return XxxxPowerful.a(str);
}
再去翻看cn.xxxxapp.android.xxxxpower.xxxxPowerful.a(String str):
public class xxxxPowerful {
static {
System.loadLibrary("xxxxpower");
}
public static String a(String str) {
return c(str);
}
public static String b() {
return i();
}
public static native String c(String str);
...
}
现在了然了,从libxxxxpower.so中获取client.p12证书密码。
b.hook获取
frida -U -f cn.xxxxapp.android -l .\hook_Key.js --no-pause
hook_Key.js
setTimeout(function(){
Java.perform(function (){
var KeyStore = Java.use("java.security.KeyStore");
KeyStore.load.overload('java.io.InputStream', '[C').implementation = function(a,pass) {
console.log("\n============keystore.load()============");
console.log(pass);
return this.load(a,pass);
};
var XxxxNetworkSDK = Java.use("cn.xxxxapp.android.net.XxxxNetworkSDK");
XxxxNetworkSDK.b.overload('java.lang.String').implementation = function(str) {
var res = this.b(str);
console.log("\n============XxxxNetworkSDK.b()============");
console.log(str);
console.log(res);
return str;
}
});
},0);
我一开始想直接hook java.security.KeyStore.load方法获取key但是结果总为空,后来通过hook XxxxNetworkSDK中b方法成功获取密钥:
frida logcat:
[Redmi K30 5G::cn.xxxxapp.android]->
============keystore.load()============
null
============keystore.load()============
null
============XxxxNetworkSDK.b()============
10000003
}%3R-\0SsjpP1w%X
============keystore.load()============
[object Object]
c.导入证书
d.成功抓包
而且奇怪的是这个app似乎对请求没有限速,5线程疯狂访问某个用户主页1000次,居然没ban我😁🙏。