sql-injection-comprehensive

star 72

SQL 注入多策略综合检测 — 注入类型或数据库不明确时统一分诊布尔盲注/时间盲注/报错/UNION;适用于接口审计、黑盒探测与快速定级场景。

Q16G By Q16G schedule Updated 6/7/2026

name: sql-injection-comprehensive description: >- SQL 注入多策略综合检测——分诊布尔盲注 / 时间盲注 / 报错 / UNION,覆盖各主流 DBMS。 流量中参数值带引号触发响应突变、响应含数据库错误关键字、同参数二态可控、注入 SLEEP 耗时增加时使用。 when-to-use: 当存在 SQL 注入嫌疑、注入类型或数据库不明确,需要多策略分诊探测时 allowed-tools: bash,read_file,list_files,rg user-invocable: false

SQL 注入:多策略综合检测(黑盒)

1. 触发线索 / 适用信号

以下是已知的 SQLi 触发线索,作为基线起点而非必检硬清单。结合流量与响应特征动态调整:

  • 适用且已完成 → [x] done
  • 明确不适用 → [-] n/a (原因)(原因要具体到响应特征)
  • 基线未列出但实际发现 → [+] added (来源)

响应特征命中信号(漏洞-specific):

  • 单引号触发响应突变(200 → 500 / 内容差异)
  • 响应里出现数据库错误关键字(SQL syntax / ORA- / PostgreSQL / Unclosed quotation
  • 同参数 1=1 vs 1=2 响应可区分
  • 注入 SLEEP(N) 耗时增加 N 秒

入口类型粗筛(仅作类似场景示例 不限于此):

  • 搜索 / 列表 / 筛选接口(LIKE 拼接常见)
  • 登录 / 注册接口(WHERE 拼接常见)
  • 排序接口(ORDER BY 拼接,白名单常缺失)
  • 详情 / 修改接口(路径 ID / 主键查询)

业务命名只作粗筛——sink 语义相同就属此范围。JSON body 任一字段、header / cookie 任一字段都是 SQLi 候选,不限于"看起来像数据库"的字段名;具体参数位置由 HAR 实际请求推导,不在此预设清单。

2. 造成原因

source 是任何用户可控输入(query / body / header / cookie / 路径参数 / 已入库再回读的字段)。sink 是 SQL 上下文:WHERE / LIKE / ORDER BY / GROUP BY 子句、INSERT 值、UPDATE SET、JOIN ON、HAVING、LIMIT / OFFSET、任何拼接进 SQL 查询的字符串位置。

任何 source 未经参数化绑定就被拼接到 sink,即构成 SQL 注入——攻击者控制的字符串改变了 SQL 语法树。预编译参数(PreparedStatement / $1 $2 / ? 占位符)把数据和指令在协议层隔离开,是默认防御。

ORM 不是免疫层:所有 ORM 都有 Raw 通道(.raw() / .query() / Raw() / nativeQuery()),且字段名 / 表名 / 排序方向不可参数化(必须白名单)。

3. 响应信号映射

列出 SQLi 黑盒可观测的响应通道集合(observation-channel)——攻击效果可被黑盒探测的侧信道。输入位置(query / body / header / cookie / path)从 HAR 实际请求推导,本节不预设清单。

响应观察通道集合(observation-channel):

  • error-echo:错误信息回显(数据库错误关键字 + 可控数据回显)
  • union-echo:UNION 拼接列值直接渲染到响应
  • boolean-diff:同参数二态稳定可区分(status / 内容 / 长度)
  • time-sidechannel:耗时可控(SLEEP / WAITFOR / pg_sleep)
  • oob-dns / oob-http:带外通道触发(DNS / HTTP 请求)
  • secondary-readback:二阶注入在另一端点回读时触发

4. 常见类型

类型 触发条件 响应特征 适用 DBMS
布尔盲注(Boolean) 响应内容随条件 true/false 二态变化 ' AND 1=1 -- vs ' AND 1=2 -- 响应可区分 全部
时间盲注(Time-based) 响应内容不可区分但耗时可控 SLEEP(N) / WAITFOR DELAY / pg_sleep MySQL / MSSQL / PG
报错注入(Error-based) 错误信息回显到响应 updatexml() / extractvalue() / cast() MySQL / MSSQL
UNION 注入 查询结果直接渲染到响应 UNION SELECT NULL, NULL, ... 列数匹配后回显 全部
堆叠查询(Stacked) 驱动允许 ; 分隔多语句 ; DROP TABLE... 副作用 MSSQL / PG(MySQL 默认禁)
二阶注入 先入库后回读时触发 source 入库不报错,回读拼接时触发 全部
OOB(带外) 无回显且无延时通道 LOAD_FILE / xp_dirtree 触发 DNS / HTTP MySQL / MSSQL

5. 侦察输入

按以下方式从侦察输出中筛 SQLi 候选:

从 HAR / 端点账本

  • 参数名含 q / search / keyword / id / sort / order / filter / where / category / tag
  • 端点路径含 /api/search / /list / /page / /{id} / /query / /filter
  • 响应里曾出现过数据库错误关键字(作为基线参考)
  • POST / PUT 端点的 body 全字段(JSON / form 各字段都是候选)

从业务场景(由 page-analysis 输出):

  • 电商:搜索 / 商品列表 / 订单查询 / 评论筛选
  • SaaS 多租户:跨租户的资源查询(IDOR + SQLi 复合)
  • 内容 / 论坛:文章搜索 / 评论列表 / tag 筛选
  • 金融:交易记录 / 账户查询 / 流水报表

从身份切换 HAR 对比

  • 普通用户 / 管理员两份 HAR 里仅在管理员端出现的端点是高价值候选(admin 端常复用普通端的查询模板但权限边界更松)
  • 跨子系统的同名端点(多个端口 / 子域 / 业务条线)每个独立测,不假设"在 A 测过 B 也安全"

6. 框架 / DBMS 响应指纹

通过响应(错误关键字 / header / 行为)推断后端 DBMS / 框架 / WAF,优化 payload 选择。

DBMS 响应指纹

响应特征 推断 DBMS payload 选择
You have an error in your SQL syntax / MySQL / SQLSTATE MySQL / MariaDB SLEEP() / -- 注释 / 0x hex / /**/ 绕过
syntax error at or near / PostgreSQL PostgreSQL pg_sleep() / -- 注释 / `
Unclosed quotation mark / ODBC / SQL Server / Microsoft MSSQL WAITFOR DELAY / xp_cmdshell / 堆叠查询
ORA-00933 / Oracle Oracle DBMS_PIPE.RECEIVE_MESSAGE 延时 / `
SQLite3.OperationalError / near SQLite 限制:无 SLEEP、无堆叠、无 xp_cmdshell

框架响应指纹

响应特征 推断框架 优化方向
X-Powered-By: Express / Set-Cookie: connect.sid Express (Node.js) 大概率 Sequelize 或 mysql2,常见拼接形态
Set-Cookie: PHPSESSID / X-Powered-By: PHP/... PHP mysqli / PDO 拼接
Server: nginx + JSESSIONID cookie Java / Spring JdbcTemplate / MyBatis ${}
Server: gunicorn / Python traceback Django / Flask .raw() / .extra()
X-Aspnet-Version ASP.NET ADO.NET / EF Raw

WAF 响应指纹

响应特征 WAF 绕过方向
cf-ray header / Cloudflare 拦截页 Cloudflare 编码绕过 / chunked / 大小写混用
request blocked + 阿里云 LOGO 阿里云 WAF URL 编码 / 注释截断
imunify360 Imunify360 同上
自定义 403 + 安全狗签名 安全狗 同上

响应指纹仅作辅助判断——真实的 sink 验证仍需在 §9 闭环要求章节定义的可观测效果证据。

7. 思考检查点

加载本 skill 时按这些问题思考:

  • 这个参数在 HAR 里出现在哪个位置?响应里有没有可观察的回显或差异通道?
  • 同端点其他参数是否走同一段 SQL 模板?(同模板下其他字段往往是候选)
  • 响应里有数据库错误关键字吗?没有的话,能否用时间盲注 / 带外 / 布尔差异作为侧信道?
  • 是不是字段名 / 表名 / 排序方向位置(?sort= / ?order_by=)?这类不能参数化,必须看白名单。
  • 是不是二阶?这个参数会被入库吗?后续哪些端点会回读它?
  • 跨子系统是否有同 pattern_id 端点?(admin 端常复用普通端代码)

8. 检测方法论 / 决策树

全局约束(默认保守预算)

  • 单参数最多 20 次请求(含基线 / 重试);同一轮只改 1 个参数
  • 时间盲注延时选择能区分网络抖动的最小值(通常 3-5s),抖动大时增加重试次数
  • 并发建议 1;抖动大时加重试而非加并发
  • 一旦"确认"立即停止进一步探测

参数隔离

  • 每轮只改一个参数,便于将响应差异与该参数建立因果关系
  • 参数位置按优先级依次排查:Query → Body → Cookie → Header(仅改 1 个位置)
  • 基线参数选择不限于"看起来像数据库"的命名——按 sink 语义判定,所有触发线索类别都是候选

Step 0:基线采集

  1. 发送原始请求 2-3 次,记录"基线响应特征" + "基线耗时分布"
  2. 标记并忽略动态字段(时间戳 / 随机 ID / sessionToken)

Step 1:闭合 / 上下文探测

参数末尾追加 ' / " / ) / --,观察响应突变 / 报错。不要全打,按 sink 语义选 2-3 个候选试:

  • 引号探测:'",看是否出现的语法错误特征或响应突变
  • 括号探测:) / )),观察从"错误→正常"或"正常→错误"的可复现翻转
  • 注释候选:MySQL 优先 -- / #;其他 -- / ;

输出:候选上下文集合(numeric / string + quote + paren_close + comment)。

Step 2:响应指纹判断

按 §6 响应指纹表识别 DBMS 与框架。结论标注置信度(high / medium / low)。

Step 3:策略决策树

有错误回显且语法错误可触发?      → 报错注入(信息量最高)
查询结果直接渲染到响应?           → UNION 注入
响应内容差异稳定(TRUE/FALSE)?   → 布尔盲注
响应不可区分但耗时可控?           → 时间盲注(速度最慢)
无回显无延时?                     → OOB / 堆叠(仅 MSSQL/PG)

Step 4:确认 + 防误报

  • 强证据(满足其一即 confirmed):稳定数据库错误回显且只由 payload 引发;稳定 UNION 回显;带外通道收到明确归属本注入的请求
  • 弱证据(需两类同时满足才升 confirmed):布尔盲注 TRUE/FALSE 差异可复现 3 次 + 另一辅助证据;时间盲注统计显著(差异远大于抖动)+ 指纹 / 闭合推断一致
  • 拒绝条件:单次报错 / 单次延时 / 响应仅 500 不带可控信息——一律 suspected

Payload 范式与编码绕过

  • WAF 关键字过滤 → 大小写混用 / 内联注释 /**/ / 等价函数(SUBSTRINGSUBSTR / SLEEPBENCHMARK
  • 引号过滤 → 0x... 十六进制编码 / CHAR(0x...) / 宽字节 %bf%27(GBK / 旧版本 MySQL)
  • 空格过滤 → /**/ / + / %0a / %0b / (...)
  • 字段名 / 表名拼接(无引号位置)→ 直接构造子查询或 CASE 表达式:?sort=(case when 1=1 then created_at else id end)

基线检查项(按 §4.3 三态标注)

  • 单参数所有候选位置(query / body / header / cookie / path)都过了 Step 0-1
  • 同端点其他参数同步分诊
  • 字段名 / 排序方向位置单独评估(不可参数化,看白名单)
  • 二阶通道:从入库端点追到回读端点

9. 闭环要求(必须遵守)

闭环判定(confirmed / suspected / not_vulnerable)以 common/closure-verification.md 为准。下面只列本漏洞特有的可观测信号。

confirmed(必须挂可观测效果证据)

  • 布尔盲注:同参数 ' AND 1=1 -- vs ' AND 1=2 -- 响应可区分,重复 3 次稳定,差异点可指认
  • 时间盲注:注入 SLEEP(3) 耗时 > 基线 + 2.5s,重复 3 次稳定,且无延时参数耗时回到基线
  • 报错注入:响应里出现攻击者可控数据库回显(如 updatexml 报错带 @@version / database() / 表名)
  • UNION 注入:响应里出现 UNION 拼接的列值(版本号 / 当前用户 / 表名 / 业务表数据)
  • OOB:带外通道(DNS / HTTP)收到明确归属本注入的请求,含时间戳和唯一 token

suspected(落 status=needs_review

  • 单次报错 / 单次延时(未稳定复现)
  • 引号触发响应突变但无法构造稳定二态
  • 报错只到"SQL 语法错误"层级,未拿到任何可控回显

not_vulnerable(落 status=not_vulnerable

  • 同模板下所有参数均经参数化绑定(来自 graybox 流程的白盒证据)
  • 该端点不接触 SQL(静态资源 / 健康检查)

禁止仅凭"响应 500""执行无异常""绕过了某黑名单"判 confirmed——这些只到 suspected。

反例义务(必须遵守)

why:反例义务属于交付契约——"该子系统无 SQLi"或"已防护"结论是覆盖完整性产物声明,缺失反向验证清单会让下游误信"该维度全站安全"。

写"未发现 SQLi"或"已防护"前,产物必须包含:

  • 测过的 SQLi 候选端点完整清单(按 sink 语义枚举,含登录账号 / 搜索 keyword / ORDER BY 字段 / ID 路径参数 / JSON body 各字段 / Header 值 / Cookie 等全部触发线索类别
  • 每端点测过的 payload 类型(引号 / 括号 / OR 永真 / UNION / 布尔盲注 / 时间盲注)
  • 每端点的响应证据(基线响应 / payload 响应 / 差异点)

清单不完整 → 结论降级为 partial-coverage 并显式声明未覆盖范围。

10. 具象化反例库

FP(看似命中实际不构成)

反例 1:响应突变源于 WAF 拦截,不是 SQL 报错

  • 抽象规则:响应突变 ≠ 注入成功
  • 具体场景:附带引号的请求返回 403 / 自定义错误页 / 响应里出现 request blocked / security violation 字样
  • 关键识别特征:响应 body 含 WAF 关键字(Cloudflare / Sucuri / 阿里云 / 安全狗);响应头 cf-ray / Server: imunify360 等可识别 WAF
  • 排除方法:去掉引号但保留其他扰动(如改大小写),若响应仍突变多半是 WAF;同时尝试合法 SQL 注释 -- 是否被替换 / 拦截

反例 2:错误 500 不带 SQL 关键字

  • 抽象规则:500 ≠ SQLi
  • 具体场景:响应 status 500,body 是通用错误页或 JSON {"error": "internal"},无数据库关键字
  • 关键识别特征:响应里无 SQL / query / database / DBMS 名字
  • 排除方法:尝试其他注入位置看是否同样 500(可能是异常处理缺失,不是 SQLi)

反例 3:MySQL LIMIT 后参数化失败的旧版拼接不一定是注入

  • 抽象规则:旧版 MySQL JDBC / 旧版 PHP PDO 的 LIMIT ? 占位曾不支持,开发者用拼接
  • 具体场景:SELECT ... LIMIT + pageSize
  • 关键识别特征:pageSize 通常是整型校验过的;攻击面取决于上游是否做 int 解析
  • 排除方法:尝试 pageSize 注入非数字内容看是否被强制转换 + 异常拒绝

FN(看似不命中实际是真洞)

反例 4:字段名拼接(无引号不报错)

  • 抽象规则:ORDER BY / GROUP BY 后接的字段名不能用引号包裹,参数化对它无效
  • 具体场景:?sort=created_at → 后端拼接 ORDER BY;改成 ?sort=invalid_column 报错 unknown column
  • 关键识别特征:?sort / ?order_by 参数 + 改成无效字段名报错 unknown column
  • 确认方法:尝试 ?sort=(case when 1=1 then created_at else id end) 看是否可控字段顺序;或 ?sort=if(1=1,id,name)

反例 5:二阶注入(入库时不报错,回读时触发)

  • 抽象规则:source 入库走参数化不报错,不代表回读拼接安全
  • 具体场景:注册时邮箱字段含 ',入库正常;后台 admin 页面以邮箱查日志,回读时拼接进新查询
  • 关键识别特征:「同一字段在 2 个 SQL 上下文里出现」+「其中至少 1 个用拼接」
  • 确认方法:追入库字段被哪些回读端点消费,每个回读点都看是否参数化

反例 6:JSON body 字段被忽略的 SQLi 候选

  • 抽象规则:JSON body 字段每个都是候选,不能只测可见 form 字段
  • 具体场景:POST /api/users 的 body 含 {"sortBy": "id", "filter": "..."},filter 字段被拼到 WHERE
  • 关键识别特征:HAR 里 POST body 字段未在 query string 里出现,但在响应中影响排序 / 筛选
  • 确认方法:JSON body 每个字段单独 fuzzing,参考 Step 1 闭合探测

易混淆案例

反例 7:跨子系统隐式推广(漏报高发模式)

  • 抽象规则:在子系统 A 测过 ≠ 子系统 B 也安全
  • 具体场景:测了 user-portal 的搜索接口未发现 SQLi,admin-portal 的同名搜索接口未测就推断安全
  • 关键识别特征:不同子系统、不同团队、不同时期开发;admin 端常复用普通端代码但实现可能各异
  • 确认方法:admin / user / 第三方接入等每个子系统独立做反例义务自检

11. 测试安全边界

破坏性 / 不可逆动作的闭环边界以 common/closure-verification.md《破坏性 / 不可逆动作的闭环边界》节为准。下面只列 SQLi 特有的破坏点。

禁止对真实业务数据执行以下动作来"挂可观测效果":

  • ; DROP TABLE / ; TRUNCATE / ; DELETE FROM <real_table>(堆叠查询场景)
  • UPDATE ... SET ... WHERE 1=1(无 WHERE 限定的更新)
  • 任何用 LOAD_FILE 读取系统文件后回写、或 INTO OUTFILE 写入文件系统的动作
  • 任何通过 xp_cmdshell / sys_exec / COPY ... FROM PROGRAM 触发 OS 命令的动作

允许的非破坏验证手段:

  • 哨兵自证:建测试库 / 测试表 / 测试行(前缀 sastx_sentinel_),仅对哨兵执行可破坏操作
  • 非破坏差分:仅做 SELECT 类回读 + 时间盲注 + 报错回显
  • 带外通道:DNS / HTTP OOB(不修改目标状态)
  • CASE 表达式:用 WHERE col = (CASE WHEN ... THEN col ELSE col END) 类构造测试逻辑可控性,不改变查询语义

12. 修复建议

源头治理(首选)

  • 全部走参数化 / 占位符:
    • JDBC / PDO / Go database/sql:? / $N 占位 + 单独传 args
    • MyBatis:#{} 而非 ${}${} 仅限明确可信白名单内的字段名 / 表名)
    • ORM:用表达式对象 where: {col: val} / db.Where("col = ?", val),禁止字符串拼接进 Raw 通道

字段名 / 表名 / ORDER BY 子句

  • 白名单:把允许的字段名 / 排序方向 enum 化,请求参数在 enum 内才进 SQL;否则 400 / 用默认值

二阶注入

  • 入库即参数化:注册 / 写入时仍用参数化(防一阶)
  • 回读必参数化:任何 source 字段被回读到新 SQL 上下文时,按 source 重新做参数化绑定,不复用入库时的"已校验"假设

边界过滤(次选,作为深度防御)

  • WAF 规则覆盖常见 payload(UNION / SLEEP / xp_cmdshell 等关键字)——仅作辅助,不替代参数化
  • 应用层拒绝单引号 / 特殊字符——易绕过,仅作日志记录与告警触发

兜底拒绝

  • 数据库最小权限:业务账号禁止 DDL / 跨库查询 / 文件操作(FILE 权限)
  • 错误响应不暴露 SQL 语法信息(即使 dev 模式也走统一错误码)

参考

Install via CLI
npx skills add https://github.com/Q16G/aster --skill sql-injection-comprehensive
Repository Details
star Stars 72
call_split Forks 6
navigation Branch main
article Path SKILL.md
More from Creator