# Sqli

> SQL 注入测试技能 —— 面向真实业务系统，覆盖参数边界、布尔/时间盲注、WAF 绕过与误报规避，产出可复现 PoC 与证据链

- Skill: `cdxiaodong/sqli` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cdxiaodong/sqli`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cdxiaodong/sqli/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: cdxiaodong (https://skillmd.com/u/cdxiaodong)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cdxiaodong/sqli

---


# SQL 注入测试技能（SQLi）

> 定位：面向**真实授权业务系统**的注入验证，不是 CTF writeup 的 payload 罗列。重点在「参数边界判定、注入点定位、响应差异建模、误报排除」，而非追求一个 flag。

## 触发条件

满足以下任一信号即应进入本技能（侦察阶段产出 `endpoints.json` 已标注候选注入点优先级）：

- 端点存在用户可控的查询参数（`id` / `q` / `search` / `sort` / 分页 `page` / `offset` / 筛选器 `filter`），且响应体随参数值语义变化（列表条数、字段、排序顺序）。
- HTTP 头部带结构化参数：`Cookie` 中的会话/偏好字段、`X-Forwarded-For`、`Referer`、`User-Agent`（后端记日志时常拼入 SQL）。
- JSON / XML / GraphQL 请求体存在嵌套字段，后端 ORM 层将其展开为查询条件（ORM 不等于安全，`order_by` / `group_by` 字段名注入、`raw()` / `extra()` 逃逸是高发点）。
- 二阶注入信号：注册/评论/个人资料页写入的值，在另一查询场景（如后台统计、导出）被拼入 SQL 但前端不可见——需结合 `assets.json` 的数据流追踪判断是否值得测。
- 错误回吞但响应可观测差异：同一参数，传入合法值与非法值（超大整数、非预期字符）时，响应大小/耗时/字段集合出现稳定可复现差异。

## 三层测试模型

> 对齐 DESIGN §3.1：L1 探测（快速排除明显不存在）→ L2 验证（确立可复现差异）→ L3 绕过（对抗真实 WAF / 风控）。每层只做上一层成立后才推进的事，避免对每个参数都跑完整 payload 表烧 token。

### L1 探测

目标：用最小请求量判定「该参数是否可能受 SQL 语法影响」，不追求确认漏洞。

- 布尔语义探针：对同一参数分别传 `真值基准` 与 `AND 1=1` / `AND 1=2`（数字型）或 `' AND '1'='1` / `' AND '1'='2`（字符型），比较响应指纹（状态码、Content-Length、关键 DOM 节点数、耗时）。
- 时间探针：对疑似盲注参数传 `; WAITFOR DELAY '0:0:3' --`（MSSQL）/ `AND SLEEP(3)`（MySQL）/ `pg_sleep(3)`（PG）/ `DBMS_PIPE.RECEIVE_MESSAGE('a',3)`（Oracle），以**响应延迟相对基准的稳定偏移**（非单次抖动）为信号。
- 语法错误探针：传 `'` / `"` / `)` / `\` 单字符，观察是否触发数据库原生错误回显、HTTP 500、或响应结构塌缩（ORM 异常常表现为 500 + 框架默认错误页）。
- 边界类型混淆：数字参数传字母串、字符串参数传超大数字、JSON 字段传数组/对象——ORM 反序列化失败有时会泄露底层 SQL 片段。

> L1 的产出是「候选参数 + 初判数据库指纹 + 注入类型假设」，写入 `findings.json` 的 `hypothesis` 字段，不直接定级。

### L2 验证

目标：把 L1 假设变成**可复现、可向他人演示**的差异证据，禁止仅凭响应码或单次延迟下结论。

