---
name: web-vuln-hunting-playbook
description: Hunt web vulnerabilities on authorized targets and archive each confirmed finding as a structured dossier. Use when the user asks for 渗透测试, 找漏洞, 漏洞挖掘, WAF bypass, or to continue hunting on a site. Do not use without authorization.
---

# Web 漏洞挖掘与档案化作业手册

这是从实战中沉淀的作业流程，不是知识点罗列。目标有两个，缺一不可：
1. **真的找到并证实漏洞**（可复现、可取证、能排除误判）；
2. **把每个结论落成可交给开发修的档案**（一漏洞一文件夹、索引同步、副作用登记）。

聊天里说得再热闹，没落盘就等于没做。

---

## 0. 开工前（不做完不要动手）

| 检查 | 动作 |
|---|---|
| 授权 | 确认目标归属、测试时间窗、允许的强度。没有授权只做被动信息收集 |
| 红线 | 不删库、不改配置、不批量爆破、不写入持久化后门。上传/写文件仅在用户明确要求且限定"最小证明"时做，做完必须删 |
| 账号 | 优先要测试账号；没有就用自己注册的低权账号。**绝不用真实用户账号做破坏性操作** |
| 记录 | 开工即建档案目录骨架（见第 6 节），边测边写，不要事后补 |
| 环境 | 记录本机时间与目标时区差；后面写"发现时间"要用目标侧时间 |
| 工具 | **sqlmap 在 `x:\漏洞库\tools\sqlmap`**（入口 `sqlmap.py`，需 Python 3.9+）。只用于"确认注入 + 最小取数"，用法与红线见 `references/sqlmap-usage.md`，包装器 `scripts/sqlmap-safe.ps1` |

---

## 1. 工作循环

```
指纹 → 攻击面清点 → 选假设 → 最小验证 → 取证 → 归档 → 清理 → 换面
```

- **一次只验证一个假设**。同时改三个变量，出了结果也说不清是谁的功劳。
- **同一方向连续失败 3 次就换面**。不要在一个点上反复刷同一句话，那是浪费。
- **每次验证都要有"对照组"**：正常值 → 异常值 → 恢复值。只有异常能重复出现，才算数。
- 优先级排序：**不用登录 > 弱登录 > 需要高权**；**能直接读数据 > 只能探测**；**影响面大 > 单点**。

---

## 2. 攻击面清点（先列全，再挑）

按层扫一遍，别只盯着 URL 参数——实战里最容易漏的是 Cookie 和 Header。

| 层 | 要看什么 |
|---|---|
| 入口 | 所有 `.aspx/.php/.ashx/.jsp/.do`、`/api/*`、`*.json`、上传点、导入导出、回调、webhook、旧版路径 |
| 参数 | URL query、POST body、**Cookie**、自定义 Header（`X-Forwarded-For`、`Referer`、`User-Agent`）、多值参数、数组参数 |
| 身份 | 登录/注册/找回/改密、验证码、第三方 OAuth、Session 与 Token 的生成与校验、Cookie 是否可伪造 |
| 数据流 | 输入 → 存储 → 渲染（存储型 XSS/注入）、输入 → 拼接 SQL、输入 → 文件路径、输入 → 外部请求（SSRF）、输入 → 命令/模板 |
| 输出点 | 页面、接口 JSON、错误页、邮件/短信、后台列表、导出文件、日志 |
| 权限 | 前台/后台、普通/管理员，**菜单隐藏 ≠ 页面鉴权**（直接改 URL 逐页点一遍） |
| 基础设施 | WAF（SafeDog/CF/ModSecurity）、CDN 与源站 IP、缓存策略、子域、端口、备份与 `.git`、`robots.txt` |

**双通道原则**：任何"用户可控值"都要问一句——它进 SQL 了吗？它进 HTML 了吗？它进文件路径了吗？它发起了外部请求吗？四条都问一遍。

---

## 3. 各技术栈的快速判定

指纹决定打法。先花 5 分钟认清栈，能省 2 小时弯路。

