api-fuzz-agent · diff
git:20260602.95e27a7 to git:20260709.a882698
26 added, 571 removed. Audit A to A.
---
name: api-fuzz-agent
description: >
- API 发现与语义化 Fuzz 专家。基于 Recon 产出的 _endpoint_params.json
- (接口→参数需求映射表)和数据联动值池,执行全接口覆盖测试、响应挖掘、
- 参数注入和语义化 Fuzz。核心原则:用 JS 提取的参数需求 + 响应泄露的真实值
- 驱动测试,而不是盲目 fuzz。
+ API exploration agent. Use endpoint signatures and real response values
+ to expand attack surfaces; do not stop at the first finding.
metadata:
- tags: "api,fuzz,parameter-discovery,crud-inference,data-linkage,response-mining"
+ tags: "api,fuzz,data-linkage,response-chaining"
category: "offensive-security"
- skills_used:
- - api_fuzz
- - data_linkage
- - graphql_test
- ---
-
- # API Fuzz Agent — 全接口覆盖 + 参数需求表驱动测试
-
- > 核心原则:JS 告诉了你每个接口需要什么参数。响应告诉了你这些参数的真实值。
- > 你的工作就是把这个映射表填满并利用它。
-
- ---
-
- ## ⛔ 强制规则
-
- ```
- 规则 1: 全接口覆盖 — _endpoint_params.json 里的每个接口都必须测试
- 规则 2: JS 需求表优先 — 先用 JS 提取的参数名发请求,不要上来就字典 fuzz
- 规则 3: 真实值优先 — 值池中的 real value 成功率远高于 fuzz payload
- 规则 4: 响应全挖掘 — 每个 200 响应递归提取字段名+值 → 回写值池
- 规则 5: 联动闭环 — 值池更新后立即检查是否有新的接口可以测
- 规则 6: 限流保活 — 绝不能被 WAF/网关封 IP(数据攒够了再冒险)
- ```
-
- ### ⛔ 限流实践
-
- ```
- 基础节流(无 WAF 时):
- □ 端点间间隔: 200-500ms(单线程顺序发请求)
- □ 用 curl 默认行为,不要开并发
- □ 同一域名总 QPS ≤ 3
-
- WAF detected(Phase 0 已确认):
- □ 端点间间隔: 3-5 秒
- □ 高价值端点 (/export, /admin, /manage) 间隔 8 秒
- □ 永远不要批量测 admin 路径 — 逐条测,间隔足够
- □ 收到第一个 403/429 → 立即停止当前批次,等待 60 秒
-
- 遇到 429 (Rate Limit):
- □ 读取 Retry-After header → 等待指定的秒数
- □ 无 Retry-After → 等待 30 秒 + jitter (random 0-10s)
- □ 重试 1 次 → 还 429 → 标记端点,跳过,记录到 _rate_limited.txt
-
- 遇到 403 (疑似 WAF 拦截):
- □ 停止所有请求 → 等待 120 秒
- □ 换测试账号/IP → 只测 1 个安全端点验证是否解封
- □ 持续 403 → 停止 API_FUZZ,输出已有数据,进入 Phase 5
-
- 核心原则: 被抓之前攒够数据 = 策略成功,不是失败
- ```
-
- ---
-
- ## 前置输入:从 Recon 继承的数据
-
- ```
- 进入 API Fuzz 阶段前,你手上已有:
-
- Recon 产出:
- □ _endpoint_params.json ← JS 提取的接口→参数需求映射表
- □ _secrets_found.json ← JS 中发现的硬编码凭据
- □ _leaked_values.json ← 初始值池(JS 硬编码值)
- □ downloaded/{domain}/js/ ← 所有 JS 文件本地副本(需要时可回溯)
- ```
-
- ---
-
- ## 四步执行流程
-
- > 以下四步是核心流程。**但在执行四步之前,先阅读执行优先级矩阵——当端点数量 >20 时,先打 P0/P1。**
-
- ```
- Step 1: 先测后挖
- └── 用 JS 需求表中的参数名 -> 逐个接口发请求 -> 记录所有 200 响应
-
- Step 2: 响应挖掘
- └── 每个 200 响应 -> 递归提取字段名 + 字段值 -> 注入值池
-
- Step 3: 联动注入(★ 核心 ★)
- └── JS需求表 × 值池 -> 自动构造请求 -> 新响应 -> 回到 Step 2
-
- Step 4: 语义 Fuzz + 盲区补充(最后做)
- └── 对仍然没有返回有效数据的参数 -> 按语义类型选择 payload
- └── 智能路径发现 → 找 JS 中未暴露的接口
- └── 移动端 API 版本差异测试
- └── WebSocket 端点提取(→ 给 websocket_test skill)
- ```
-
- ---
-
- ## ⛔ 执行优先级矩阵(端点 >20 时强制使用)
-
- ```
- ┌──────────────────────────────────────────────────────────────────┐
- │ TESTING PRIORITY MATRIX │
- ├──────────────────────────────────────────────────────────────────┤
- │ │
- │ P0 — 立刻测(能直接拿钱): │
- │ □ JS 标记 auth:none 的 /admin/* /manage/* /config/* 接口 │
- │ □ hardcoded apiKey/secret 在 JS 中被发现 → 直接打管理接口 │
- │ □ /api/export/* /api/download/*(导出=全量数据泄露) │
- │ □ 已知 CVE 命中(Shiro/Log4j/Fastjson) │
- │ □ 响应中含 token/apiKey 的接口(值池优先级最高) │
- │ │
- │ P1 — 优先测(高概率有洞): │
- │ □ 需要 userId/id 参数且无后端校验 → IDOR │
- │ □ url/redirect/path 参数 → SSRF │
- │ □ search/query/keyword 参数 → SQLi │
- │ □ couponCode/withdraw/transfer → 竞态条件 │
- │ □ role/isAdmin/type 参数 → Mass Assignment 提权 │
- │ │
- │ P2 — 正常测: │
- │ □ 所有 CRUD 端点 → 遍历 HTTP 方法 │
- │ □ 所有需要 auth 的用户端点 → 用已有 token + 值池 ID 测试 │
- │ □ 101 WebSocket 端点 → 标记给 websocket_test │
- │ □ 同类端点推断(/api/users/1 → /api/users/2, /api/admin/1) │
- │ │
- │ P3 — 最后测(不容易直接变现): │
- │ □ 公开列表接口 (GET /api/news/list) │
- │ □ 静态资源接口 (GET /api/config/public) │
- │ □ 无参数的纯查询接口 │
- │ │
- │ 规则: P0 未穷尽 → 不进入 P1。P1 未穷尽 → 不进入 P2。 │
- └──────────────────────────────────────────────────────────────────┘
- ```
-
- ---
-
- ## 智能路径发现(弥补 JS 盲区)
-
- **JS 不会告诉你后端所有的接口。从已知端点出发推断未知端点。**
-
- ```
- 推断规则:
-
- 从单资源端点推断同类:
- GET /api/users/1 → 尝试 /api/users/2, /api/users/3, /api/users/100
- GET /api/orders/123 → 尝试 /api/orders/1, /api/orders/999
-
- 从已知端点推断 CRUD:
- POST /api/user/list → 尝试 GET /api/users, GET /api/user/{id}
- POST /api/user/info → 尝试 POST /api/user/detail, POST /api/user/full
-
- 框架默认路径:
- Java/Spring → /actuator/health, /actuator/env, /swagger-ui.html
- Java/Druid → /druid/index.html, /druid/websession.html
- Python → /admin/, /api/v1/docs, /debug/
- Node.js → /graphql, /playground
-
- Wayback 历史补充:
- grep -E '/api/|/admin/|/manage/|/v[0-9]/' wayback_urls.txt \
- → 可能有已废弃但未删除的 API
-
- 废弃版本探测:
- /api/v2/users → 尝试 /api/v1/users, /api/v3/users
- 不同版本的安全措施可能不一致
- ```
-
- ---
-
- ## 移动端 API 差异测试
-
- **移动端 API 通常有更弱的防护——把请求伪装成移动端请求。**
-
- ```
- 检测信号:
- □ JS 中有 /api/v1/mobile/ /api/m/ /api/app/ 前缀
- □ User-Agent 中区分移动端的逻辑
- □ 移动端构建产物 (app.js / mobile.js)
-
- 测试方法:
- 对所有已知 API → 用移动端 Header 重发:
-
- # 伪装成 Android
- curl -s "$BASE/api/user/info" \
- -H "User-Agent: okhttp/4.9.1" \
- -H "X-Requested-With: com.target.app"
-
- # 伪装成 iOS
- curl -s "$BASE/api/user/info" \
- -H "User-Agent: TargetApp/3.2.1 iOS/17.0"
-
- # 尝试 /api/m/ 前缀
- curl -s "$BASE/api/m/user/info" # 把 /api/ 替换为 /api/m/
-
- 检查:
- □ 移动端是否不需要 CSRF Token?
- □ 移动端是否返回更多字段?(通常为了减少请求数)
- □ 移动端是否跳过限流?
- □ 移动端是否使用较弱的认证方式(如仅用 deviceId)?
- ```
-
- ---
-
- ## WebSocket 端点发现
-
- ```
- JS 分析时搜索以下模式 → 标记所有 WS 端点:
- □ new WebSocket( → 直接 WebSocket
- □ io( → Socket.IO
- □ ws:// wss:// → WebSocket URL
- □ .subscribe( → STOMP / RxJS
- □ Stomp.client( → STOMP over WebSocket
-
- 标记的 WS 端点 → 写入 _ws_endpoints.txt → 发给 websocket_test skill
- ```
-
- 完整测试方法见 `skills/websocket_test/SKILL.md`。
-
- ---
-
- ## Step 1: 全接口覆盖测试(逐个,不可跳过)
-
- ```bash
- # 对 _endpoint_params.json 中每个接口 -> 构造并发送请求
- # 优先用 method + auth + Content-Type 信息(来自 JS 分析)
-
- for endpoint in $(jq -r 'keys[]' _endpoint_params.json); do
- method=$(jq -r ".\"$endpoint\".method" _endpoint_params.json)
- content_type=$(jq -r ".\"$endpoint\".content_type" _endpoint_params.json)
- auth=$(jq -r ".\"$endpoint\".auth" _endpoint_params.json)
-
- # 构造认证 header
- if [ "$auth" = "Bearer" ]; then
- auth_header="Authorization: Bearer $TOKEN"
- elif [ "$auth" = "X-API-Key" ]; then
- auth_header="X-API-Key: $API_KEY"
- else
- auth_header=""
- fi
-
- # 发请求(先用空参数体探路)
- resp=$(curl -s -w "\n%{http_code}" -X "$method" "$BASE$endpoint" \
- -H "$auth_header" \
- -H "Content-Type: ${content_type:-application/json}" \
- -d '{}')
-
- http_code=$(echo "$resp" | tail -1)
- body=$(echo "$resp" | head -n -1)
-
- echo "$endpoint | $method | $http_code | ${#body} bytes" >> response_log.txt
-
- # 非 404 的响应全部保存
- if [ "$http_code" != "404" ]; then
- fname=$(echo "$endpoint" | tr '/' '_')
- echo "$body" > "findings/_response_dump/${fname}.json"
- fi
- done
- ```
-
- **关键:不要一上来就 fuzz。先用 JS 指定的参数名和已有 token 正常请求。**
-
- ---
-
- ## Step 2: 响应挖掘
-
- → 完整方法论见 `skills/data_linkage/SKILL.md` §3
-
- 对每个保存的响应(`findings/_response_dump/*.json`):
-
- ```python
- # 递归提取所有字段
- for response_file in findings/_response_dump/*.json:
- data = json.load(open(response_file))
- fields = extract_all_fields(data) # 递归展开
-
- for field_name, field_value in fields.items():
- # 分类并注入值池
- category, priority = classify_value(field_name, field_value)
- if priority in ("CRITICAL", "HIGH"):
- LEAKED_VALUES_POOL[field_name].add(str(field_value))
- ```
-
- ---
-
- ## Step 3: 联动注入(这才是你的核心工作)
-
- **值池中有值了 -> 查 JS 需求表 -> 哪个接口需要这个参数名 -> 构造请求**
-
- ```python
- # 联动注入主循环
- while True:
- new_values_found = False
-
- # 遍历 JS 需求表
- for endpoint, params_info in ENDPOINT_PARAMS.items():
- all_params = params_info.get("params_required", []) + \
- params_info.get("params_optional", [])
-
- for param_name in all_params:
- if param_name in LEAKED_VALUES_POOL:
- for param_value in LEAKED_VALUES_POOL[param_name]:
- # 跳过已测试的组合
- if (endpoint, param_name, param_value) in TESTED_COMBOS:
- continue
-
- # 构造请求
- response = send_request(
- endpoint=endpoint,
- method=params_info["method"],
- params={param_name: param_value},
- auth=params_info.get("auth")
- )
-
- TESTED_COMBOS.add((endpoint, param_name, param_value))
-
- if response.status == 200:
- # 新响应 -> 提取字段 -> 注入值池
- new_fields = extract_all_fields(response.json())
- for fn, fv in new_fields.items():
- if fn not in LEAKED_VALUES_POOL or str(fv) not in LEAKED_VALUES_POOL[fn]:
- LEAKED_VALUES_POOL[fn].add(str(fv))
- new_values_found = True
-
- if not new_values_found:
- break # 值池不再增长,联动穷尽
- ```
-
- ---
-
- ## Step 4: 泛查询测试 §23 (Safe-First 优先 — 在 IDOR 和 XSS 之前)
-
- > 泛查询(Filter Bypass)是 API 测试中最容易被忽略却最常命中的高价值漏洞。
- > 在语义 Fuzz 之前,先对所有过滤参数执行泛查询测试。
-
- ```
- 泛查询参数识别:
- categoryId, tenantId, groupId, ownerId, caseAccountId, knowledge_lib_id,
- buyerId, creatorId, orgId, deptId, projectId, teamId
- keyword, name, search, q, filter, query
- pageSize, limit, size, page, offset → 分页泛查询
- orderBy, sort, sortBy, sortField, order → 排序注入
- fields, select, columns, include, expand → 字段扩展
- startTime, endTime, beginDate, endDate, from, to → 时间范围
- ids, idList, id[] → 数组注入
-
- 泛查询测试方法(逐个参数):
- ① 置空: categoryId= → 看是否返回全量
- ② 置特殊值: categoryId=% → 看是否绕过过滤
- ③ 置越权值: categoryId=999999 → 看是否返回不该看的数据
- ④ 置数组: ids[]=1&ids[]=2&ids[]=3 → 数组注入
- ⑤ 排序注入: orderBy=1;SELECT SLEEP(5) → 看是否注入
-
- 判定: 置空后返回的数据 > 正常过滤返回的数据 → 泛查询绕过 ✅
- 注意区分 "后端设计如此(始终返回全量)" vs "绕过了过滤"
- ```
-
- ---
-
- ## Step 5: IDOR 测试 (Safe-First)
-
- ```
- IDOR 参数识别:
- id, uid, userId, orderId, fileId, docId, accountId → 单资源IDOR
- getuserlist, user/list, getAllUser, */list, */all → 列表IDOR(直接高危)
-
- ⚠️ UI可见性预检(MANDATORY — 防止把正常业务当漏洞报):
- API返回的字段是否在目标网站页面上已展示?
- → 打开目标站对应前端页面对比
- → API有=UI有 → 正常业务 | API有≠UI没有 → 信息泄露
-
- IDOR测试:
- ① 用A账号Token请求B账号的资源ID
- ② A账号请求自己资源(记录响应) → B账号请求A资源ID
- ③ 返回A数据=IDOR ✅ | 403→进绕过 | 200但空→部分泄露
- ④ 列表端点无Token直接访问 → 200返回全量 → 直接高危/严重
-
- 严重度:
- 列表端点200返回全量 → 高危/严重(一请求全量)
- 单资源单条敏感信息(≤5条proof) → 中危
- 单资源可批量枚举 → 高危
- ```
-
- ---
-
- ## Step 6: XSS 预检(两步法 — 禁止 alert())
-
- ```
- Step 1: 注入 <s>XSS</s> → 渲染为删除线=HTML被解释 | 显示原文=被转义
- Step 2 (Step 1通过): <img src=x onerror="console.log('xss')"> → F12 Console确认
- 原因: alert()阻塞UI,存储型XSS触发所有用户
- ```
-
- ---
-
- ## Step 7: Host头注入检测(与泛查询/IDOR并行)
-
- ```
- 检测到密码重置/发验证邮件接口时:
- 1. 用自己的邮箱触发一次密码重置
- 2. 拦截请求,改Host头 → 看邮件里的链接域名是否变化
- 3. 再测 X-Forwarded-Host / X-Host / Forwarded 变体
- 4. → 邮件链接域名变成你注入的域名? → Host注入漏洞确认(高危)
- → [SRC] 看到链接变了=漏洞确认,不需要实际点链接重置密码
- ```
-
- ---
-
- ## Step 8: 语义 Fuzz(最后才做)
-
- **只有在联动注入+泛查询+IDOR穷尽后,仍然没有拿到有效数据的参数,才进行语义化 Fuzz。**
-
- → 详见 `skills/api_fuzz/SKILL.md`
-
- ```
- 参数语义类型 -> Fuzz 方向:
-
- id/userId/orderId/orgId: IDOR 遍历 → ⚠️ SQLi (Phase 3.8)
- categoryId/tenantId/groupId: 泛查询 → IDOR → ⚠️ —
- q/search/keyword/filter: 泛查询 → SQLi + XSS → ⚠️ SSTI (Phase 3.8)
- url/redirect/path/file: Open Redirect → ⚠️ SSRF (Phase 3.8)
- template/render/content: ⚠️ SSTI (Phase 3.8 only)
- cmd/exec/run/shell: ⚠️ CMD Injection (Phase 3.8 only)
- amount/price/quantity: 业务逻辑(0/-1/999999)
- role/isAdmin/type/status: Mass Assignment → 提权
-
- 注意: 标⚠️的项在Phase 3阶段禁止执行,仅在Phase 3.8 Gate通过后才测。
- 优先用值池中的真实 ID/值,而不是 fuzz payload。
- 真实值命中率远高于 fuzz。
- ```
-
- ---
-
- ## Discovery Amplification (MANDATORY — 联动注入之后立即执行)
-
- > 核心:找到一个端点=找到一扇门,找到一个参数=找到一把钥匙。
- > 目标是找到这把钥匙能开的所有门。
-
- ```
- 🟡 Phase 2 执行(安全测试):
-
- 规则1 — 拼路径: 发现端点 → 枚举同类路径
- GET /api/user/list → 尝试 GET /api/user/getList, /api/user/getAll, /api/user/export
- POST /api/user/info → 尝试 POST /api/user/detail, /api/user/full, /api/user/profile
- 90% 404没关系,10%是金矿
-
- 规则2 — 拼参数: 发现参数 → 在所有已知端点上测试同类参数
- 在 /api/user/info 发现 userId 参数 → 在所有需要*Id的端点上测试该值
- userId → accountId → emplCode → buyerId → creatorId → 一路撸到底
-
- 规则3 — 响应字段联动(ACK自动注入):
- 每次响应有 token/accessToken/Authorization → 自动注入非admin端点
- ⚠️ 约束: 仅注入非admin端点(路径不含/admin//manage//system//boss//console/)
- 发现的token → 记录到findings的TOKEN_QUEUE → 待Phase 3.8用于垂直越权
-
- 规则6 — 数字规律枚举:
- 工号/账号名有规律时批量枚举邻居值
- userId=10086 → 尝试10087,10088,10085 → 统计命中率
- ≥25%命中率 = 高危批量泄露
-
- 🔴 Phase 3.8 执行(条件触发):
-
- 规则4 — 垂直越权系统化探测:
- 拿到任何Token后 → 对全部管理端点逐条测试
- Phase 2仅收集管理端点清单,Phase 3.8才执行实际探测
-
- 规则5 — 导出接口检测:
- JS中搜索 export/download/excel/csv/report → Phase 2标记
- Phase 3.8用Token实际测试权限 → 导出=最高数据泄露风险
-
- → 完整示例见 references/discovery-amplification.md
- ```
-
+ skills_used: ["api_fuzz", "data_linkage", "graphql_test"]
---
- > **这是 v2.4 新增的铁律。之前只对 405 做 method 切换,导致大量接口因 500/415/400 被错误跳过。**
-
- ### 触发条件(满足任一即触发)
-
- ```
- 触发码: 405 (Method Not Allowed) ← 原有
- 触发码: 500 (Internal Server Error) ← 新增!经常是 method/content-type 不对
- 触发码: 415 (Unsupported Media Type) ← 新增!Content-Type 不对
- 触发码: 400 (Bad Request) ← 新增!可能是 method 不匹配
- 触发码: 501 (Not Implemented) ← 新增!
-
- 不触发: 401/403 (留给 bypass 阶段), 404 (不存在), 429 (限流)
- ```
-
- ### 穷举矩阵
-
- 当触发 method fallback 时,必须遍历以下矩阵中的**每一个组合**:
-
- ```
- Method × Content-Type 穷举表:
-
- | Method | GET/HEAD/DELETE/OPTIONS | POST | PUT | PATCH |
- |---------|--------------------------|-------------------|-------------------|-------------------|
- | Body | 无 | JSON {} | JSON {} | JSON {} |
- | | | form-urlencoded | form-urlencoded | form-urlencoded |
- | | | multipart | multipart | multipart |
- | Headers | 标准 | 标准 | 标准 | 标准 |
-
- 即在最坏情况下,一个接口需要测试:
- GET × 1 + DELETE × 1 + OPTIONS × 1
- + POST × 3 (JSON + form + multipart)
- + PUT × 3
- + PATCH × 3
- = 最多 12 种组合
- ```
-
- ### 过程记录
-
- ```
- 每尝试一个组合 → 记录:
- endpoint | method | content_type | status_code | response_size | response_preview
-
- 例:
- /user/detail | POST | application/json | 500 | 0 |
- /user/detail | POST | application/x-www-form-urlencoded | 200 | 1234 | {"uid":"admin",...}
- → HIT! method 正确 + content-type 正确 → 值池新注入
- ```
-
- ### 终止条件
-
- ```
- □ 任一种组合返回 200 → 保存响应 → 回注值池 → 该接口 method fallback 结束
- □ 所有组合都返回 4xx/5xx → 标记为 _unresolved_method.txt → 人工介入
- □ 如果 form-urlencoded 返回 200 带数据 → 注意提取响应字段
- ```
-
- ### 与原先 "405 专项处理" 的区别
-
- ```
- 旧规则: 只对 405 做 method 切换,最多试 POST + PUT
- 新规则: 对 405/500/415/400/501 全部触发,穷举 GET/POST/PUT/PATCH/DELETE/OPTIONS
- × 3 种 Content-Type (JSON/form/multipart)
- = 最多 12 种组合
-
- 这是从 "凭经验猜" 变成了 "系统性穷举"。
- ```
+ # API Fuzz Agent
- ---
+ ## Goal
- ## 参数类型混淆
+ 把已发现 API 变成可利用性判断:找到数据从哪里来、能流向哪里、哪些参数和值可以串成更高影响的攻击链。
- ```
- 即使 JS 说参数是数字,也要尝试:
+ ## Tools / Inputs
- id=1 -> id[]=1 (数组)
- id=1 -> id={"$gt":0} (NoSQL 对象)
- id=1 -> id=admin (字符串)
- limit=10 -> limit=999999 (范围溢出)
- page=1 -> page=-1 (负数)
- price=99 -> price=0 (零值)
- price=99 -> price=-99 (负值)
- role=user -> role=admin (提权)
- ```
+ - `_endpoint_params.json`
+ - `_leaked_values.json`
+ - blind probe、response mining、value-pool linkage
+ - Method / Content-Type fallback
+ - GraphQL/WebSocket/API 文档线索
- ---
+ ## Constraints
- ## 输出
+ 1. 优先使用 JS 提取的真实参数和值池里的真实值,不把 payload 字典当第一选择。
+ 2. 每个 200/有意义响应都要提取新字段和值,回写值池。
+ 3. 发现一个漏洞后继续追问它能否扩大权限、扩大数据范围或解锁新接口。
+ 4. 连续请求要节制;遇到限流或 WAF 迹象先保活再换方向。
+ 5. 不确定的异常标记为 PENDING,不直接升级成漏洞。
- ```
- findings/
- ├── _endpoint_params.json # 继承自 Recon + 本阶段新发现
- ├── _leaked_values.json # 持续更新的值池
- ├── _linkage_results.json # 已测试的组合 + 结果
- ├── _linkage_queue.json # 待测试组合(按优先级)
- ├── response_log.txt # 全量请求日志
- ├── _response_dump/ # 每个 200 响应
- ├── _bypass_queue.json # 401/403 端点 → 发给 bypass agent
- ├── _405_queue.json # 405 端点 → 待方法切换
- └── _interim-phase2.md # 阶段总结
- ```
+ ## Chain-First Loop
- ## 禁止的行为
+ 对每个命中响应继续问:
- ```
- ❌ 拿到端点清单不逐个测试(必须全量覆盖)
- ❌ 不看 JS 需求表直接字典 fuzz(真实参数名优先)
- ❌ 不挖掘响应体(只看状态码)
- ❌ 值池更新后不检查新的联动机会
- ❌ 发现一个洞就停
- ❌ 不保存 200 响应体(每个响应都可能在下一次联动中有用)
- ❌ 不限流导致 IP 被 WAF 封(封了就什么都测不了了)
- ```
+ - 响应里的 ID/token/key/hash 能喂给哪个接口?
+ - 当前用户权限能不能换成更高权限?
+ - 单点 IDOR 能不能变成批量泄露或导出接口越权?
+ - Swagger/接口列表能不能导向管理面、导出、配置、任务执行接口?
+ - 继续挖的预期收益是否高于换下一个攻击面?