- 布尔盲注建立稳定基线：重复 N 次（≥3）取「真条件响应」与「假条件响应」的指纹差，确认差异在去掉网络抖动后稳定存在；记录两组完整请求/响应（脱敏后）。
- 时间盲注建立统计：连续发 K 次（≥5）延迟探针 + K 次基准请求，用延迟分布（中位数而非单点）判定是否触发 `sleep`；单次 3s 不能定论（GC、慢查询同样造成延迟）。
- 联合查询/报错注入：若 L1 暴露回显或报错，用 `ORDER BY n` 二分定位列数，再取可见回显列；报错型优先用函数回显（如 MySQL `updatexml` / PG `CAST` 异常 / MSSQL `convert`），避免堆叠多请求。
- 数据库指纹收口：联合查询确定列数 + 版本函数（`@@version` / `version()` / `banner from v$version`）一起取，把「假设的库」收敛为「确认的库」，定级与后续 payload 都依赖它。

### L3 绕过

目标：在目标存在 WAF / 风控 / 输入过滤时，验证注入是否仍可达——这才是实战与靶场的分水岭。

- 关键字过滤识别：逐个传 `SELECT` / `UNION` / `AND` / 空格 / 注释符，记录哪些被拦截（403 / WAF 页 / 静默丢弃），建立「过滤面」清单，而非盲目堆 payload 字典。
- 编码与变形：对被拦关键字尝试大小写混写、内联注释 `/**/`、URL 双重编码、`%0b` 等空白替代、等价函数（`SUBSTRING`↔`MID`、`ASCII`↔`ORD`）；变形以「绕过该特定 WAF」为目标，逐个验证而非组合爆破。
- 语义等价改写：`AND` 被禁用 `&&` / `BETWEEN`；空格被禁用括号语法 `UNION(SELECT...)`；引号被转义时尝试宽字节（GBK 场景 `%bf%27`）或 `CHAR()` 构造。
- 风控对抗：控制单 IP 请求频率、轮换行为正常的请求伪装成业务流（先访问首页再发探针）、避免在风控采样窗口内集中触发——目标是「证明在真实对抗环境下注入仍可达」，不是触发风控封禁。

> L3 成立是定级上调的依据（绕过防护 = 利用链真实可达），但产出仍须 PoC + 证据，不得凭「能绕过」直接定级。

## 证据要求

什么才算确认 SQLi（缺一不可，禁止仅凭响应码/单次现象下结论）：

1. **可复现**：同一 PoC 在去掉抖动后重复执行（≥3 次）稳定复现差异或回显，记录每次的请求与响应指纹。
2. **对照基线**：提供「注入 payload」与「等价无注入基准」的成对请求/响应（如 `id=1` vs `id=1 AND 1=2`），证明差异由 SQL 语义而非业务逻辑引起。
3. **数据库确证**：至少一条证据指向具体数据库与版本（版本函数回显、报错中的方言特征、`information_schema` / `sysobjects` 可访问性），避免「疑似注入」的模糊定级。
4. **影响说明**：注明该注入可读取/篡改的具体数据边界（当前库、跨库、是否 DBA 权限、是否可写文件/执行命令），基于已确认的权限而非假设。
5. **证据脱敏**：响应中出现的真实用户数据、业务记录只记录结构与条数，不落明文；发现的凭证样式字符串（连接串里的口令等）只存哈希。

## 禁止事项

- **仅授权目标**：本技能只在 `scope.yaml` `in_scope` 且有书面授权的目标上运行；ScopeGuardHook 拦截即停，不尝试旁路自身防护。
- **不破坏数据**：不执行 `DROP` / `UPDATE` / `DELETE` / `INSERT` / 写文件 / 执行系统命令等破坏性或持久化操作——证明可读性已足以定级，写操作不提供额外安全价值且违反只读原则。
- **凭证不落明文**：响应或数据库内容中出现的口令、Token、连接串，证据里只记录哈希与类型，原文不入 `findings.json` / 日志 / 报告。
- **不超范围扩张**：发现的注入点只能用于确认该参数的漏洞边界，不得据此横向探测 scope 外资产或枚举库表以外的系统信息。
- **不依赖错误回显作为唯一证据**：错误回吞是常态，能确认就别只靠报错型；报错证据须与盲注证据至少二选一可独立成立。

