mobile-ssl-pinning-bypass
モバイルアプリのSSLピン留めをバイパスするためのプレイブック。証明書ピン留め・公開鍵ピン留め・SPKIハッシュピン留めを実装したAndroid/iOSアプリ(React Native、Flutter、Xamarinを含む)のHTTPSトラフィックを傍受する際に使用します。
description の原文を見る
>- Mobile SSL pinning bypass playbook. Use when intercepting HTTPS traffic from mobile applications that implement certificate pinning, public key pinning, or SPKI hash pinning on Android and iOS, including React Native, Flutter, and Xamarin frameworks.
SKILL.md 本文
SKILL: Mobile SSL Pinning Bypass — Expert Attack Playbook
AI LOAD INSTRUCTION: モバイルプラットフォーム向けエキスパートSSLピンニング回避テクニック。AndroidおよびiOSの回避方法(Frida、Objection、Xposed、SSL Kill Switch)、フレームワーク固有の回避方法(Flutter、React Native、Xamarin)、非標準ピンニング実装のトラブルシューティングを対象としています。ベースモデルはフレームワーク固有のフックポイントとマルチレイヤーピンニング構成を見落とします。
0. RELATED ROUTING
詳細に入る前に、以下のロードを検討してください:
android-pentesting-tricksSSL回避を超えた幅広いAndroidテストの場合ios-pentesting-tricksSSL回避を超えた幅広いiOSテストの場合api-secトラフィックがインターセプトされた後、API レベルのテスト用
1. SSL PINNING の種類
| Pinning タイプ | ピンニング対象 | 耐性 | 一般的な用途 |
|---|---|---|---|
| 証明書ピンニング | 正確なリーフ証明書(DER/PEM) | 低(証明書更新で破損) | レガシーアプリ |
| 公開鍵ピンニング | Subject Public Key Info | 中(鍵が変わらなければ証明書更新後も有効) | モダンアプリ |
| SPKI ハッシュピンニング | SPKI の SHA-256 | 中(公開鍵ピンニングと同様) | OkHttp、AFNetworking |
| CA ピンニング | 中間 CA または ルート CA 証明書 | 高(その CA からの任意の証明書が機能) | エンタープライズアプリ |
| マルチピン(バックアップピン) | プライマリ + バックアップピン | 高(フォールバックピン) | HPKP 対応アプリ |
ピンニングの仕組み
TLS ハンドシェイク
│
├── サーバーが証明書チェーンを提示
│
├── 標準検証(システム信頼ストア)
│ └── パス? 続行 : 接続失敗
│
└── ピン検証(アプリレベルチェック)
├── サーバー証明書/公開鍵/SPKI ハッシュを抽出
├── 埋め込みピンと比較
└── マッチ発見? → 許可 : → 拒否
2. ANDROID 回避方法
2.1 Frida ユニバーサル SSL 回避
// TrustManager、OkHttp、Volley、Retrofit、Conscryptをフック
Java.perform(function() {
// ── TrustManagerImpl(Android システム) ──
try {
var TMI = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TMI.verifyChain.implementation = function() {
console.log('[Bypass] TrustManagerImpl.verifyChain');
return arguments[0]; // チェーンをそのまま返す
};
} catch(e) {}
// ── X509TrustManager(カスタム実装) ──
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 インターセプター ──
try {
var OkHttpClient = Java.use('okhttp3.OkHttpClient$Builder');
OkHttpClient.certificatePinner.implementation = function(pinner) {
console.log('[Bypass] OkHttpClient.Builder.certificatePinner');
return this; // ピナーなしでビルダーを返す
};
} 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);
// ホスト名ベリファイアーを削除
conn.setHostnameVerifier(Java.use(
'javax.net.ssl.HttpsURLConnection').getDefaultHostnameVerifier());
return conn;
};
} catch(e) {}
// ── Conscrypt / BoringSSL(モダン Android) ──
try {
var Conscrypt = Java.use('org.conscrypt.ConscryptFileDescriptorSocket');
Conscrypt.verifyCertificateChain.implementation = function() {
console.log('[Bypass] Conscrypt verifyCertificateChain');
};
} catch(e) {}
// ── Apache HttpClient(レガシー) ──
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] カスタム HostnameVerifier を無視');
};
} catch(e) {}
console.log('[+] Android ユニバーサル SSL バイパス ロード完了');
});
2.2 Objection(ワンコマンド)
objection -g com.target.app explore --startup-command "android sslpinning disable"
2.3 Network Security Config(デバッグオーバーライド)
<!-- AndroidManifest.xml: android:networkSecurityConfig="@xml/network_security_config" -->
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" /> <!-- ユーザーがインストール済みの CA を信頼 -->
</trust-anchors>
</base-config>
</network-security-config>
ワークフロー:APKを逆コンパイル → 設定を追加/修正 → 再パッケージ → 再署名 → インストール。
apktool d target.apk -o target_dir
# res/xml/network_security_config.xml を編集
# 必要に応じて AndroidManifest.xml に参照を追加
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 必須 |
|---|---|---|---|
| JustTrustMe | TrustManager + OkHttp をフック | アプリごと | Yes(Xposed) |
| SSLUnpinning | 証明書検証をフック | アプリごと | Yes(LSPosed) |
| TrustMeAlready | グローバル TrustManager バイパス | システム全体 | Yes(LSPosed) |
2.5 Magisk + System CA インストール
# プロキシ CA をシステム証明書としてインストール(Android 7+ ではシステムレベルの信頼に必須)
# 方法 1:MagiskTrustUserCerts モジュール
# Magisk オーバーレイ経由でユーザー CA を /system/etc/security/cacerts/ に移動
# 方法 2:手動(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 # ハッシュネーム
chmod 644 /system/etc/security/cacerts/9a5ba575.0
mount -o remount,ro /system
# 正しいハッシュファイル名を取得:
openssl x509 -inform PEM -subject_hash_old -in burp_ca.pem | head -1
# 出力:9a5ba575 → ファイル名は 9a5ba575.0
2.6 手動逆コンパイル → パッチ → 再パッケージ
# ステップ 1:逆コンパイル
jadx -d decompiled/ target.apk
# ステップ 2:ピンニングコードを検索
grep -r "CertificatePinner\|X509TrustManager\|checkServerTrusted\|ssl" decompiled/
# ステップ 3:ピンニング実装を特定してパッチ
# より細かな制御のため smali 編集を使用:
apktool d target.apk
# smali ファイルを編集してピンニングチェックを NOP アウト
# invoke-virtual {checkServerTrusted} を探して return-void に置き換え
# ステップ 4:再パッケージと署名
apktool b target_dir -o patched.apk
apksigner sign --ks debug.keystore patched.apk
3. iOS 回避方法
3.1 Frida(SecTrust フック)
// iOS SSL 検証関数のコアをフック
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));
}
});
// SSLHandshake をフック(より低レベル)
var SSLHandshake = Module.findExportByName('Security', 'SSLHandshake');
if (SSLHandshake) {
Interceptor.attach(SSLHandshake, {
onLeave: function(retval) {
if (retval.toInt32() === -9807) { // errSSLXCertChainInvalid
retval.replace(ptr(0));
}
}
});
}
// NSURLSession デリゲートメソッドをフック
try {
var cls = ObjC.classes.NSURLSession;
// デリゲート上の URLSession:didReceiveChallenge:completionHandler: をフック
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] デリゲート検出: ' + 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(Jailbreak Tweak)
# Cydia/Sileo 経由でインストール
# パッケージ:com.nablac0d3.sslkillswitch2
# SSL ピンニングをシステム全体または Settings トグル経由でアプリごとに無効化
# フック対象:
# - SecTrustEvaluate
# - SSLHandshake
# - SSLSetSessionOption
# - tls_helper_create_peer_trust
3.4 ライブラリ固有フック
| ライブラリ | iOS フックポイント | Frida アプローチ |
|---|---|---|
| AFNetworking | AFSecurityPolicy.evaluateServerTrust:forDomain: | YES を返す |
| Alamofire | ServerTrustManager.evaluate(_:forHost:) | 検証をスキップ |
| TrustKit | TSKPinningValidator verifyPublicKeyPin: | 成功を返す |
| NSURLSession | URLSession:didReceiveChallenge:completionHandler: | .useCredential で completionHandler を呼び出す |
3.5 手動バイナリパッチ
# バイナリ内のピンニング関数を検索
strings decrypted_binary | grep -i "pin\|cert\|trust"
# バイナリを逆アセンブルして検証関数を探す
# 比較/分岐命令を NOP または無条件パスに置き換え
# LLDB ランタイム修正
lldb -n TargetApp
(lldb) breakpoint set -n "SecTrustEvaluateWithError"
(lldb) breakpoint command add 1
> thread return 1
> continue
> DONE
4. フレームワーク固有の回避
4.1 Flutter
Flutter は Dart の dart:io ライブラリと、その下の BoringSSL を使用します。Java/ObjC レイヤーの標準 Frida フックは機能しません。
// Flutter SSL バイパス — BoringSSL を直接フックする必要あり
// libflutter.so 内の ssl_crypto_x509_session_verify_cert_chain を検索
var libflutter = Process.findModuleByName('libflutter.so'); // Android
// var libflutter = Process.findModuleByName('Flutter'); // iOS
// ssl_verify_peer_cert をフック(BoringSSL 関数)
// シグネチャは Flutter バージョンによって異なる — パターンスキャンを使用
var pattern = 'FF C3 ..'; // サンプルパターン、異なる場合あり
var matches = Memory.scan(libflutter.base, libflutter.size, pattern, {
onMatch: function(address, size) {
console.log('[Flutter] 潜在的な検証関数のアドレス: ' + address);
Interceptor.attach(address, {
onLeave: function(retval) {
retval.replace(ptr(0)); // SSL_VERIFY_OK
}
});
},
onComplete: function() {}
});
// 代替案:reflutter ツールを使用した自動パッチング
// reflutter target.apk
// Flutter エンジンの BoringSSL を直接パッチし、トラフィックをプロキシにリダイレクト
reflutter ツール(Flutter アプリの推奨):
pip install reflutter
reflutter target.apk
# パッチ済み APK を出力、プロキシにトラフィックをリダイレクト
# BoringSSL エンジンの SSL 検証も無効化
4.2 React Native
React Native はプラットフォームネットワークを使用:Android では OkHttp、iOS では NSURLSession。
| プラットフォーム | ネットワークスタック | 回避方法 |
|---|---|---|
| Android | OkHttp3 | 標準 OkHttp CertificatePinner フック |
| iOS | NSURLSession | 標準 SecTrust フック |
| Android(Hermes) | 同じ OkHttp | 同じフック、ただし Hermes JIT には追加対応が必要な場合あり |
// React Native Android — OkHttp バイパスと同じ
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 が見つかりません、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 ピンニングは通常以下を経由:
// ServicePointManager.ServerCertificateValidationCallback
// またはカスタム HttpClientHandler
// Xamarin 向け Frida バイパス(Mono ランタイム)
// Mono メソッドをフック:System.Net.ServicePointManager.set_ServerCertificateValidationCallback
var mono_method = Module.findExportByName('libmonosgen-2.0.so',
'mono_runtime_invoke');
// より実用的:CIL レベルでマネージコールバックをフック
// Frida の Mono ブリッジまたは objection の組み込み Xamarin サポートを使用
// Objection には組み込みの Xamarin バイパスがあります:
// objection -g com.target.app explore
// > android sslpinning disable (Android での Xamarin をカバー)
5. Certificate Transparency & HPKP
| テクノロジー | ステータス | テスト時の影響 |
|---|---|---|
| Certificate Transparency(CT) | アクティブ、ブラウザで強制 | モバイルアプリはめったに CT を強制しません。バイパス障害ではありません |
| HPKP(HTTP Public Key Pinning) | 非推奨(2018) | レガシーアプリが引き続きチェック可能。プロキシレスポンスからヘッダーを削除 |
| Expect-CT ヘッダー | 非推奨(2024) | モバイルテストへの影響は最小限 |
| モバイルアプリの CT | 稀 | Google アプリのみがカスタム CT チェック経由で強制 |
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 stapling 不一致 | OCSP チェックを無効化または OCSP レスポンダーをモック |
6.2 診断ステップ
# プロキシ CA が正しくインストールされているか確認
# Android:
adb shell "ls /system/etc/security/cacerts/ | grep $(openssl x509 -subject_hash_old -in ca.pem | head -1)"
# iOS: 設定 → 一般 → 情報 → 証明書信頼設定
# ターゲットアプリが実際に SSL を使用しているか確認(プレーン HTTP ではなく)
# Wireshark フィルタ:tcp.port == 443 and ip.addr == <device_ip>
# Frida が正しいプロセスをフックしているか確認
frida-ps -U | grep target
# デバッグ用に Frida の詳細出力
frida -U -f com.target.app -l bypass.js --debug
7. SSL Pinning Bypass 判定ツリー
モバイルアプリ HTTPS トラフィックをインターセプトする必要
│
├── プラットフォーム?
│ ├── Android ↓
│ │ ├── Root 化されたデバイスが利用可能?
│ │ │ ├── はい → Frida ユニバーサルバイパス(§2.1)【最初に試す】
│ │ │ │ ├── 動作? → 完了
│ │ │ │ └── 失敗? → Conscrypt + Volley フックを追加
│ │ │ ├── 引き続き失敗? → LSPosed + TrustMeAlready(§2.4)
│ │ │ └── 引き続き失敗? → CA をシステム証明書としてインストール(§2.5)
│ │ └── Root 化なし?
│ │ ├── デバッグビルド? → Network Security Config(§2.3)
│ │ └── リリースビルド? → 逆コンパイル + パッチ + 再パッケージ(§2.6)
│ │
│ └── iOS ↓
│ ├── Jailbreak 化されたデバイスが利用可能?
│ │ ├── はい → Objection ios sslpinning disable(§3.2)【最初に試す】
│ │ │ ├── 動作? → 完了
│ │ │ └── 失敗? → Frida SecTrust フック(§3.1)
│ │ ├── 引き続き失敗? → SSL Kill Switch 2(§3.3)
│ │ └── 引き続き失敗? → ライブラリ固有フック(§3.4)
│ └── Jailbreak なし?
│ ├── Frida gadget で再署名 → Frida フック実行
│ └── バイナリパッチ → sideload(§3.5)
│
├── フレームワーク固有アプリ?
│ ├── Flutter → reflutter ツール または BoringSSL ネイティブフック(§4.1)
│ ├── React Native → 標準プラットフォームフック(§4.2)
│ └── Xamarin → Objection または Mono ランタイムフック(§4.3)
│
├── バイパスは動作するが問題が残存?
│ ├── クライアント証明書が必要? → 抽出 + プロキシにインポート(§6.1)
│ ├── 非 HTTP プロトコル? → プロトコル固有ツール(§6.1)
│ └── アプリがクラッシュ? → まずアンチタンパリングを修正(§6.1)
│
└── すべての方法が失敗?
├── ネットワークレベルでトラフィックを分析(Wireshark/tcpdump)
├── カスタム独自プロトコルをチェック
└── iptables + 透過プロキシアプローチを検討
8. プロキシ設定クイックリファレンス
| プロキシツール | 最適用途 | SSL バイパス統合 |
|---|---|---|
| Burp Suite | 完全な HTTP 分析 | CA をデバイスにインポート |
| mitmproxy | スクリプト化されたインターセプション | mitmproxy --set confdir=~/.mitmproxy |
| Charles Proxy | macOS ネイティブ、セットアップが簡単 | 組み込み CA インストール |
| Proxyman | macOS/iOS ネイティブ | iOS デバイス直接対応 |
| HTTP Toolkit | Android クイックセットアップ | 自動化 CA + Frida バイパス |
# Android プロキシ設定
adb shell settings put global http_proxy <host_ip>:8080
# プロキシ削除
adb shell settings put global http_proxy :0
# iOS プロキシ:設定 → Wi-Fi → プロキシを設定 → 手動
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- yaklang
- リポジトリ
- yaklang/hack-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/yaklang/hack-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。