| 线索 | 判定 | 优先打 |
|---|---|---|
| `X-AspNet-Version`、`.aspx`、`__VIEWSTATE`、`.ashx` | ASP.NET WebForms | ViewState MAC、`ashx` 接口、Cookie 注入、错误页、上传、后台弱口令 |
| `wp-content`、`wp-json`、`wp-login.php` | WordPress | 版本/插件枚举、用户枚举、xmlrpc、REST 未授权、插件 CVE、备份文件 |
| `PHPSESSID`、`.php`、`X-Powered-By: PHP` | PHP 通用 | LFI/`php://filter`、上传、反序列化、`.git`、`phpinfo`、错误页 |
| `JSESSIONID`、`.do/.action`、`Whitelabel Error` | Java/Spring | Actuator、Swagger、Shiro、Fastjson/Log4j2、Jolokia |
| `X-Powered-By: Express`、`connect.sid` | Node | 原型污染、SSRF、JWT 弱校验、依赖 CVE |
| `Server: nginx/apache/IIS` | 只做辅助 | 路径穿越、目录列表、大小写/尾点绕过 |

细节清单（含 WordPress 完整打法）见 `references/stack-checklists.md`。

---

## 4. 验证纪律（决定报告可信度）

### 4.1 什么叫"打成功"

必须同时满足：
1. **能复现**：换浏览器/无 Cookie/新会话，按文档步骤还能出同样结果；
2. **有对照**：正常输入不出、恶意输入才出；
3. **影响可证**：不是"页面报错"就算，要能拿到具体数据或实际执行效果。

### 4.2 必须排除的误判

| 现象 | 别急着下结论 | 正确做法 |
|---|---|---|
| 提交 URL 后返回"远程服务器错误" | 不等于 SSRF | 用**确定返回 200 的地址**复测；若结果一样，说明根本没抓你给的地址 |
| 页面回显 SQL 关键字 | 不等于注入 | 看是否只是把输入原样打印；构造 `1/0`、`'`、`1+1` 三种对照 |
| 后台菜单看不到某功能 | 不等于没权限 | 直接改 URL 访问，看是否 200 且能操作 |
| 自己的浏览器里弹了框 | 不等于 XSS 可用 | **退出登录、无 Cookie** 再来一次 |
| 修改成功提示出现 | 不等于真的落库 | 刷新页面/换会话重新读取确认 |
| 能看到别人的 ID | 不等于越权 | 用另一个账号验证能否读到他人数据 |

### 4.3 双缓存陷阱（非常容易把结论搞错）

现代站点常有**两层缓存**：CDN 边缘缓存（如 Cloudflare）+ 源站输出缓存（`cache-control: public, max-age=...`）。

- 直接访问 `/` 可能命中 CDN 的旧快照（`cf-cache-status: HIT`、`age` 很大）；
- 用 `/?r=随机数` 才能回源看到真实状态；
- 源站还有自己的 TTL（见过剩余 383 秒、3780 秒的），**后台改完前台不变是正常的**。

结论：**验证"改动是否生效"必须绕开缓存**，并把 `cache-control`、`cf-cache-status`、`age` 记进证据。

### 4.4 编码与 WAF

- 同一个 payload，URL 里被封、**Cookie 里未必封**（WAF 只按 URL 规则查是很常见的实现缺陷）；
- 分隔符差异：空格 → `/**/`、`+`、`%09`；单引号 → `%u0027`、`%ef%bc%87`（全角）；
- 经过 PowerShell/curl 的 `%u` 会被二次转义（`%25u0027`），这类载荷**必须走真实浏览器**；
- 报错信息是最快的取数通道：`CAST`/`CONVERT` 类型转换失败能把数字带进错误页。

### 4.5 边界感

- 读数据可以，**不整表拖库**；证明能力只取最小样本（1–3 行）；
- 弱口令只试公开的常见口令与已泄露哈希反查结果，不做大规模字典；
- `xp_cmdshell`、写文件、RCE 这类只做"是否可达"的判定，除非用户明确要求并限定最小证明。
- **sqlmap 只做"确认 + 最小取数"**：默认 `--batch --level=1 --risk=1 --threads=1 --delay=2`；禁止 `--dump-all`、`--sql-shell`、`--os-shell`、`--file-read/--file-write`、`--risk=3`。单表 dump 必须用户书面同意，并加 `--where` + 只取前 1–3 行。详见 `references/sqlmap-usage.md`。

