SQL注入第一关实战:union联合注入从注入点判断到取数据的完整链路
1. 为什么第一关反而是最值得反复琢磨的很多人搭好本地靶场环境之后第一关往往三分钟就过了然后急着往后刷。我自己早期也是这样觉得第一关太简单没什么可讲的。后来带新人复盘的时候才发现恰恰是第一关把 union 联合注入的完整链路暴露得最干净从判断注入点、猜列数、定位回显位、探数据库名、探表名、探字段名到最终取数据每一步都能在一关里跑通。把这关吃透后面那些关卡无非是换了过滤规则和注入位置而已。这篇内容面向的是刚接触 SQL 注入原理、正在用本地靶场练手的朋友也适合已经会跑工具但说不清手工流程的人。我会把第一关从零到取到数据的过程完整拆一遍重点讲清楚每一步为什么这么做、参数怎么定、遇到回显不对怎么排查。所有操作都在你自己搭建的本地练习环境里进行目的是理解注入的成因和防御思路不要对任何非授权目标做测试。先说清楚这一关的底层场景页面接收一个 id 参数直接拼进 SQL 查询然后把查询结果渲染到页面上。因为没有任何过滤和参数化处理我们输入的字符会原样进入数据库执行。union 联合注入的核心思路就是利用 union 可以把另一条 select 的结果拼接到原查询结果后面这个特性把原本查不到的数据“借”到页面上显示出来。理解这一点很关键。union 注入不是凭空造数据而是“搭便车”——原查询返回什么结构我们就得让附加查询返回同样的结构否则数据库直接报错。所以整条链路里猜列数、对回显位这两步是地基地基没打牢后面全是白费。2. 注入点判断与 union 注入的适用前提2.1 先确认这个参数到底能不能注入拿到一个带参数的页面第一步不是急着上 union而是先确认它是不是注入点。我习惯用最朴素的办法给参数分别传一个正常值、一个带单引号的值、一个数学表达式看页面反应。假设正常访问是?id1页面显示一个用户信息。接着试?id1如果页面报 SQL 语法错误或者内容明显异常基本可以判定单引号被带进了 SQL 语句。再试?id2-1如果页面显示的是 id1 的结果说明参数没被当成纯字符串处理而是参与了运算这进一步坐实了注入。这里有个细节很多人忽略报错不一定每次都出现。有些环境把错误关掉了页面只是空白或者显示“无结果”。这时候不能直接下结论说不能注入要换布尔判断的方式比如?id1 and 11和?id1 and 12对比返回内容是否一致。前者正常、后者异常说明 and 条件生效了注入点成立。提示判断注入点时单引号、双引号、括号都要试。不同写法对应的闭合方式不同第一关通常是数字型或字符型单引号闭合但养成都试一遍的习惯后面遇到复杂闭合才不会慌。2.2 union 注入成立需要满足哪些条件union 注入不是万能钥匙它有几个硬性前提。第一原查询和附加查询的列数必须一致这是数据库的语法要求不一致直接报错。第二页面上必须有回显位也就是原查询的某些列会显示在页面上我们才能把数据塞到那些位置。第三当前数据库用户要有对应库表的查询权限权限不够就算语句对了也取不到数据。第一关之所以适合入门就是这三个条件全都满足列数可以通过 order by 试出来回显位肉眼可见权限也是足够的。所以它成了理解 union 注入的最佳样本。我个人的经验是先判断注入类型再决定用 union 还是报错注入、布尔盲注。如果页面有回显、有报错union 是效率最高的如果页面什么都不显示那 union 就没法把数据带出来得换盲注思路。这个判断顺序别搞反否则会在错误的方向上浪费大量时间。3. 猜列数order by 与 union select 两种手法对比3.1 用 order by 二分定位列数确定注入点之后第一件正事是猜原查询有几列。最常用的手法是order by。它的原理是order by N表示按第 N 列排序如果 N 超过了实际列数数据库就会报“Unknown column”之类的错误。所以我们从 1 开始递增直到报错报错前那个数字就是列数。实际操作时访问?id1 order by 1、?id1 order by 2、?id1 order by 3……假设到 4 的时候页面报错那说明原查询是 3 列。为了快一点可以用二分法先试 10报错就说明列数小于 10再试 5以此类推。列数少的时候直接递增更直观列数多的时候二分更省事。这里有个坑有些环境对 order by 后面的数字做了处理或者页面本身不显示排序错误。这时候 order by 可能失灵得换 union select 来试。3.2 用 union select 直接试列数另一种办法是直接构造?id1 union select 1,2,3如果列数不对数据库会报“The used SELECT statements have a different number of columns”。我们不断调整数字个数直到页面正常返回那个个数就是列数。两种手法我一般配合用先用 order by 快速定位再用 union select 验证一遍。因为 order by 有时会因为排序字段类型问题产生误判而 union select 的列数校验是数据库层面的硬校验更可靠。手法优点缺点适用场景order by不改变回显内容判断干净部分环境屏蔽排序错误列数较少、报错可见union select数据库硬校验结果可靠列数不对时页面直接报错需要精确验证列数注意猜列数时不要一上来就写一大堆数字。列数猜多了报错猜少了也报错只有刚好相等才正常。所以要么递增要么二分别乱猜。4. 定位回显位让数据出现在你能看到的地方4.1 为什么原查询查不到数据反而更好用列数确定后下一步是找哪几列会显示在页面上。这里有个反直觉的技巧把原查询的 id 改成一个数据库里不存在的值比如?id-1或者?id99999。这样原查询返回空页面上原本显示用户信息的位置就空出来了union 附加查询的结果就会顶上去显示。如果原查询有结果union 的结果会拼在它后面页面上可能只显示第一条我们看不到自己塞的数据。所以让原查询“查空”是定位回显位的关键操作。这一步很多人第一次做会懵明明语句对了却看不到数据多半就是原查询还有结果占着位置。4.2 用数字标记回显位构造?id-1 union select 1,2,3页面正常返回后你会看到页面上某些位置显示了 1、2、3 中的某几个数字。这些数字出现的位置就是回显位。比如页面显示了 2 和 3说明第 2、3 列会渲染到页面上第 1 列不回显。回显位可能只有一个也可能有多个。多个回显位时我们通常选最靠前、显示最完整的那个来放数据因为有些位置可能被截断或者格式受限。第一关一般有两到三个回显位足够我们操作。提示如果页面显示的是 1、2、3 但顺序和位置对不上别慌那是页面模板决定的。你只需要记住哪个数字出现在哪个可见区域后面把查询语句替换到那个数字的位置即可。4.3 回显位选哪个更稳我一般优先选页面正中间、显示完整、周围没有多余字符干扰的那个位置。有些回显位旁边带着固定文案比如“欢迎 xxx”那 xxx 的位置就是理想的注入点。选好之后把2替换成database()如果页面显示出数据库名说明这个位置可用链路就打通了。这一步验证成功的那一刻其实 union 注入最核心的部分就完成了。剩下的都是在这个位置上换不同的查询函数把想要的数据一点点取出来。5. 从库名到数据information_schema 的实战用法5.1 先拿当前数据库名回显位确定后第一件事是查当前数据库名用database()。构造?id-1 union select 1,database(),3页面回显位显示的就是当前库名。这个库名很重要因为后面查表名、字段名都要以它为条件缩小范围。拿到库名后我习惯先记下来后面所有查询都围绕它展开。有些环境有多个库如果不限定库名查出来的表会一大堆干扰判断。5.2 查表名information_schema.tables数据库名有了接着查这个库里有哪些表。MySQL 系列数据库有一个系统库叫information_schema里面tables表记录了所有库表信息。构造查询?id-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()group_concat把多行结果拼成一行方便在单个回显位里看全。table_schemadatabase()限定只查当前库。页面回显出来的就是当前库所有表名用逗号分隔。如果回显位长度有限表名太多被截断可以加limit分批取或者用where table_schemadatabase() limit 0,1一条条看。第一关一般表不多一次就能看全。5.3 查字段名information_schema.columns表名拿到后挑一个看起来像存用户信息的表比如 users 之类。接着查它的字段?id-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schemadatabase() and table_nameusers页面回显的就是 users 表的所有字段名。通常能看到 id、username、password 这类字段。到这一步数据结构就完全暴露了。查询目标关键函数/表限定条件当前库名database()无表名information_schema.tablestable_schemadatabase()字段名information_schema.columnstable_schema table_name具体数据目标表直接查指定字段5.4 取具体数据字段名有了最后一步就是取数据?id-1 union select 1,group_concat(username,0x3a,password),3 from users0x3a是冒号的十六进制用来把用户名和密码拼在一起显示比用逗号更清晰。页面回显出来的就是所有用户名和密码的组合。到这一步整个 union 注入链路就走完了。注意实际练习环境里取到的数据都是靶场自己造的假数据不要拿这套流程去碰任何真实系统。理解原理是为了知道怎么防不是为了去搞破坏。6. 实操中容易翻车的几个点6.1 列数对了但页面还是报错这种情况我遇到过好几次。列数明明和 order by 试出来的一致union select 却报错。排查下来通常是两个原因一是原查询用了select *实际列数比页面显示的字段多二是某些列的数据类型不兼容比如原查询某列是数字你 union 里塞了字符串数据库在类型转换时报错。解决办法是把 union 里的数字换成 null。null 可以匹配任何类型兼容性最好。构造?id-1 union select null,null,null如果正常返回说明列数对问题出在类型上再逐个把 null 换成具体查询即可。6.2 回显位显示不全或被截断有时候数据取出来了但页面只显示一半。这通常是页面模板对输出长度做了限制或者回显位本身宽度有限。应对办法是用substr分段取比如substr(database(),1,5)先取前五个字符再取后面的。也可以用group_concat配合limit分批。我一般先用length(database())看总长度再决定分几段取。虽然麻烦一点但能保证数据完整。6.3 单引号闭合方式判断错误第一关常见的是数字型注入不需要闭合引号。但如果你按字符型去闭合多加了一个单引号语句就错了。判断方法很简单传?id1正常传?id1报错说明原语句里 id 没有被引号包裹是数字型不需要闭合。如果传?id1正常、?id1报错那可能是字符型需要闭合。这个判断直接影响后面所有语句的构造搞错了后面全错。所以我在注入点判断阶段会反复确认闭合方式不急着往下走。6.4 常见问题速查表现象可能原因排查方向union select 报列数不一致列数猜错重新用 order by 或 null 法确认页面空白无回显原查询有结果占位把 id 改成不存在的值数据只显示一半输出长度限制用 substr 分段取语句报语法错误闭合方式不对确认数字型还是字符型查不到表名库名限定错误用 database() 确认当前库7. 从攻击视角反推防御思路把第一关完整走一遍之后其实最有价值的收获不是“会注入了”而是明白了漏洞是怎么来的。页面把用户输入的 id 直接拼进 SQL 语句没有做任何处理这就是根源。防御的核心就一句话让用户输入永远只是数据不能变成 SQL 代码的一部分。具体到工程实践参数化查询预编译是最有效的手段。它把 SQL 语句的结构提前固定好用户输入的值只能填进占位符无法改变语句结构。即使用户输入了单引号、union 这些字符也只会被当成普通字符串处理不会被执行。除了参数化查询还有几层辅助措施对输入做类型校验id 这种参数强制转成整数数据库账号遵循最小权限原则Web 应用连库的账号不给 information_schema 之外的敏感库权限关闭详细报错避免把数据库结构泄露给攻击者。这几层叠加起来union 注入基本就没有生存空间了。我自己在复盘时有个习惯每学一种注入手法就反过来想它在什么防御措施下会失效。union 注入怕参数化、怕类型校验、怕权限收紧。想清楚这些才算真正理解了这种漏洞而不是只会照着步骤敲语句。8. 我练第一关时踩过的几个坑第一次做第一关我在猜列数那步卡了很久。当时用 order by 一直试到 10 都没报错以为列数很多结果是我访问的 URL 里参数拼接写错了order by 根本没生效。后来发现是浏览器自动把空格编码了得用或者%20代替空格。这个细节很小但当时折腾了半小时。还有一次是回显位定位我死活看不到 union 的结果。排查半天才发现原查询的 id1 有数据union 结果被挤到后面去了。改成 id-1 之后立刻就出来了。这个“让原查询查空”的技巧现在成了我教别人的第一句话。最后一个坑是 group_concat 的长度限制。默认它有长度上限表名或字段名太多时会被截断看起来像是数据不全。解决办法是调大group_concat_max_len或者干脆用 limit 一条条取。我现在的习惯是只要用 group_concat就先确认一下会不会超长避免取到一半的数据还以为拿全了。这些坑说起来都不复杂但没踩过就是想不到。手工注入练的就是这种对细节的敏感度工具能帮你跳过这些但跳过之后你也就失去了排查问题的能力。所以我的建议是第一关至少手工完整走三遍每一遍都试着不看笔记直到能闭着眼睛说出下一步该干什么。

