mcpField
M
mobile-ssl-pinning-bypass

mobile-ssl-pinning-bypass

github.com/yaklangセキュリティ2.6k3.7k 回インストール6 週間前に更新
リポジトリ

mobile-ssl-pinning-bypass について

AndroidとiOSアプリのSSLピンニングを調べるモバイルセキュリティテストガイドです。実行時フック、アプリのパッチ、フレームワーク別の手法、通信傍受に失敗した場合の診断を扱います。

主な機能

  1. 01AndroidとiOSの回避手法
  2. 02FridaとObjectionのフック
  3. 03アプリのデコンパイルと再パッケージ
  4. 04Flutter、React Native、Xamarinの解説
  5. 05ピンニング失敗の診断

活用シーン

  1. 01許可されたテストでアプリのHTTPS通信を傍受
  2. 02複数層のピンニングがあるアプリのテスト
  3. 03Flutterアプリのネットワーク検証の調査
  4. 04プロキシ証明書の信頼問題の診断

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill mobile-ssl-pinning-bypass

インストール後、Claude Code で/mobile-ssl-pinning-bypassを入力して読み込まれたか確認します。

詳細

スキル:モバイル SSL ピンニングのバイパス — エキスパート向け攻撃プレイブック

AI LOAD INSTRUCTION:モバイルプラットフォーム向けのエキスパートレベルの SSL ピンニングバイパス技術です。Android と iOS のバイパス方法(Frida、Objection、Xposed、SSL Kill Switch)、フレームワーク固有のバイパス(Flutter、React Native、Xamarin)、標準的でないピンニング実装のトラブルシューティングを扱います。ベースモデルでは、フレームワーク固有のフックポイントや多層ピンニング構成を見落とします。

0. 関連するルーティング

詳しく調べる前に、次の読み込みを検討してください。

  • SSL バイパス以外の Android テスト全般については、android-pentesting-tricks
  • SSL バイパス以外の iOS テスト全般については、ios-pentesting-tricks
  • トラフィックを傍受した後の API レベルのテストについては、api-sec

1. SSL ピンニングの種類

ピンニングの種類ピンニング対象耐性よく使われる環境
証明書ピンニングリーフ証明書そのもの(DER/PEM)低(証明書のローテーションで機能しなくなる)レガシーアプリ
公開鍵ピンニングSubject Public Key Info中(鍵が変わらなければ証明書の更新後も有効)最新のアプリ
SPKI ハッシュピンニングSPKI の SHA-256中(公開鍵ピンニングと同じ)OkHttp、AFNetworking
CA ピンニング中間またはルート CA 証明書高(その CA が発行した証明書ならどれでも有効)エンタープライズアプリ
マルチピンニング(バックアップピン)プライマリピン+バックアップピン高(フォールバックピン)HPKP 対応アプリ
ピンニングの仕組み
TLS Handshake
│
├── Server presents certificate chain
│
├── Standard validation (system trust store)
│   └── Passes? continue : connection fails
│
└── Pin validation (app-level check)
    ├── Extract server cert/pubkey/SPKI hash
    ├── Compare against embedded pins
    └── Match found? → allow : → reject connection

2. Android のバイパス方法

