所有SQL注入检测的本质,都是制造"正常查询"和"异常查询"之间的差异,然后想办法观测到这个差异。
报错探测 —— 利用"语法错误泄露信息"
正常情况下,你的输入是:
sql
SELECT * FROM users WHERE username = 'wang';当你输入单引号'后,SQL变成:
SELECT * FROM users WHERE username = ''';数据库解析器看到:'开头的字符串,在遇到第二个'时闭合了,但后面多了一个孤立的单引号,导致字符串没有正确终结,SQL语法不完整。
数据库引擎报错(不同数据库错误信息不同):
MySQL:
You have an error in your SQL syntaxPostgreSQL:
ERROR: unterminated quoted stringOracle:
ORA-01756: quoted string not properly terminatedSQL Server:
Unclosed quotation mark
关键点:这个错误信息如果被Web服务器原样返回给前端,你就看到了"报错回显"。
为什么有时看不到报错?
应用代码可能用了try-catch捕获异常,返回一个200状态码的自定义错误页面,而不是把数据库原始错误抛出来——这时候报错探测就失效了,需要转向下面其他方法
布尔盲注 —— 利用"真假条件导致页面不同"
当数据库不返回报错信息,但页面在查询结果为真/假时输出不同内容(比如显示"欢迎回来" vs "账号不存在"),我们可以通过构造逻辑表达式来"问"数据库问题,通过页面差异拿到答案。
核心payload对:
-- 真条件(永远为真) SELECT * FROM users WHERE username = 'admin' AND 1=1 -- ' -- 假条件(永远为假) SELECT * FROM users WHERE username = 'admin' AND 1=2 -- '攻击者利用这种差异逐字符"问"出数据:
-- 问:数据库名字的第一个字符是不是'a'? admin' AND SUBSTRING(database(),1,1) = 'a' --
如果页面返回"欢迎回来" → 答案是'a' ✅
如果返回"账号不存在" → 不是'a',继续试 'b','c'...
时间盲注 —— 利用"睡眠函数制造时间差"
当页面无论真假返回内容都完全一样(布尔盲注也失效),但数据库仍然逐条执行SQL指令,我们可以利用数据库内置的延时函数制造可观测的时间差异
-- 如果条件为真,等待5秒再返回 admin' AND IF(1=1, SLEEP(5), 0) -- -- 如果条件为假,不等待 admin' AND IF(1=2, SLEEP(5), 0) --带外交互(OAST)—— 利用"数据库发起外部网络请求"
原理
当时间盲注也被禁用(比如WAF拦截了SLEEP函数,或者数据库连接超时限制太短),OAST(Out-of-Band Application Security Testing)是最后的武器。
核心思路是:让数据库向外发起网络请求,你监控这个请求是否到达你控制的服务器。