mcpField
I
ios-redteam-pipeline

ios-redteam-pipeline

github.com/elementalsoulsセキュリティ5.3k193 回インストール今日更新
リポジトリ

ios-redteam-pipeline について

アプリの一覧化や IPA の取得から、静的・動的解析までを段階的に進める iOS アプリ向けセキュリティテストスキルです。認可されたモバイル評価で、シークレット、通信保護、URL 処理、ネットワーク通信を調べます。

主な機能

  1. 01組織が所有する iOS アプリの一覧化
  2. 02IPA ビルドの取得と展開
  3. 03バイナリ内のエンドポイントとシークレットの検査
  4. 04ATS と証明書ピンニングの確認
  5. 05URL スキームと Universal Links のテスト
  6. 06動的計測と通信キャプチャの支援

活用シーン

  1. 01バグバウンティ対象の iOS アプリ評価
  2. 02TestFlight と App Store ビルドの比較
  3. 03モバイルアプリの通信保護とディープリンクの検査
  4. 04テスト中のアプリ通信の追跡

インストール

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

$npx skills add https://github.com/elementalsouls/claude-bughunter --skill ios-redteam-pipeline

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

詳細

このスキルを使用するタイミング

次の場合に実行します:

  • 調査で、対象の Apple Developer/App Store の発行元ページに 1 つ以上のアプリが見つかった場合
  • TestFlight の公開リンク、またはエンタープライズ/アドホック配布の .ipa/manifest.plist(OTA インストール)が見つかった場合
  • 顧客向けアプリ、ディーラー/パートナー向けポータル、または従業員向けモバイルコンパニオンアプリが iOS で提供されている場合
  • バグ報奨金プログラムの対象範囲に iOS が含まれている場合
  • apk-redteam-pipeline ですでに Android のエンドポイント/シークレットが見つかっている場合 — iOS ビルドでは異なるバージョンのバックエンドが使われていることが多く、差分調査する価値があります(hunt-shadow-api を参照)

次の場合は使用しないでください:

  • Android のみが対象の場合 — apk-redteam-pipeline を使用してください
  • React Native/Flutter アプリが、Web 側の JS バンドル分析ですでに完全にカバーされている場合
  • モバイルクライアントが対象範囲に含まれない、サーバーサイドのみの評価の場合

ステージ 0 — 組織が所有するすべての iOS アプリを一覧化する

# App Store search API (no auth, no scraping needed)
curl -s "https://itunes.apple.com/search?term=<brand>&country=us&entity=software&limit=50" | python3 -m json.tool

# Pull the full metadata for a known bundle ID (once you have one)
curl -s "https://itunes.apple.com/lookup?bundleId=com.<brand>.app&country=us"

抽出する項目:trackId、bundleId、sellerName(開発者アカウント — 関連アプリを見つけるためのピボットに使用)、version、 releaseNotes(変更履歴には非推奨/削除済みの API 動作が記載されていることが多く、hunt-shadow-api に活用できます)。

Android APK の一覧から見つかった関連アプリのバンドル ID と照合してください(同じ複数ブランドを展開する企業グループでは、通常、両プラットフォームで com.<corp>.<sub-brand> という命名規則が使われています)。


ステージ 1 — IPA の入手

優先:管理下の実機から入手する(購入済み/無料アプリなら脱獄不要)
# Install the app on a real device via Apple Configurator 2 or Xcode, then pull the .ipa
# Apple Configurator 2 (macOS): Devices > select device > right-click installed app > "Save to..."
# Or via libimobiledevice:
brew install libimobiledevice ideviceinstaller
ideviceinstaller -l              # list installed apps + bundle IDs
次点:TestFlight(プログラムでベータ版が一般公開されている場合)

TestFlight の公開リンクを開き、TestFlight アプリからインストールしてから、上記の手順で抽出します。 TestFlight ビルドは、App Store リリースよりも保護が弱いことがよくあります(デバッグログが有効なまま、ステージング API ホストがハードコードされているなど)。両方ある場合は、必ず App Store ビルドより TestFlight ビルドを優先してください。

その次:エンタープライズ/アドホック配布(OTA インストール)
# itms-services:// links embed a manifest.plist with a direct .ipa URL
curl -s "https://<target>/manifest.plist" | plutil -convert xml1 -o - -
# Look for <key>software-package</key> — that URL is a directly downloadable, unencrypted IPA
curl -sk -L "<software-package-url>" -o target.ipa