相关新闻

深度学习第二章自救指南:概率论与数值计算如何落地

深度学习第二章自救指南:概率论与数值计算如何落地

说实话,当我在学习笔记目录里看到deeplearningbook_002-2这个编号时,第一反应是有点头皮发麻的。002 指的是那本经典深度学习教材的第二章,而 -2 则意味着这一章被我拆成了两个部分来处理。前半部分线性代数还能靠矩阵乘法硬撑下去&#xff0…

2026/10/17 4:53:15 阅读更多 →
MySQL基本应用与性能调优:从建表、SQL优化到索引实战

MySQL基本应用与性能调优:从建表、SQL优化到索引实战

1. MySQL到底是什么,为什么大家都在用它先别急着敲命令,把概念搞清楚比什么都重要。MySQL本质是一个关系型数据库管理系统,它帮你把数据按照“表”的形式组织起来,一张表里有行有列,行是一条记录,列是一个字…

2026/10/17 4:53:15 阅读更多 →
海风域名查询工具v1.0:纯PHP轻量模块,无需API快速集成

海风域名查询工具v1.0:纯PHP轻量模块,无需API快速集成

简介:海风域名查询工具v1.0是一款基于PHP开发的轻量级域名查询系统,面向需要在Linux主机上快速搭建域名信息查询服务的站长与开发者,尤其适合具备基础PHP环境配置能力的技术人员使用。资源包为rar压缩格式,整体约372KB&#xff0c…