2.1 Frida による汎用 SSL バイパス
// Hooks TrustManager, OkHttp, Volley, Retrofit, Conscrypt
Java.perform(function() {

    // ── TrustManagerImpl (Android system) ──
    try {
        var TMI = Java.use('com.android.org.conscrypt.TrustManagerImpl');
        TMI.verifyChain.implementation = function() {
            console.log('[Bypass] TrustManagerImpl.verifyChain');
            return arguments[0]; // return untouched chain
        };
    } catch(e) {}

    // ── X509TrustManager (custom implementations) ──
    var TrustManager = Java.registerClass({
        name: 'com.bypass.TrustManager',
        implements: [Java.use('javax.net.ssl.X509TrustManager')],
        methods: {
            checkClientTrusted: function() {},
            checkServerTrusted: function() {},
            getAcceptedIssuers: function() { return []; }
        }
    });

    var SSLContext = Java.use('javax.net.ssl.SSLContext');
    SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;',
        '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom')
        .implementation = function(km, tm, sr) {
        console.log('[Bypass] SSLContext.init');
        this.init(km, [TrustManager.$new()], sr);
    };

    // ── OkHttp3 CertificatePinner ──
    try {
        var CP = Java.use('okhttp3.CertificatePinner');
        CP.check.overload('java.lang.String', 'java.util.List').implementation = function() {
            console.log('[Bypass] OkHttp3 CertificatePinner.check: ' + arguments[0]);
        };
        // check$okhttp variant (OkHttp 4.x)
        try { CP['check$okhttp'].implementation = function() {}; } catch(e) {}
    } catch(e) {}

    // ── Retrofit / OkHttp interceptor ──
    try {
        var OkHttpClient = Java.use('okhttp3.OkHttpClient$Builder');
        OkHttpClient.certificatePinner.implementation = function(pinner) {
            console.log('[Bypass] OkHttpClient.Builder.certificatePinner');
            return this; // return builder without pinner
        };
    } catch(e) {}

    // ── Volley (HurlStack) ──
    try {
        var HurlStack = Java.use('com.android.volley.toolbox.HurlStack');
        HurlStack.createConnection.implementation = function(url) {
            console.log('[Bypass] Volley HurlStack: ' + url);
            var conn = this.createConnection(url);
            // Remove hostname verifier
            conn.setHostnameVerifier(Java.use(
                'javax.net.ssl.HttpsURLConnection').getDefaultHostnameVerifier());
            return conn;
        };
    } catch(e) {}

    // ── Conscrypt / BoringSSL (modern Android) ──
    try {
        var Conscrypt = Java.use('org.conscrypt.ConscryptFileDescriptorSocket');
        Conscrypt.verifyCertificateChain.implementation = function() {
            console.log('[Bypass] Conscrypt verifyCertificateChain');
        };
    } catch(e) {}

    // ── Apache HttpClient (legacy) ──
    try {
        var AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');
        AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String;',
            '[Ljava.lang.String;', 'boolean').implementation = function() {
            console.log('[Bypass] Apache AbstractVerifier');
        };
    } catch(e) {}

    // ── HostnameVerifier ──
    try {
        var HV = Java.use('javax.net.ssl.HttpsURLConnection');
        HV.setDefaultHostnameVerifier.implementation = function(v) {
            console.log('[Bypass] Ignoring custom HostnameVerifier');
        };
    } catch(e) {}

    console.log('[+] Android universal SSL bypass loaded');
});
2.2 Objection(ワンコマンド)
objection -g com.target.app explore --startup-command "android sslpinning disable"
2.3 Network Security Config(デバッグ用オーバーライド)



<network-security-config>
  <base-config>
    <trust-anchors>
      <certificates src="system" />
      <certificates src="user" />     
    </trust-anchors>
  </base-config>
</network-security-config>

ワークフロー:APK を逆コンパイル → 設定を追加/変更 → 再パッケージ化 → 再署名 → インストール。

apktool d target.apk -o target_dir
# Edit res/xml/network_security_config.xml
# Add reference in AndroidManifest.xml if missing
apktool b target_dir -o target_patched.apk
zipalign -v 4 target_patched.apk target_aligned.apk
apksigner sign --ks my-key.keystore target_aligned.apk
adb install target_aligned.apk
2.4 Xposed/LSPosed モジュール
モジュール方法適用範囲root 権限が必要
JustTrustMeTrustManager と OkHttp にフックアプリ単位はい(Xposed)
SSLUnpinning証明書の検証にフックアプリ単位はい(LSPosed)
TrustMeAlreadyシステム全体の TrustManager をバイパスシステム全体はい(LSPosed)
2.5 Magisk + システム CA のインストール
# Install proxy CA as system cert (Android 7+ requires this for system-level trust)
# Method 1: MagiskTrustUserCerts module
# Moves user CAs to /system/etc/security/cacerts/ via Magisk overlay

