# sqlmap 使用手册（注入验证与最小取数）

> 工具位置：**`x:\漏洞库\tools\sqlmap`**（入口 `sqlmap.py`，当前 1.10.x）。
> 换机器：`git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git`，需要 Python 3.9–3.12（3.13/3.14 也能跑）。
> 自检：`python sqlmap.py --version`。
> 本机包装器：`scripts/sqlmap-safe.ps1`（自动定位 + 强制安全参数 + 拦截越界开关）。

---

## 1. 什么时候才该用 sqlmap

**先手工，后自动化。** sqlmap 不是"扫一下就知道"，它只会放大你已有的判断。

必须先做完手工三对照（见 SKILL.md 4.1/4.2），满足下面两条才值得上 sqlmap：

1. 同一参数：正常值 / 单引号 / `AND 1=1` / `AND 1=2` 四组请求，**状态码或长度有稳定差分**；
2. 差分能排除"前端校验拦截""验证码错误页""WAF 拦截页""登录重定向"这四种假象。

> 反面教材：`username=admin'` 返回 500、`username=admin` 返回 200，看着像注入；
> 但 `' AND 1=1--` 和 `' AND 1=2--` 都是 500 —— 这是**语法报错**，不是布尔注入。sqlmap 大概率误报。

---

## 2. 三种输入方式（按推荐度）

| 方式 | 适用 | 命令骨架 |
|---|---|---|
| `-r 请求文件`（**最推荐**） | 有 Cookie/Header/JSON/验证码会话 | Burp 里右键 `Copy to file`，保存为 `login.txt`，再 `-r login.txt` |
| `-u` + `--data` | 简单表单 | 见下方示例 |
| `--forms` | 纯交互式、无登录态 | 仅手动跑，脚本里别用 |

JSON 接口加 `--data='{"a":1}' --headers="Content-Type: application/json"`。

---

## 3. 安全参数（默认就用这一套）

```bash
python x:\漏洞库\tools\sqlmap\sqlmap.py ^
  -u "http://TARGET/path" ^
  --data="username=admin&password=x&checkCode=0000&returnUrl=" ^
  -p username ^
  --batch --level=1 --risk=1 --threads=1 ^
  --delay=2 --timeout=30 --retries=1 ^
  --random-agent
```

| 参数 | 作用 | 为什么必须 |
|---|---|---|
| `-p 参数名` | 只测指定参数 | 少打无关参数，少留日志 |
| `--batch` | 不交互 | 避免卡在默认选项上 |
| `--level=1` | 最小测试集 | level≥3 会测 Cookie/UA，噪音大 |
| `--risk=1` | 只读载荷 | **`--risk=3` 含 OR 型载荷，可能改数据，禁用** |
| `--threads=1` | 单线程 | 并发会打挂小站/WAF |
| `--delay=2` | 请求间隔 | 降低触发风控与封 IP 的概率 |
| `--timeout=30 --retries=1` | 快速失败 | 目标挂起时不要干等 |
| `--random-agent` | 随机 UA | 别用 sqlmap 默认 UA 送人头 |

需要 TLS 时加 `--force-ssl`；走代理加 `--proxy=http://127.0.0.1:8080`。

---

## 4. 确认注入类型（只做判定，不取数）

```bash
# 只测时间盲注，最安静
... --technique=T --time-sec=5

# 只测报错注入（前提：错误页会回显 DB 报错）
... --technique=E

# 只测布尔盲注
... --technique=B
```

输出里要抓的三行：

- `parameter 'xxx' is vulnerable` / `does not appear to be injectable`
- `back-end DBMS: ...`
- `Payload: ...`（这条要抄进档案的 payload/）

**判定纪律**：sqlmap 说 vulnerable 不算数，必须用它给的那条 payload 手工 `curl` 再打一次，结果一致才写"已确认"。

---

## 5. 取数边界（红线）

| 允许（只读元数据） | 允许（经用户书面同意） | **禁止** |
|---|---|---|
| `--current-user`、`--current-db`、`--hostname`、`--dbs`、`--tables`、`--columns` | 单表 `--dump -T 表 --where="id=1" --start=1 --stop=3`（≤3 行） | `--dump-all`、`--sql-shell`、`--os-shell`、`--os-pwn`、`--file-read`、`--file-write`、`--risk=3` |

- 证明能力只用 1–3 行；**不整表拖库**。
- 拿到 `password` 哈希后，走 SKILL.md 的"弱口令哈希反查"路线，不要对线上跑字典。
- 任何写操作、命令执行，一律先问用户，并限定"最小证明"，做完登记清理。

---

## 6. 特殊环境怎么处理

| 场景 | 处理 |
|---|---|
| **验证码** | sqlmap 不会解验证码。先手工过验证码，拿会话 Cookie 用 `--cookie="..."`；或直接找**不带验证码**的接口（App/API/老版本） |
| **验证码通过后请求挂起 60s** | 说明后端异常，**停**。此时跑时间盲注没有意义，还会压垮应用池（对应档案里的"登录挂起"条目） |
| **WAF/IPS 返回 503 或连接重置** | 立即停。换参数位置（Cookie/Header）再手工试，别让 sqlmap 连续刷 |
| **页面永远 200（软 404）** | 用 `--string`/`--not-string` 指定"成功页特征"，否则布尔判断全错 |
| **HTTPS 证书错误** | `--force-ssl`；别关校验去"绕过" |
| **目标在 CDN 后面** | 先确认回源方式；缓存会让响应不稳定，sqlmap 判定会飘 |

---

## 7. 证据归档（跑完立刻做）

```bash
... -t evidence/traffic.log --output-dir evidence/sqlmap
```

- `traffic.log`：完整请求/响应，放 `NN-xxx/evidence/`；
- `--output-dir` 下的 `log`、`session.sqlite` 一并归档（session 文件含 payload 历史）；
- 档案 README 第 4 节必须能让人**不用 sqlmap**、只靠 `curl` 复现；
- 第 10 节写清：用了哪些 technique、哪些参数没测、为什么停。

---

## 8. 常见失败原因（按出现频率）

1. **把 500 当注入**：先看带引号与布尔真/假是否同码同长。
2. **验证码页骗过 sqlmap**：所有请求都返回同一张"验证码错误"页 → 布尔判断失真。
3. **WAF 把 payload 换成拦截页**：表现为"所有 payload 长度一致"，用 `-t` 看原始流量。
4. **目标挂起**：`--timeout` 不够会误判"不可注入"，但盲目调大只会更慢。
5. **参数选错**：`-p` 指到了 `password`/`checkCode` 这类噪音字段。
6. **JSON 没带 Content-Type**：请求被当表单解析，永远 400。

---

## 9. 一句话总结

sqlmap 的定位是**"确认 + 最小取数"**，不是"一键日站"。它跑出来的每个结论，都要能用一条 `curl` 手工复现；做不到的，就写"待验证"。