エンタープライズ/アドホックの IPA は FairPlay で暗号化されていない ため、App Store のバイナリをデバイスから取得した場合とは異なり、脱獄や復号ツールは不要です。

App Store から入手したバイナリの復号(脱獄済みデバイスから抽出した場合のみ)

App Store のバイナリは保存時に FairPlay で暗号化されています。脱獄済みデバイスからコピーしたバイナリを静的解析ツールで適切に読み取るには、実行時に復号する必要があります(frida-ios-dump、bagbak、または flexdecrypt を使用します)。

pip install --break-system-packages frida-tools
# with frida-server running on the jailbroken device and the app in foreground:
python3 dump.py <bundle_id>          # frida-ios-dump — outputs a decrypted .ipa

ステージ 2 — 展開と静的解析

# An IPA is just a zip
unzip -o target.ipa -d extracted_target/
cd extracted_target/Payload/*.app

# Info.plist — bundle ID, URL schemes, ATS config, entitlements hint
plutil -convert xml1 -o - Info.plist

# Entitlements — codesign reads the .app bundle (or the Mach-O binary), NOT Info.plist
codesign -d --entitlements :- Payload/<AppName>.app 2>/dev/null || \
  security cms -D -i embedded.mobileprovision | plutil -convert xml1 -o - -

# class-dump for Objective-C symbol/class recovery (compiled binary, not the .app bundle)
brew install class-dump
class-dump -H <AppBinaryName> -o headers/

# Swift binaries: class-dump won't show much — use Hopper, Ghidra, or `nm`/`strings` instead
nm -a <AppBinaryName> | grep -i swift | head -50
strings -a <AppBinaryName> > strings_target.txt

逆アセンブラを使わずに迅速なトリアージを行う場合、文字列ダンプだけでも通常、ステージ 3 で探す情報の大部分が見つかります。


ステージ 3 — シークレットの検索(apk-redteam-pipeline と同じカタログに、iOS 固有の情報源を追加)

# URL grep — owned-domain references
grep -oE 'https?://[a-zA-Z0-9.-]+\.(target1|target2|target3)\.(com|io|net)[a-zA-Z0-9./_?=&%-]*' strings_target.txt | sort -u

# Cloud credentials (same 60-pattern catalog as Android — reuse verbatim)
grep -oE 'AKIA[A-Z0-9]{16}'                             # AWS Access Key
grep -oE 'AIza[A-Za-z0-9_-]{35}'                        # Google API key
grep -oE 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*' strings_target.txt   # JWT

# iOS-specific: GoogleService-Info.plist (Firebase config bundled per-platform)
find extracted_target -iname "GoogleService-Info.plist" -exec plutil -convert xml1 -o - {} \;
# Look for API_KEY, PROJECT_ID, STORAGE_BUCKET, GCM_SENDER_ID, GOOGLE_APP_ID — same Firebase
# public-read tests as apk-redteam-pipeline Stage 6.

# iOS-specific: hardcoded config plists shipped in the bundle
find extracted_target -iname "*.plist" ! -iname "Info.plist" -exec sh -c 'echo "=== {} ==="; plutil -convert xml1 -o - "{}"' \;

# App Transport Security exceptions (Info.plist) — tells you if arbitrary/insecure loads are allowed
plutil -extract NSAppTransportSecurity xml1 -o - Info.plist 2>/dev/null
バックアップに残されたキーチェーン項目(デバイスのバックアップがある場合。暗号化の有無は問いません)
pip install --break-system-packages iphone_backup_decrypt   # for encrypted local backups
# keychain-dumper (run ON a jailbroken device) for live keychain contents:
./keychain-dumper -e   # -e also decodes entitlements per item, showing which app owns which secret

ステージ 4 — App Transport Security(ATS)の設定ミスと証明書ピンニングの回避

ATS が一括で無効化されていないか確認する(iOS のネットワーク設定ミスで最もよく見られるもの)
plutil -extract NSAppTransportSecurity xml1 -o - Info.plist

出力に含まれる危険な兆候:

  • トップレベルで NSAllowsArbitraryLoads = true — HTTP(平文)がアプリ全体で許可されています。
  • 認証トークンを扱うドメインに対する NSExceptionAllowsInsecureHTTPLoads = true。
  • NSAllowsArbitraryLoadsInWebContent = true — WKWebView のトラフィックが除外されています。見落としやすい問題です。

ATS の一括例外とネットワーク上の攻撃位置(不正な AP、ARP スプーフィング、悪意のある VPN プロファイル)が組み合わさると、ピンニングに一切触れることなく、認証情報/トークンを平文で傍受できます。

証明書ピンニングの回避(ピンニングが存在し、正しく設定されている場合)
pip install --break-system-packages frida-tools objection
objection --gadget <bundle_id> explore
# inside objection:
ios sslpinning disable

Frida スクリプトを使う場合は、自作せず、メンテナンスされている汎用バイパスを使用してください (例:広く使われている frida-ios-pinning/ios-ssl-bypass コミュニティスクリプト)。最新の iOS TLS は BoringSSL を経由するため、信頼性の高い汎用フックでは、ネイティブ層の SSL_CTX_set_custom_verify / SSL_get_psk_identity を対象にし、検証コールバックが「OK」を返すよう強制します。これにより、 URLSession、AFNetworking、Alamofire、TrustKit をまとめて捕捉できます。一方、非推奨の NSURLConnection デリゲートなど、デリゲートごとの Objective-C フックでは捕捉できません。

# Pull a maintained universal BoringSSL-layer bypass and run it:
frida -U -f <bundle_id> -l ios-ssl-bypass.js --no-pause

実際には、自作スクリプトより SSL Kill Switch 2(脱獄済みデバイスに tweak としてインストール)または objection の ios sslpinning disable を優先してください。どちらもアプリごとの調整をせずに、一般的な ピンニング実装(NSURLSession、AFNetworking、TrustKit)に対応します。


ステージ 5 — URL スキーム/ユニバーサルリンクの列挙

# Custom URL schemes (CFBundleURLTypes) — anything can invoke these via Safari/another app
plutil -extract CFBundleURLTypes xml1 -o - Info.plist

# Universal Links / Associated Domains (applinks:) — requires a matching apple-app-site-association
plutil -extract com.apple.developer.associated-domains xml1 -o - Info.plist 2>/dev/null
curl -s "https://<domain>/.well-known/apple-app-site-association" | python3 -m json.tool

見つかったカスタムスキームごとに(例:myapp://):

  • Safari/Notes から呼び出し、アプリがパラメーターをどう処理するかを確認します。 myapp://reset-password?token=x&redirect=https://evil.com — アプリは攻撃者が指定した redirect/url/callback パラメーターを信用して WebView で読み込むでしょうか(オープンリダイレクト → WebView-XSS の連鎖)、あるいは認証画面の回避に利用するでしょうか?
  • 同じスキームがデバイス上の別のアプリにも登録されている場合(スキームスクワッティング)、悪意のある アプリが正規アプリ宛ての通信を傍受できます。CFBundleURLName が一意であることを確認してください。
  • AASA の検証に失敗した場合、または AASA が存在しない場合、ユニバーサルリンクはカスタムスキームにフォールバックします。 同じパラメーターインジェクションの攻撃面について、両方の経路をテストしてください。

ステージ 6 — 実行時インストルメンテーション(Frida/objection)

脱獄済みデバイスが必要です(古い iOS には checkra1n/palera1n、または Corellium の仮想デバイスを使用します)。 Android とは異なり、iOS には実用的な root 化エミュレーター相当の環境はありません。

# Setup
pip install --break-system-packages frida-tools objection
# Install frida-server on the jailbroken device via Cydia/Sileo (frida repo), matching the
# host frida-tools version exactly — version skew is the #1 cause of "failed to attach" errors.

# Full interactive exploration
objection --gadget <bundle_id> explore
# Inside objection:
ios hooking watch class <ClassName>
ios hooking watch class_method <Class>.<method> --dump-args --dump-return
ios keychain dump
ios plist dump
ios cookies get
ネットワーク通信のキャプチャ(ピンニング回避後)
mitmproxy --listen-port 8080
# Set the device Wi-Fi proxy to host:8080, install the mitmproxy CA via http://mitm.it on-device
# (Settings > General > VPN & Device Management > trust the cert, then enable full trust under
# Certificate Trust Settings — iOS requires this second step, unlike Android)

判定ツリー — 発見した内容に応じた次の手順

発見事項次の手順
NSAllowsArbitraryLoads = trueトークン/認証情報が実際に HTTP を通過することを確認します。悪用にはネットワーク上の位置が必要ですが、設定レベルの発見事項として、MITM を使わずに報告できます
文字列ダンプにハードコードされた JWT/API キーがあるAndroid の場合と同様に、API ホストに対してテストし、hunt-api-misconfig につなげます
GoogleService-Info.plist が存在する公開されている Firestore/RTDB/Storage の読み取りをテストします(apk-redteam-pipeline のステージ 6 と同じです)
カスタム URL スキームが redirect/url パラメーターを受け付けるオープンリダイレクト → WebView 読み込みの連鎖をテストし、インストール済みの他のアプリによるスキームスクワッティングを確認します
ユニバーサルリンクの AASA が存在しない/誤設定されているスキームへのフォールバックでも同じインジェクション可能なパラメーターが引き継がれることを確認します
Entitlements で keychain-access-groups が他のアプリと共有されているアプリ間の Keychain 読み取りが可能です。侵害された兄弟アプリが、このアプリのシークレットを読み取ります
現在の Web アプリが呼び出すものより古い API バージョンが参照されているバージョン差分の確認を hunt-shadow-api に引き継ぎます

アンチパターン

  • App Store のアプリは FairPlay で暗号化されており、脱獄が必要だと思い込まないでください — TestFlight やエンタープライズ/アドホックビルドは暗号化されていないことが多く、復号手順がまったく必要ない場合もあります。frida-ios-dump を使う前に、必ず配布チャネルを確認してください。
  • class-dump に何も表示されないからといって、Swift のバイナリを無視しないでください — strings と nm は引き続き使えます。Swift に対応した適切な逆アセンブラー(Hopper、Swift の名前修飾解除に対応した Ghidra)を使えば、残りも解析できます。
  • 「証明書ピンニングがある」だけで調査結果としないでください — ピンニングは緩和策であり、脆弱性ではありません。調査結果は、ピンニングを回避した後にできること(または、ピンニングを無意味にする ATS の設定ミス)です。
  • WKWebView で読み込まれるコンテンツを無視しないでください — NSAllowsArbitraryLoadsInWebContent は、トップレベルの ATS 設定とは別の、見落とされやすい例外です。
  • 個人用または本番用の Apple ID 端末に対して Frida による計測を実行しないでください — 専用の脱獄済みテスト端末か Corellium インスタンスを使用してください。

ツールのインストール(初回のみ)

brew install libimobiledevice ideviceinstaller class-dump
pip install --break-system-packages frida-tools objection iphone_backup_decrypt
# Jailbroken test device (checkra1n/palera1n) or a Corellium virtual iOS device for runtime work
# frida-server installed on-device via the Frida Cydia/Sileo repo

関連スキルと連携

  • apk-redteam-pipeline — Android に対応するスキルです。対象アプリが両方のプラットフォームで提供されている場合は、両方を実行してください。プラットフォーム間で共通するバンドル ID やバックエンドのエンドポイントが見つかることがよくあります。
  • hunt-shadow-api — モバイルビルド(iOS、Android ともに)では、現在のウェブアプリより古い API バージョンがハードコードされていることがよくあります。連携の流れ:IPA から /v1/* エンドポイントを特定し、hunt-shadow-api で /v1/ と現在の /v3/ を比較して、認証や検証の不備を調べます。
  • cloud-iam-deep — IPA からのシークレット抽出で、有効な AWS/GCP/Azure の認証情報や Firebase の設定が見つかることがよくあります。連携の流れ:文字列の grep で AWS キーを検出し、cloud-iam-deep で権限を分析します。
  • hunt-api-misconfig — ここで抽出したハードコードされた JWT や API キーを使って、そちらで JWT のアルゴリズム混同や一括割り当てのテストを行います。
  • evidence-hygiene — 抽出した Keychain の項目やシークレットは、レポートに含める前にマスキングする必要があります。
  • offensive-osint — App Store の開発者ページの列挙は、より広範な組織の偵察グラフの一部です。同じブランドの証明書透明性検索と組み合わせてください。

コメント