# Method 2: Manual (requires root)
adb push burp_ca.pem /sdcard/
adb shell
su
mount -o remount,rw /system
cp /sdcard/burp_ca.pem /system/etc/security/cacerts/9a5ba575.0  # hash-named
chmod 644 /system/etc/security/cacerts/9a5ba575.0
mount -o remount,ro /system

# Get correct hash filename:
openssl x509 -inform PEM -subject_hash_old -in burp_ca.pem | head -1
# Output: 9a5ba575 → filename is 9a5ba575.0
2.6 手動で逆コンパイル → パッチ → 再パッケージ化
# Step 1: Decompile
jadx -d decompiled/ target.apk

# Step 2: Find pinning code
grep -r "CertificatePinner\|X509TrustManager\|checkServerTrusted\|ssl" decompiled/

# Step 3: Identify pinning implementation and patch
# Use smali editing for precise control:
apktool d target.apk
# Edit smali files to NOP out pinning checks
# Look for invoke-virtual {checkServerTrusted} and replace with return-void

# Step 4: Repackage and sign
apktool b target_dir -o patched.apk
apksigner sign --ks debug.keystore patched.apk

3. iOS のバイパス方法

3.1 Frida(SecTrust フック)
// Hook core iOS SSL validation functions
var SecTrustEvaluateWithError = Module.findExportByName('Security', 'SecTrustEvaluateWithError');
Interceptor.attach(SecTrustEvaluateWithError, {
    onLeave: function(retval) {
        retval.replace(ptr(1));
    }
});

var SecTrustEvaluate = Module.findExportByName('Security', 'SecTrustEvaluate');
Interceptor.attach(SecTrustEvaluate, {
    onLeave: function(retval) {
        retval.replace(ptr(0));
    }
});

// Hook SSLHandshake (lower-level)
var SSLHandshake = Module.findExportByName('Security', 'SSLHandshake');
if (SSLHandshake) {
    Interceptor.attach(SSLHandshake, {
        onLeave: function(retval) {
            if (retval.toInt32() === -9807) { // errSSLXCertChainInvalid
                retval.replace(ptr(0));
            }
        }
    });
}

// Hook NSURLSession delegate method
try {
    var cls = ObjC.classes.NSURLSession;
    // Hook URLSession:didReceiveChallenge:completionHandler: on delegates
    ObjC.enumerateLoadedClasses({
        onMatch: function(name) {
            try {
                var methods = ObjC.classes[name].$ownMethods;
                for (var i = 0; i < methods.length; i++) {
                    if (methods[i].indexOf('didReceiveChallenge') !== -1 &&
                        methods[i].indexOf('completionHandler') !== -1) {
                        console.log('[SSL] Found delegate: ' + name + ' ' + methods[i]);
                    }
                }
            } catch(e) {}
        },
        onComplete: function() {}
    });
} catch(e) {}
3.2 Objection(ワンコマンド)
objection -g com.target.app explore --startup-command "ios sslpinning disable"
3.3 SSL Kill Switch 2(脱獄用 Tweak)
# Install via Cydia/Sileo
# Package: com.nablac0d3.sslkillswitch2
# Disables SSL pinning system-wide or per-app via Settings toggle

# Hooks:
# - SecTrustEvaluate
# - SSLHandshake
# - SSLSetSessionOption
# - tls_helper_create_peer_trust
3.4 ライブラリ固有のフック
ライブラリiOS のフックポイントFrida のアプローチ
AFNetworkingAFSecurityPolicy.evaluateServerTrust:forDomain:YES を返す
AlamofireServerTrustManager.evaluate(_:forHost:)評価をスキップ
TrustKitTSKPinningValidator verifyPublicKeyPin:成功を返す
NSURLSessionURLSession:didReceiveChallenge:completionHandler:.useCredential を指定して completionHandler を呼び出す
3.5 手動でのバイナリパッチ
# Find pinning function in binary
strings decrypted_binary | grep -i "pin\|cert\|trust"
# Disassemble and find the validation function
# Replace comparison/branch instruction with NOP or unconditional pass

# LLDB runtime modification
lldb -n TargetApp
(lldb) breakpoint set -n "SecTrustEvaluateWithError"
(lldb) breakpoint command add 1
> thread return 1
> continue
> DONE

