Zry.IO

返回

背景

在使用 fiddler 对某 Android 应用进行抓包时发现,即使将 fiddler 生成的证书添加至设备信任列表,仍然会在试图登录时产生如下图错误,而 fiddler 中也抓不到请求

1.png

逆向分析

反编译应用后分析其 java 源码,发现其 HTTPS 请求类中存在 Certificate Pinning (证书锁定) 措施,主要实现位于:

  • com.amazon.identity.auth.device.framework.security.CertificatePinning
  • com.amazon.identity.auth.device.framework.AuthenticationWebViewClient

其中 CertificatePinning 通过 javax.net.ssl.TrustManagerFactory 先从指定证书生成 TrustManager,再进行 javax.net.ssl.SSLContext.init 方法,实现证书锁定

AuthenticationWebViewClient 继承自 android.webkit.WebViewClient,通过 onReceivedSslError 方法实现证书锁定

编写 frida 脚本

首先,用 fiddler 证书来生成 TrustManagers,对 TrustManagerFactory.getTrustManagers 进行 hook,使其永远返回指定的 TrustManagers

TrustManagerFactory.getTrustManagers.implementation = function () {
    console.log("App invoked TrustManagerFactory.getTrustManagers");
    return TrustManagers;
}
javascript

SSLContext.init 进行 hook

var SSLContext_init = SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom");
SSLContext_init.implementation = function (a, b, c) {
    console.log("App invoked javax.net.ssl.SSLContext.init");
    SSLContext_init.call(this, null, TrustManagers, null);
}
javascript

对于 WebView,对 WebViewClient.onReceivedSslError 进行 hook,以忽略证书错误

WebViewClient.onReceivedSslError.implementation = function (webView, sslErrorHandler, sslError) {
    sslErrorHandler.proceed();
    // proceed 方法使 WebView 忽略 SSL 证书错误
    return;
}
javascript

完整脚本如下

注入操作

将 fiddler 证书导出,放至脚本中所设设备路径 (如:/data/local/tmp/fiddler.crt)

$ adb push /path/to/fiddler.crt /data/local/tmp/fiddler.crt
bash

将合适版本的 frida-server 上传至设备,通过 adb shell 启动

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

进行 spawn 注入

$ frida -U -f com.foo.bar --no-pause -l hooks.js
...
Spawned `com.foo.bar`. Resuming main thread!
[FooBar::com.foo.bar]-> Certificate Pinning Bypass
Crafted TrustManagers
App invoked TrustManagerFactory.getTrustManagers
App invoked TrustManagerFactory.getTrustManagers
...
bash

成功抓包

2.png

其他 pinning 方法的绕过

okhttp

var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner");

CertificatePinner.check.overload("java.lang.String", "[Ljava.security.cert.Certificate;").implementation = function (a, b) {
    console.log("App invoked CertificatePinner.check");
    return;
};

CertificatePinner.check.overload("java.lang.String", "java.util.List").implementation = function (a, b) {
    console.log("App invoked CertificatePinner.check");
    return;
};
javascript

okhttp3

var CertificatePinner = Java.use("okhttp3.CertificatePinner");

CertificatePinner.check.overload("java.lang.String", "java.util.List").implementation = function () {
    console.log("App invoked CertificatePinner.check");
}
javascript
使用 frida 绕过 Android 应用 SSL Certificate Pinning
https://zry.io/zh/security/frida-bypass-ssl-certificate-pinning-in-android-app-zh
作者 zry98
发布于 2018年10月21日