PortSwigger -sql学习

所有SQL注入检测的本质,都是制造"正常查询"和"异常查询"之间的差异,然后想办法观测到这个差异。

报错探测 —— 利用"语法错误泄露信息"

正常情况下,你的输入是:

sql

SELECT * FROM users WHERE username = 'wang';

当你输入单引号'后,SQL变成:

SELECT * FROM users WHERE username = ''';

数据库解析器看到:'开头的字符串,在遇到第二个'时闭合了,但后面多了一个孤立的单引号,导致字符串没有正确终结,SQL语法不完整。

数据库引擎报错(不同数据库错误信息不同):

  • MySQLYou have an error in your SQL syntax

  • PostgreSQLERROR: unterminated quoted string

  • OracleORA-01756: quoted string not properly terminated

  • SQL ServerUnclosed 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)是最后的武器。

核心思路是:让数据库向外发起网络请求,你监控这个请求是否到达你控制的服务器。