2026/10/17 4:53:15 阅读更多 →

最新新闻

IP-Guard部署避坑指南:从服务端拆分到文档加密策略全解析

IP-Guard部署避坑指南:从服务端拆分到文档加密策略全解析

简介:IP-guard是常见的终端安全管理软件,可对企业内网进行实时监控、上网行为审计及文件外发控制。其中提供了解除406用户数限制的部署版本,面向需要大规模接入终端的IT运维人员,在企业办公、呼叫中心、研发设计等场景中尤其适用&…

2026/10/17 5:41:29 阅读更多 →
华为三层交换机VLAN间通信配置与排障全指南

华为三层交换机VLAN间通信配置与排障全指南

1. 为什么三层交换机不是“高级二层设备”,而是网络架构的转折点很多人第一次看到“华为利用三层设备实现VLAN间通信”这个标题时,下意识会想:“不就是配个IP地址、开个路由功能吗?跟路由器有啥区别?”——这恰恰是我在…

2026/10/17 5:41:29 阅读更多 →
多Agent系统设计核心:任务解耦、确定性调度与四层架构

多Agent系统设计核心:任务解耦、确定性调度与四层架构

1. 这不是“多个AI凑在一起”——大模型多Agent系统的真实面貌很多人第一次听说“多Agent”时,脑子里浮现的是几个聊天窗口并排开着,一个写大纲、一个查文献、一个润色句子——看起来热闹,但实际运行起来卡顿、重复、互相覆盖结论&#xff0c…