4. フレームワーク固有のバイパス

4.1 Flutter

Flutter は、内部で BoringSSL を使用する Dart の dart:io ライブラリを使います。Java/ObjC レイヤーへの標準的な Frida フックは機能しません。

// Flutter SSL bypass — must hook BoringSSL directly
// Find ssl_crypto_x509_session_verify_cert_chain in libflutter.so
var libflutter = Process.findModuleByName('libflutter.so');  // Android
// var libflutter = Process.findModuleByName('Flutter');       // iOS

// Hook ssl_verify_peer_cert (BoringSSL function)
// Signature varies by Flutter version — use pattern scanning
var pattern = 'FF C3 ..';  // Example pattern, varies
var matches = Memory.scan(libflutter.base, libflutter.size, pattern, {
    onMatch: function(address, size) {
        console.log('[Flutter] Potential verify function at: ' + address);
        Interceptor.attach(address, {
            onLeave: function(retval) {
                retval.replace(ptr(0));  // SSL_VERIFY_OK
            }
        });
    },
    onComplete: function() {}
});

// Alternative: use reflutter tool for automated patching
// reflutter target.apk
// This patches BoringSSL in the Flutter engine directly

reflutter ツール(Flutter アプリに推奨):

pip install reflutter
reflutter target.apk
# Outputs patched APK that redirects traffic to your proxy
# Also disables SSL verification in the BoringSSL engine
4.2 React Native

React Native はプラットフォームのネットワーク機能を使用します。Android では OkHttp、iOS では NSURLSession を使用します。

プラットフォームネットワークスタックバイパス方法
AndroidOkHttp3標準的な OkHttp CertificatePinner フック
iOSNSURLSession標準的な SecTrust フック
Android(Hermes)同じ OkHttp同じフック。ただし、Hermes JIT には追加の対応が必要な場合があります
// React Native Android — same as OkHttp bypass
Java.perform(function() {
    try {
        var CP = Java.use('okhttp3.CertificatePinner');
        CP.check.overload('java.lang.String', 'java.util.List').implementation = function() {};
    } catch(e) { console.log('OkHttp3 not found, trying okhttp2...'); }

    try {
        var CP2 = Java.use('com.squareup.okhttp.CertificatePinner');
        CP2.check.overload('java.lang.String', 'java.util.List').implementation = function() {};
    } catch(e) {}
});
4.3 Xamarin
// Xamarin pinning typically via:
// ServicePointManager.ServerCertificateValidationCallback
// or custom HttpClientHandler
// Frida bypass for Xamarin (Mono runtime)
// Hook Mono method: System.Net.ServicePointManager.set_ServerCertificateValidationCallback
var mono_method = Module.findExportByName('libmonosgen-2.0.so',
    'mono_runtime_invoke');
// More practical: hook the managed callback at CIL level
// Use Frida's Mono bridge or objection's built-in Xamarin support

// Objection has built-in Xamarin bypass:
// objection -g com.target.app explore
// > android sslpinning disable   (covers Xamarin on Android)

5. 証明書の透明性と HPKP

技術状況テストへの影響
Certificate Transparency(CT)有効。ブラウザーで強制されるモバイルアプリで CT が強制されることはまれです。バイパスの障害にはなりません
HPKP(HTTP Public Key Pinning)非推奨(2018 年)レガシーアプリでまだチェックされる場合があります。プロキシの応答からヘッダーを削除してください
Expect-CT ヘッダー非推奨(2024 年)モバイルテストへの影響は最小限です
モバイルアプリでの CTまれカスタム CT チェックによって強制されるのは Google アプリのみです

6. トラブルシューティング