---

## 5. 高价值手法（按投入产出排序）

完整手法库与可直接套用的载荷见 `references/hunting-patterns.md`。这里只列思路：

1. **Cookie/Header 注入**：多数 WAF 只看 URL。`userid=1/0`、`1+@@version` 这类先用除零/类型错误试探。
2. **错误回显取数**：把子查询结果拼进会转换失败的表达式，一次读一个值（版本、库名、表名、单行数据）。
3. **弱口令哈希反查**：拿到 `password` 哈希后，本地算常见口令的哈希去库里等值匹配，比跑字典快几个数量级。
4. **后台功能穷举**：登录后把菜单、隐藏页、`.aspx/.php` 全点一遍；很多站"菜单隐藏、页面不鉴权"。
5. **上传四重判定**：后缀白名单 → 内容校验 → 是否改名 → 是否落在可执行域。四项有一个不满足才可能 getshell，缺一项就写"不可执行"。
6. **缓存相关**：缓存键与实际内容不匹配（`/account.aspx/x.css`）→ 跨用户缓存泄露；缓存投毒 → 存储型 XSS 的放大器。
7. **内容注入面**：昵称/评论/简介等"只是文本"的地方，检查输出是否编码、外链是否 `nofollow`、页面是否可索引——这是 SEO 污染与钓鱼的入口。
8. **组合链**：单点低危 + 单点低危 = 高危。例：SQL 注入读到后台账号 → 弱口令进后台 → 越权改配置 → 首页挂外链。
9. **sqlmap 自动化验证**：手工三对照出现"真/假有稳定差分"后，用 sqlmap 确认注入类型（先 `--technique=T` 或 `E` 单项测），再取最小证明。它**不会解验证码**；遇到 503/连接重置立刻停；跑完必须能用一条 `curl` 手工复现。位置、参数与红线见 `references/sqlmap-usage.md`，也可用 `scripts/sqlmap-safe.ps1` 一键带安全默认值。

---

## 6. 档案化（硬性规范，照抄）

### 6.1 目录

```
漏洞档案/
├── README.md                      # 规范 + 索引表 + 变更记录
├── 附录-已测试未发现问题.md        # 排除项，避免重复劳动
├── 01-简短名称/
│   ├── README.md                  # 必备
│   ├── payload/                   # 必备，至少一个可复现载荷/脚本
│   └── evidence/                  # 证据：响应片段、截图、抓包
├── 02-...
```

- 目录名 `NN-简短名称`，`NN` 从 01 递增，**不跳号、不复用**；
- 一漏洞一文件夹，**不允许只在聊天里说**。

### 6.2 README 必备章节（顺序固定）

1. 基本信息（编号 / 等级 / 状态 / 发现时间 / 影响地址 / 前置条件）
2. 一句话结论（外行能看懂）
3. 影响范围
4. 攻击手法与复现（可直接粘贴的请求、参数、载荷）
5. 危害说明（对业务、对用户分开写）
6. 判定标准（怎么算成功、怎么排除误判）
7. 证据（请求/响应、关键响应头、执行结果、截图）
8. 修复建议（按优先级）
9. 修复验证方法（改完之后怎么验）
10. 备注与限制（哪些没测、为什么没测）

枚举值固定：状态 = `已确认` / `待验证` / `已修复` / `误报` / `已接受风险`；等级 = `严重` / `高危` / `中危` / `低危` / `信息`。

模板见 `references/report-template.md`，骨架可用 `scripts/new-finding.ps1` 生成。

### 6.3 每轮结束必做

1. 更新根 `README.md` 的**索引表**（加一行）与**变更记录**（加一条，写清"新增/升级/更正/撤回"）；
2. 不成立的项写进**附录**（含测了什么、为什么排除），下次不用重测；
3. **副作用登记**：测试产生的评论/文章/上传文件/缓存污染/积分变动，逐条登记 + 清理状态；
4. **PII 脱敏**：手机号 `166****7271`、邮箱 `a***@x.com`；原始值只留在本地 `evidence/`；
5. 事实修正：发现之前的判断错了，**在文档里明确写"更正/撤回"**，不要偷偷改掉。

### 6.4 清理

- 测试数据能删就删，并在档案里写"已删除 + 复核方式 + 复核结果"；
- 删除能力本身要验证：**后台"删除"按钮可能是坏的**（实测过整页返回字节完全一致、什么都没删的情况）；
- 删不掉就写清"残留物 + 精确清理条件"（如 `content=... and addtime=... and user_id=...`），交给运维；
- 收尾：退出所有会话、清测试 Cookie、删本地临时文件（验证码截图、整页截图、抓包文件）。

---

## 7. 定级参考

| 等级 | 判定 |
|---|---|
| 严重 | 未授权即可读取大规模敏感数据 / 直接控制后台 / 可执行代码 |
| 高危 | 需要低门槛（任意注册账号、单一弱口令）即可造成数据泄露或持久化影响 |
| 中危 | 需要较高权限或前置条件；或影响面有限但确实可被滥用 |
| 低危 | 信息泄露、缺少防护头、单点业务逻辑缺陷 |
| 信息 | 仅提示，无直接危害 |

组合链的定级要写清楚："单点中危，与 XX 号组合即为未授权控制首页"。

---

## 8. 常见坑（都是踩过的）

1. **登录态自嗨**：所有 XSS/越权结论都要在**退出登录后**复验一次。
2. **只测 URL 参数**：Cookie、Header 往往不经过 WAF，是真正的入口。
3. **被缓存骗**：后台改完前台不变，先看 `cf-cache-status` 与 `Cache-Control`，别急着说"没生效"。
4. **把报错当漏洞**：先确认报错里有没有你能控制/读取的数据。
5. **忽略 SameSite**：跨站 CSRF 在现代浏览器常被 `SameSite=Lax` 挡死，能打通的是**同站**（子域）投递。
6. **旧前端库让修复失效**：jQuery 2.x 的原型污染会让"先转义再 `.html()`"重新变成 XSS。
7. **后台渲染也要看**：后台列表把用户昵称当 HTML 渲染，管理员在后台点到就中招。
8. **验证码环节**：OCR/人工识别成本高，优先走"不需要验证码"的接口；必须过时，先确认验证码是否与 Session 绑定。
9. **删除不等于删掉**：逻辑删除、缓存残留、CDN 快照都会让"我删了"变成假象，必须换会话/绕缓存复核。
10. **文档拖延**：当场写，10 分钟；事后补，1 小时还漏细节。
11. **迷信 sqlmap**：500 ≠ 注入。WAF 拦截页、验证码错误页、登录重定向都会让 sqlmap 误报或全漏；先手工
    四对照（正常/单引号/`AND 1=1`/`AND 1=2`），有稳定差分再上工具。它说 vulnerable 也必须用 `curl` 复现一次才算数。

---

## 9. 交付自检（每次收工前过一遍）

- [ ] 每个结论都有"可复现的最小步骤"，不依赖我的浏览器状态
- [ ] 每个结论都在**匿名/无 Cookie** 下复验过（XSS、越权、外链类必做）
- [ ] 误判项已写进附录，并说明排除依据
- [ ] 用过 sqlmap 的话：只跑了判定/最小取数，**没有** `--dump-all`/`--os-shell`/`--file-read`/`--risk=3`；最终 payload 已用 `curl` 手工复现并归档到 `payload/`
- [ ] 一漏洞一文件夹，README 十章节齐全，`payload/` 有东西
- [ ] 根索引 + 变更记录已更新
- [ ] 副作用登记完整，清理结果有复核
- [ ] PII 已脱敏
- [ ] 会话已退出、Cookie 已清、本地临时文件已删
- [ ] 留了"下一步还能打哪"的一句话（给下一轮）
