判断依据是页面是否回显数据或错误信息:有数据回显且支持union结构(列数、类型一致)则选联合查询注入;无数据回显但返回数据库错误详情(如xpath syntax error)则选报错注入。

联合查询注入和报错注入是两种有回显前提下的主流SQL注入手法,但适用条件完全不同:前者依赖页面能直接显示查询结果,后者依赖数据库错误信息可被返回到前端。
怎么判断该用 UNION 还是报错注入
关键看页面是否“吐出”数据库内容或错误信息:
- 如果输入
1' OR '1'='1后页面正常显示数据,但换用1' ORDER BY 3--+报错提示列数超限 → 很可能支持UNION注入,且有显示位 - 如果输入
1' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT USER()),0x7e))--+页面返回类似XPATH syntax error: '~root@localhost'的错误 → 属于报错注入场景 - 若两者都无反应(页面空白/500/跳转),需转向盲注(时间型或布尔型)
- 注意:MySQL 5.7+ 默认关闭
sql_mode=STRICT_TRANS_TABLES时,floor(rand()*2)类报错可能失效;而updatexml()和extractvalue()在 8.0 中仍可用,但部分云数据库已过滤函数名
UNION 注入必须绕过的三个硬约束
UNION SELECT 不是写完就能跑,MySQL 强制校验结构一致性:
- 列数必须一致:用
ORDER BY N试探,或直接爆破UNION SELECT 1,2,3...N - 对应列数据类型要兼容:比如第2列原为
VARCHAR,你不能塞1.23(会隐式转成字符串),但塞NULL或'abc'更稳 - 只有最后一个
SELECT允许带LIMIT、ORDER BY;前面的子句加这些会直接语法报错 - 实战中常配合
GROUP_CONCAT()拼接多行结果,避免只显示第一行;例如:UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema=database()
报错注入为什么常用 extractvalue() 和 updatexml()
这两个函数本质是“借刀杀人”:利用 XML 解析器对非法 XPath 表达式的严格报错,把查询结果塞进错误消息里:
-
extractvalue(1, CONCAT(0x7e, (SELECT user()), 0x7e)):XPath 第二参数必须是合法路径,CONCAT()拼出的~root@localhost不是有效路径,MySQL 就在错误中返回它 -
updatexml(1, CONCAT(0x7e, (SELECT database()), 0x7e), 1):第三个参数本该是新值,但第二个参数非法,解析失败时就把拼接内容当错误上下文输出 - 注意长度限制:两个函数对第二参数长度上限都是 32 字符,超长会截断;需要用
SUBSTRING()分段提取,例如:SUBSTRING((SELECT password FROM users LIMIT 0,1),1,32) -
floor(rand(0)*2)+GROUP BY的老套路在 MySQL 5.6+ 已不稳定,容易因临时表冲突失败,不建议优先使用
真实环境中最容易忽略的细节
不是 payload 能跑通就万事大吉:
- URL 编码问题:空格必须转
%20或+(注意+在 GET 中是空格,不是加号),单引号要保持原样不编码,否则后端可能先解码再拼接 - 字符集干扰:某些 CMS 对输入做
utf8mb4转义,导致0x7e(~)被破坏,可改用0x3a(:)或双写绕过 - WAF 拦截点:很多规则盯
extractvalue、updatexml、concat,可尝试大小写混写(ExTrAcTvAlUe)、内联注释(extractvalue/**/(1,...)或用geometrycollection()等冷门函数替代 - 报错注入在高版本 MySQL 或开启
log_error_verbosity=1时可能只返回通用错误,此时需切换思路——错误信息没出来,不代表语句没执行