6.1 よくある失敗
症状原因対処法
バイパススクリプトは読み込まれたが、通信が依然として失敗するピンニング層が複数あるすべての層にフックします:TrustManager + OkHttp + カスタムチェック
「クライアント証明書が必要です」相互 TLS(mTLS)アプリのバンドル/キーチェーンからクライアント証明書を抽出し、プロキシにインポートします
接続はできるが、HTTP トラフィックがない非 HTTP プロトコル(MQTT、gRPC、WebSocket)Wireshark またはプロトコル専用のプロキシを使用します
バイパス後にアプリがクラッシュする改ざん防止機能がフックを検出するまず整合性チェックをバイパスし、その後 SSL をバイパスします
プロキシの CA が信頼されないAndroid 7 以降のユーザー CA 制限CA をシステム証明書としてインストールします(Magisk モジュール)
Flutter アプリがフックを無視するネイティブ層で BoringSSL がフックされていないreflutter またはネイティブの BoringSSL フックを使用します
証明書チェーンの検証がタイムアウトするOCSP ステープリングの不一致OCSP チェックを無効にするか、OCSP レスポンダーをモックします
6.2 診断手順
# Verify proxy CA is installed correctly
# Android:
adb shell "ls /system/etc/security/cacerts/ | grep $(openssl x509 -subject_hash_old -in ca.pem | head -1)"

# iOS: Settings → General → About → Certificate Trust Settings

# Check if target app is actually using SSL (vs. plain HTTP)
# Wireshark filter: tcp.port == 443 and ip.addr == <device_ip>

# Check if Frida is hooking the right process
frida-ps -U | grep target

# Verbose Frida output for debugging hooks
frida -U -f com.target.app -l bypass.js --debug

7. SSL ピンニングのバイパス判断ツリー

Need to intercept mobile app HTTPS traffic
│
├── Platform?
│   ├── Android ↓
│   │   ├── Rooted device available?
│   │   │   ├── Yes → Frida universal bypass (§2.1) [FIRST TRY]
│   │   │   │   ├── Works? → done
│   │   │   │   └── Fails? → add Conscrypt + Volley hooks
│   │   │   ├── Still fails? → LSPosed + TrustMeAlready (§2.4)
│   │   │   └── Still fails? → install CA as system cert (§2.5)
│   │   └── No root?
│   │       ├── Debug build? → Network Security Config (§2.3)
│   │       └── Release build? → decompile + patch + repackage (§2.6)
│   │
│   └── iOS ↓
│       ├── Jailbroken device available?
│       │   ├── Yes → Objection ios sslpinning disable (§3.2) [FIRST TRY]
│       │   │   ├── Works? → done
│       │   │   └── Fails? → Frida SecTrust hooks (§3.1)
│       │   ├── Still fails? → SSL Kill Switch 2 (§3.3)
│       │   └── Still fails? → library-specific hooks (§3.4)
│       └── No jailbreak?
│           ├── Re-sign with Frida gadget → run Frida hooks
│           └── Binary patch → sideload (§3.5)
│
├── Framework-specific app?
│   ├── Flutter → reflutter tool or BoringSSL native hooks (§4.1)
│   ├── React Native → standard platform hooks (§4.2)
│   └── Xamarin → Objection or Mono runtime hooks (§4.3)
│
├── Bypass works but issues remain?
│   ├── Client cert required? → extract + import to proxy (§6.1)
│   ├── Non-HTTP protocol? → protocol-specific tooling (§6.1)
│   └── App crashes? → fix anti-tampering first (§6.1)
│
└── All methods fail?
    ├── Analyze traffic at network level (Wireshark/tcpdump)
    ├── Check for custom proprietary protocol
    └── Consider iptables + transparent proxy approach

8. プロキシ設定クイックリファレンス

プロキシツール最適な用途SSL バイパスの連携
Burp SuiteHTTP の包括的な分析CA をデバイスにインポート
mitmproxyスクリプトによる傍受mitmproxy --set confdir=~/.mitmproxy
Charles ProxymacOS ネイティブ、簡単な設定CA のインストール機能を内蔵
ProxymanmacOS/iOS ネイティブiOS デバイスを直接サポート
HTTP ToolkitAndroid の迅速な設定CA と Frida バイパスを自動化
# Android proxy setup
adb shell settings put global http_proxy <host_ip>:8080

# Remove proxy
adb shell settings put global http_proxy :0

# iOS proxy: Settings → Wi-Fi → Configure Proxy → Manual

コメント