2026/10/17 5:41:28 阅读更多 →
npm不是内部或外部命令:从环境变量到Node环境的完整修复指南

npm不是内部或外部命令:从环境变量到Node环境的完整修复指南

前段时间帮朋友排查一个报错,他主持一个基于某开源中后台管理框架改写的系统,后端是 Java,前端是 Vue,前后端分离开发。按理说这个工作流很成熟:后端起个服务,前端目录下执行npm install,然后np…

2026/10/17 5:41:28 阅读更多 →
ViT原理与实战:从Patch Embedding到微调技巧全解析

ViT原理与实战:从Patch Embedding到微调技巧全解析

1. 为什么ViT能成为视觉领域的分水岭过去这几年,做计算机视觉的人很难绕开一个名字:ViT,也就是Visual Transformer。我第一次看到这个模型时,第一反应是"Transformer不是在自然语言处理那边跑得好好的吗,怎么突然…

2026/10/17 5:41:28 阅读更多 →
Codex+VS Code构建可审计的AI Coding工程化实践

Codex+VS Code构建可审计的AI Coding工程化实践

1. 项目概述:这不是又一个“AI写代码”的演示,而是真实开发流里的生存实验“AI Coding 实践(再续)”——这个标题里最值得咀嚼的不是“AI”,也不是“Coding”,而是那个轻描淡写的“再续”。它意味着前序实践…

2026/10/17 5:40:28 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →