mcpField
I
idor-broken-object-authorization

idor-broken-object-authorization

github.com/yaklang安全2.6k3.8k 次安装6 周前更新
代码仓库

关于 idor-broken-object-authorization

面向授权 API 安全测试的 IDOR 与对象级授权缺陷检查技能,涵盖跨账户验证、不同 ID 位置、HTTP 方法及间接引用等测试。也区分对象级与功能级授权问题,并整理批量操作、隐藏字段和状态流测试方法。

主要功能

  1. 01双账户交叉验证方法
  2. 02检查路径、参数及请求体中的 ID
  3. 03测试不同 HTTP 方法的授权
  4. 04检查间接引用与子资源
  5. 05区分 BOLA 与 BFLA
  6. 06检查批量操作及隐藏字段

适用场景

  1. 01验证跨账户数据读取与修改
  2. 02检查管理端点的功能级授权
  3. 03测试附件等关联资源的访问控制
  4. 04评估 API 状态流与批量操作

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill idor-broken-object-authorization

安装后在 Claude Code 中输入/idor-broken-object-authorization确认已加载。

详细介绍

技能:IDOR / 对象级授权失效——专家攻击手册

AI 加载指令:IDOR 是漏洞赏金中排名第一的发现。本技能涵盖不明显的 IDOR 攻击面、所有攻击向量(不只是 URL 参数)、A-B 测试方法、BOLA 与 BFLA 的区别、利用 IDOR 链接造成更高影响,以及测试人员反复遗漏的问题。


1. IDOR 与 BOLA、BFLA 的区别

术语含义影响
IDOR不安全的直接对象引用读取/修改其他用户的数据
BOLA对象级授权失效(OWASP API Top 10 A1)与 IDOR 相同,是 API 术语
BFLA功能级授权失效低权限用户访问高权限功能(例如,管理员端点)

关键区别:

  • BOLA = 访问不应由自己拥有的对象(属于其他用户的数据)
  • BFLA = 访问自己无权使用的功能(管理员 CRUD 操作、批量操作、用户管理)

2. 在哪里查找对象 ID(所有位置)

不要只检查 URL 路径参数——ID 还会出现在:

URL path:        GET /api/v1/users/1234/profile
URL query:       GET /orders?order_id=982
Request body:    {"userId": 1234, "action": "view"}
JSON fields:     {"resource": {"id": 5678, "type": "invoice"}}
Headers:         X-User-ID: 1234
                 X-Account-ID: 9999
Cookies:         user_id=1234; account=org_5678
GraphQL args:    query { user(id: "1234") { ... } }
Form fields:     <input name="documentId" value="5678">
WebSocket msgs:  {"event":"subscribe","channel_id":9999}

3. A-B 测试方法

最系统的 IDOR 测试方法:

Step 1: Create two test accounts: UserA and UserB
Step 2: Perform all actions as UserA, capture all requests
        (profile edit, order view, password change, file access, etc.)
Step 3: Note every object ID created or accessed by UserA
Step 4: Authenticate as UserB
Step 5: Replay UserA's requests using UserB's session token
Step 6: If UserB can read/modify UserA's data → BOLA confirmed

Victim matters: for real bugs, target existing users, not test accounts.
Report evidence: show UserA owns the resource, UserB accessed it.

4. ID 类型及其影响

ID 模式示例说明
顺序整数id=1001 → id=1002容易预测,命中率高
UUID v4550e8400-...需要从其他端点查找 UUID
UUID v1基于时钟的 UUID可根据时间预测!提取时间戳/MAC
自有数据中的 GUID在响应中查看先从自己账户的数据中收集所有 UUID
哈希 IDmd5(user_id)尝试对顺序整数进行哈希
编码 IDbase64({"id":1001})解码 → 修改 → 重新编码
复合 ID/api/users/1/orders/5两个 ID 都可能需要分别验证

5. 水平与垂直权限提升

水平:用户 A 访问用户 B 的数据(权限级别相同)

GET /api/account/1234/statement     ← you are user 5678

垂直:低权限用户访问仅限管理员使用的功能

POST /api/admin/users/delete        ← normal user calling admin endpoint
GET /api/admin/all-users
PUT /api/users/1234/role {"role":"admin"}

组合:可导致权限提升的低权限 IDOR

GET /api/v1/users/1/details → read admin user's auth token

6. HTTP 方法升级

当 GET /resource/1234 受到正确限制时,测试所有其他动词:

GET    /api/v1/users/UserA_ID    ← might be blocked
POST   /api/v1/users/UserA_ID    ← different code path, might not check authz
PUT    /api/v1/users/UserA_ID    ← update another user's data
DELETE /api/v1/users/UserA_ID    ← delete another user's account
PATCH  /api/v1/users/UserA_ID    ← partial update (often missed in authz checks)

原理:授权逻辑通常按方法分别实现,开发人员容易遗漏边缘情况。


7. 参数污染与类型混淆

验证 id=1234 时,尝试:

id[]=1234&id[]=5678          ← array — app may use first or last
id=5678&id=1234              ← duplicate — app may prefer first or last
{"id": "1234"}               ← string vs int: might hit different code path
{"id": [1234]}               ← array in JSON
{"userId": 1234, "id": 5678} ← two ID fields — which is used for authz?

JSON 类型混淆:

{"userId": "1234"}   vs   {"userId": 1234}

某些 ORM 在查询中对字符串和整数的处理方式不同。


8. BFLA(功能级授权)攻击

常见的 BFLA 测试端点
# User management (admin-only in design):
GET /api/v1/admin/users
DELETE /api/v1/users/{any_user_id}
PUT /api/v1/users/{user_id}/role

# Bulk operations:
POST /api/v1/users/bulk-delete
GET /api/v1/export/all-data

# Billing/payment admin:
POST /api/v1/admin/subscription/modify
GET /api/v1/admin/payments/all

# Internal reporting:
GET /api/v1/reports/all-users-activity
如何查找隐藏的管理员端点
  1. 阅读 JS bundle——管理员路由通常会暴露在前端代码中
  2. 查看 API 文档(Swagger/OpenAPI),寻找标有“admin”“internal”“privileged”的标签
  3. 枚举 /api/v1/admin/**、/api/v1/manage/**、/api/v1/internal/**
  4. 在 API 基础路径上使用 Burp 的“Discover Content”
  5. 如果有相关文档,对比普通用户文档与管理员部分的文档

9. 间接 IDOR(引用链)

应用检查了对象 A的权限,却没有检查被引用对象 B的所有权:

示例:

UserA has permission to read their own messages.
GET /api/messages/1234 → checks: "does user own message 1234?" ✓

But: messages have attachments.
GET /api/attachments/5678 → doesn't check: "does attachment belong to message owned by user?"

测试:不经过父端点,直接通过附件/子资源的 ID 访问它们。

GraphQL 变体:内联查询相关对象,而不单独进行授权:

query {
  myProfile {
    followers {
      privateEmail    ← accessing private field of OTHER users via relationship
    }
  }
}

10. 批量赋值 → 权限提升

当 POST/PUT 接受 JSON 请求体时,即使官方 API 文档中没有列出底层模型的属性,也可能可以设置这些属性:

POST /api/v1/register
{
  "username": "attacker",
  "email": "[email protected]",
  "password": "password",
  "role": "admin",          ← hidden field
  "isAdmin": true,          ← hidden field
  "verified": true,         ← skip email verification
  "creditBalance": 9999     ← give self credits
}

如何查找隐藏字段:

  1. 拦截管理员“创建用户”与普通“注册”请求,对比字段差异
  2. 阅读 API 文档,查找所有可能的字段
  3. 如果有源代码,检查源代码(GitHub、JS bundle)
  4. 使用 Burp 进行模糊测试:添加常见属性名称,检查响应是 200 还是 400

11. 滥用状态机(业务逻辑 IDOR)

当资源具有状态/状态值时:

order.status: pending → confirmed → shipped → delivered

测试:能否跳过状态?

PUT /api/orders/1234 {"status": "delivered"}  ← from "pending"
PUT /api/orders/1234 {"status": "refunded"}   ← from "pending" (skip shipped)

能否设置其他用户订单的状态?

PUT /api/orders/UserA_order_id {"status": "cancelled"}  ← as UserB

12. IDOR 快速检查清单

□ Create 2 accounts (UserA + UserB)
□ Map all API calls that contain object IDs (Burp History export filter)
□ Test all HTTP verbs on each endpoint
□ Test ID in all locations: path, body, header, query, cookie
□ Try sequential IDs (−1, +1 from your own)
□ Try UUIDs/GUIDs collected from your own account data
□ Test sub-resources (attachments, comments, transactions)
□ Test admin endpoints directly (BFLA)
□ Test POST/PUT body for extra fields (mass assignment)
□ Compare JSON response field count vs documented fields (hidden fields)
□ Test state/status field modification

13. 系统性 IDOR 测试——8 个类别

#类别测试方法
1直接引用 ID更改 URL 中的数字 ID/UUID:/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. Create two test accounts (A and B)
2. Perform all CRUD operations as A, capture all request IDs
3. Replay each request replacing A's IDs with B's IDs
4. Check: Can A read B's data? Modify? Delete?
5. Test with: numeric IDs, UUIDs, slugs, encoded values
6. Test across: URL path, query params, JSON body, headers

14. ORM 筛选链泄露

Django ORM 筛选器注入
# Vulnerable: User.objects.filter(**request.data)
# Attacker sends: {"password__startswith": "a"}
# Django translates to: WHERE password LIKE 'a%'

# Character-by-character extraction:
POST /api/users/
{"username": "admin", "password__startswith": "a"}   → 200 (match)
{"username": "admin", "password__startswith": "b"}   → 404 (no match)
# Iterate through charset for each position

# Relational traversal:
{"author__user__password__startswith": "a"}
# Traverses: Author → User → password field

# On MySQL: ReDoS via regex
{"email__regex": "^(a+)+$"}  → CPU spike if match exists
Prisma 筛选器注入
// Vulnerable: prisma.user.findMany({ where: req.body })
// Attacker sends nested include/select:
{
  "include": {
    "posts": {
      "include": {
        "author": {
          "select": {"password": true}
        }
      }
    }
  }
}
// Leaks password field through relation traversal
Ransack(Ruby on Rails)
# Ransack allows search predicates via query params:
GET /users?q[password_cont]=admin
# Searches: WHERE password LIKE '%admin%'

# Character extraction:
GET /users?q[password_start]=a   → count results
GET /users?q[password_start]=ab  → narrow down
# Tool: plormber (automated Ransack extraction)

评论

支持 Markdown