hunt-shadow-api について
hunt-shadow-apiは、旧版・内部・非推奨APIを調査し、現行版とセキュリティ上の動作を比較するテスト用スキルです。認証、レート制限、入力検証のバージョン間の退行に着目します。
主な機能
- 01パスやヘッダーによるAPIバージョンの列挙
- 02到達可能な旧版API仕様の調査
- 03バージョン間のセキュリティ動作の比較
- 04内部および非推奨ルートの確認
- 05セキュリティ退行と外観上の差の区別
活用シーン
- 01旧版APIが引き続き到達可能か確認
- 02旧版で認証やレート制限が欠けていないかテスト
- 03バージョン間のフィールド露出と入力検証を比較
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-shadow-apiインストール後、Claude Code で/hunt-shadow-apiを入力して読み込まれたか確認します。
詳細
OWASP API9 — 不適切なインベントリ管理(シャドー API/ゾンビ API)
API の進化に伴い、古いバージョンや内部/ステージング用のルートは、現行バージョンと同じセキュリティ修正が適用されないまま、引き続きアクセス可能な状態になりがちです。存在が記録されていないためです。問題は単一のエンドポイントにあることはほとんどなく、同じ操作に対して、古いバージョンが適用するセキュリティ対策と現行バージョンが適用するセキュリティ対策の差分にあります。
使用するタイミング
次の場合に実行します。
- バージョン付きのパス(
/v1/、/v2/、/api/2023-01-01/)が見つかる、またはAccept/X-API-Versionヘッダーが使われている。 - 変更履歴、リリースノート、または非推奨の通知で、削除済み/古い API の動作に言及している。
- モバイル APK/IPA(
apk-redteam-pipeline/ios-redteam-pipeline経由)に、現在のウェブアプリが呼び出すものより古いバックエンドバージョンと思われるエンドポイントがハードコードされている。 - 複数の OpenAPI/Swagger 仕様を確認できる、または仕様の
info.versionから別のバージョンの存在がうかがえる。
バージョン履歴のない単一バージョンの API には使用しないでください。差分を取る対象がないため、存在する単一のサーフェスを直接悪用する hunt-api-misconfig に進んでください。
Stage 1 — すべてのバージョンのサーフェスを列挙する
# Path-based versioning
for v in v1 v2 v3 v4 beta alpha internal legacy old 2022-01-01 2023-01-01 2024-01-01; do
curl -s -o /dev/null -w "%{http_code} /api/$v/\n" "https://$TARGET/api/$v/"
done
# Header-based versioning
curl -s -H "X-API-Version: 1" https://$TARGET/api/users
curl -s -H "Accept: application/vnd.company.v1+json" https://$TARGET/api/users
# Subdomain-based versioning
for sub in api api-v1 api-v2 apiv1 apiv2 legacy-api old-api internal-api staging-api; do
curl -s -o /dev/null -w "%{http_code} $sub\n" "https://$sub.$TARGET/"
done
古いバージョンのパスで 200/401/403 が返る場合(404/接続拒否以外)は、認証が必要な場合でも、そのバージョンは依然として稼働中であり、Stage 3 に進める価値があります。
Stage 2 — リンク先だけでなく、アクセス可能な仕様をすべて取得する
for path in openapi.json swagger.json v1/swagger.json v2/swagger.json v3/api-docs \
api-docs.json swagger/v1/swagger.json .well-known/openapi.json; do
curl -s -o /dev/null -w "%{http_code} /$path\n" "https://$TARGET/$path"
done
# Wayback Machine — a DEPRECATED version's spec often stays indexed after the live link is removed
curl -s "http://web.archive.org/cdx/search/cdx?url=$TARGET/*swagger*&output=json&collapse=urlkey"
curl -s "http://web.archive.org/cdx/search/cdx?url=$TARGET/*openapi*&output=json&collapse=urlkey"
複数の仕様(現行版とアーカイブ/旧版)が見つかった場合は、エンドポイントの一覧を直接差分比較します。
jq -r '.paths | keys[]' v1-swagger.json | sort > /tmp/v1_paths.txt
jq -r '.paths | keys[]' v2-swagger.json | sort > /tmp/v2_paths.txt
comm -23 /tmp/v1_paths.txt /tmp/v2_paths.txt # in v1 only — candidates for "still live but forgotten"
差分にある各パスについて、v1 のベース URL に対して引き続きアクセスできることを確認してください。旧版の仕様にしか記載されていないルートが、404 以外を返す場合は、ゾンビーエンドポイントの候補です。Stage 3 に進めてください。
Stage 3 — 旧版と現行版の動作を差分比較する
両バージョンに存在する各操作について、レスポンスの形式ではなく、セキュリティに関わる動作を比較します。レスポンス形式の違いは参考情報です。調査結果となるのは、セキュリティ動作の回帰です。
- 認証の強度。 現行版では拒否される、トークンなし、期限切れトークン、または権限の低いトークンを旧版が受け入れますか?
curl -s -H "Authorization: Bearer $EXPIRED_TOKEN" https://$TARGET/api/v1/users/me -w '\n%{http_code}\n' curl -s -H "Authorization: Bearer $EXPIRED_TOKEN" https://$TARGET/api/v2/users/me -w '\n%{http_code}\n' - レート制限。 両バージョンの同等のエンドポイントに対して同じ数のリクエストを連続して送信します。旧版で
429が返らない場合、レート制限が後から追加され、バックポートされていないことを意味します。 - 入力検証。 同一のインジェクション/過大サイズ/不正なペイロードを両方に送信します。新しいバージョンでは拒否されるものを旧版が受け入れる場合、強化が新しいバージョンにしか適用されていません。ペイロードが狙うインジェクションの種類(
hunt-sqli、hunt-idorなど)に引き継いでください。 - フィールドの露出。 旧版のレスポンス本文に、内部 ID、他のユーザーのデータ、内部メモ、PII など、現行版ではその後削除されたフィールドが含まれていますか?
Stage 4 — 現行 UI から参照されていない非推奨/内部ルート
- JS バンドルを Grep して、表示される UI フローから呼び出されない API 呼び出し(
/internal/、/admin/、/debug/、/_internal/、/test/、/staging/)を探します。この用途にはhunt-source-leakの JS バンドル向け Grep パターンを再利用してください。 robots.txt/sitemap.xmlで、アクセスを許可しない API パスを確認します。自ら招いた情報開示です。- モバイルアプリのエンドポイント一覧(
apk-redteam-pipeline/ios-redteam-pipeline経由)には、現在のウェブアプリが呼び出すものより古いバックエンドバージョンが記載されていることがよくあります。APK/IPA から得たエンドポイントはすべて、稼働中のウェブ API に対するバージョン差分の候補として扱ってください。
誤検知の判定基準
- バージョンの違いだけ(レスポンス形式の違いや、見た目上のフィールド名の変更など)であれば、情報提供レベルです。検出結果がセキュリティに関わるリグレッションに当たるのは、バージョン履歴を遡ったときに認証、レート制限、または検証が弱くなっている場合です。
- 古いエンドポイントが現行の実装への単なるエイリアスやプロキシではないことを確認してから、動作の違いを主張してください。レスポンス本文のバージョン文字列を比較するだけでなく、旧ロジックと新ロジックで実際に動作が異なるペイロードを送信してください。
- 静的な「この API バージョンは廃止されています。v2 を使用してください」というメッセージを返すだけのパスで
200が返っても、検出結果にはなりません。基盤となる操作が引き続き実行されることを確認してください。
深刻度テーブル
| 検出内容 | 深刻度 |
|---|---|
| 現行バージョンでは認証が必要な箇所で、旧バージョンが認証を完全に回避できる | クリティカル |
| 現行バージョンにあるレート制限が旧バージョンにはない | 中~高(hunt-brute-force と連鎖) |
| 現行バージョンと比べ、旧バージョンが余分なフィールド(PII、内部 ID)を漏えいする | 中~高 |
| 現行バージョンでは検証/サニタイズされるペイロードを、旧バージョンが受け入れる | 高(基盤となるインジェクションの種類に連鎖) |
| バージョンには到達できるが、動作は現行バージョンと同じ | 情報提供レベル |
関連スキルと連鎖先
hunt-api-misconfig— 仕様またはエンドポイントを入手した後の悪用を担当します(マスアサインメント、JWT 攻撃、OData、Swagger 連鎖攻撃)。このスキルは、より的を絞った対象を提示します。「現行のものより検証が弱いゾンビエンドポイントはこちらです。」hunt-subdomain— ホスト/サブドメインレベルの探索(独立したホストとしてのapi-v1.target.com、潜在的な乗っ取り)を担当します。このスキルは、特定のホストのバージョン領域に入った後の調査を担当します。hunt-source-leak— 内部/非公開の呼び出しを探す JS バンドルの grep。ここではシークレットの抽出ではなく、バージョン差分の検出に再利用します。apk-redteam-pipeline/ios-redteam-pipeline— モバイルビルドでは古い API バージョンがハードコードされていることがよくあります。モバイルから取得したすべてのエンドポイントが、バージョン差分の候補になります。hunt-brute-force— ここで見つかったレート制限のリグレッションは、実際にブルートフォース可能な影響(ログイン、OTP、列挙)と連鎖して初めて、完全な検出結果になります。