当前位置: 首页 > news >正文

从CTF实战解析SQL注入:绕过过滤与联合查询攻防

1. 从一道经典CTF题看SQL注入的攻防本质

最近在整理一些老的CTF题目,发现[gxyctf2019]babysqli这道题虽然名字叫“baby”,但里面涉及到的绕过技巧和思考过程,恰恰是理解SQL注入攻防核心的绝佳材料。很多刚入门安全的朋友,一提到SQL注入,可能立刻想到的是‘ or 1=1 --这种“万能密码”,但在实际环境,尤其是CTF比赛中,防御措施往往会让这种简单攻击失效。这道题就模拟了这样一种场景:开发者已经做了一些基础的过滤,但过滤得并不彻底,留下了我们可以利用的“缝隙”。今天,我就带大家完整复盘这道题的解题思路,不仅告诉你答案,更重要的是拆解每一步背后的原理和思考逻辑,让你真正掌握这种“缝隙”中寻找机会的能力。

这道题的目标很明确:通过一个存在漏洞的登录框,获取数据库中的敏感信息(也就是flag)。题目名字叫“babysqli”,暗示它可能有一些基础的过滤,但并非无懈可击。我们解题的过程,本质上就是一场与开发者过滤逻辑的博弈。你需要像侦探一样,从有限的交互中,推测出后端代码可能的样子,然后设计出能够绕过其防御的“Payload”。接下来,我们就一步步拆解这个博弈过程。

2. 初探与信息收集:理解战场环境

任何实战攻击的第一步都是信息收集,CTF也不例外。面对一个登录框,我们首先要做的就是试探它的行为边界和过滤规则。

2.1 基础试探与错误回显分析

我首先尝试了最经典的测试Payload:在用户名或密码字段输入一个单引号。输入admin‘并提交后,页面返回了一个SQL语法错误。这个错误信息本身就是第一个重要情报。它直接告诉我们两个关键点:第一,后端确实直接将用户输入拼接到了SQL语句中,存在注入漏洞;第二,网站开启了错误回显,这意味着我们可以通过错误信息来获取数据库的详细内容,这通常被称为“报错注入”。

注意:在生产环境中,开启详细的数据库错误回显是极度危险的做法,因为它会为攻击者提供大量信息。CTF题目中设置错误回显,是为了降低难度,引导我们使用报错注入技术。

得到错误回显后,我尝试了‘ or 1=1 --这个经典Payload,期望能直接绕过登录。但这次,登录失败了,页面没有返回错误,而是像处理了正常错误密码一样。这立刻引起了我的警觉。这说明,开发者很可能对orand--(注释符)等关键词进行了过滤或处理。我的初步假设是:后端可能使用str_replacepreg_replace之类的函数,将这些关键词替换为空字符串或进行了其他处理。

2.2 关键词过滤的验证与绕过思路初现

为了验证过滤规则,我设计了一系列测试:

  1. admin‘ or ‘1‘=‘1:如果or被过滤,这个语句会变成admin‘ ‘1‘=‘1,语法错误。
  2. admin‘ and ‘1‘=‘1:测试and是否被过滤。
  3. admin‘ --:测试注释符是否被过滤。

测试发现,使用or--时,行为异常,而使用and时,有时能引发语法错误。这暗示过滤可能不是简单的删除,或者删除后产生了新的组合。一个更可靠的测试方法是使用双写绕过。我尝试了admin‘ oorr ‘1‘=‘1。如果过滤函数只执行一次,将or替换为空,那么oorr中间的or被删除后,剩下的or又会拼接起来,从而绕过过滤。但在这个题目里,双写绕过并未成功。

这时,我转换思路。既然常见的逻辑运算符和注释符可能被干扰,那么有没有不依赖它们的方法呢?答案是肯定的。这就是“联合查询注入”(Union Injection)登场的时候。联合查询的核心是使用UNIONUNION ALL操作符,将我们精心构造的查询结果,拼接到原始查询的结果集后面。只要字段数匹配,我们就能让数据库返回我们想要的数据,而不是执行原本的登录逻辑。

3. 核心攻击链构建:字段数探测与联合查询

确定了使用联合查询的思路后,我们需要解决两个技术问题:第一,原始查询语句到底查询了几个字段?第二,我们如何确定哪些字段的回显位置是可见的?

3.1 使用ORDER BY精确探测字段数

ORDER BY子句用于根据指定列索引对结果集排序。如果ORDER BY 5表示按第5列排序,而查询结果只有3列,数据库就会报错。我们可以利用这个特性来精确探测字段数。

我从ORDER BY 1开始尝试,逐渐增加数字:

  • admin‘ order by 1 --:正常(假设过滤存在,我们先按此逻辑思考)
  • admin‘ order by 2 --:正常
  • admin‘ order by 3 --:正常
  • admin‘ order by 4 --:报错!

这个过程说明,原始的SELECT语句查询了3个字段。这是一个至关重要的信息,因为我们的UNION SELECT语句也必须跟上相同数量的字段,否则会因字段数不匹配而语法错误。

实操心得:在实际测试中,如果order by也被过滤,可以尝试用group by替代,原理类似。也可以使用union select null,null,null...不断递增null的个数,直到页面返回正常(不报错)来确定字段数。null兼容所有数据类型,是最安全的占位符。

3.2 构造联合查询并定位回显点

知道字段数是3后,我就可以构造联合查询了。首先,我需要让原始查询的前半部分结果为空,这样页面上显示的就全是我们UNION后面的结果。通常,可以构造一个必然为假的条件,例如:‘ and 1=2 union select 1,2,3 --。但这里and--可能被过滤,所以需要调整。

我尝试了:admin‘ union select 1,2,3‘。这里我故意在第三个字段后加了一个单引号,目的是闭合原SQL语句中可能存在的后续引号,并让后面的内容成为注释或多余部分(可能引发错误,但有时也能执行)。经过多次测试和观察页面回显,我发现输入admin‘ union select 1,2,3时,页面发生了变化,原本登录错误的地方,显示了数字23

这是一个里程碑式的发现!它意味着:

  1. 我的UNION SELECT语句成功执行了。
  2. 页面模板会将其查询结果的第2和第3列的内容显示出来。第1列的内容可能用于其他逻辑(如用户ID判断)而未直接显示。
  3. 数字23的位置,就是我们可以用来输出数据库信息(如表名、列名、数据)的“回显点”。

4. 信息提取:从数据库结构到最终Flag

有了可用的回显点,接下来的过程就是标准的SQL注入信息提取流程,但每一步都需要考虑题目可能存在的过滤。

4.1 获取数据库名与表名

在MySQL中,database()函数返回当前数据库名,group_concat(table_name)可以从information_schema.tables中聚合所有表名。

我构造了如下Payload,将数据库名放在回显点2,表名放在回显点3:admin‘ union select 1, database(), group_concat(table_name) from information_schema.tables where table_schema=database()‘

执行后,在页面的回显位置,我看到了:

  • 位置2(数据库名):babysqli
  • 位置3(表名):news, users, flag

目标非常清晰了!数据库里有一个名为flag的表,这极大概率就是我们的目标。

4.2 获取目标表的结构(列名)

下一步是查看flag表有哪些列。这需要查询information_schema.columns

Payload如下:admin‘ union select 1,2, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=‘flag‘

这里有一个关键点:‘flag‘这个字符串常量。如果题目过滤了单引号,这个Payload就会失效。幸运的是,这道题没有过滤单引号。如果遇到过滤,我们可以使用十六进制编码绕过,比如‘flag‘的十六进制是0x666c6167,那么Payload可以写成...table_name=0x666c6167

执行后,在回显点3看到了列名:flag。果然,这个表只有一列,列名就是flag

4.3 最终提取Flag数据

最后一步,直接从flag表查询flag列的数据。

Payload:admin‘ union select 1,2, flag from flag‘

执行后,在页面的回显点3,成功获取到了最终的Flag字符串,格式通常类似flag{xxxx-xxxx-xxxx}

5. 深度复盘:过滤逻辑推测与高级绕过探讨

解题之后,我们回过头来尝试推测一下题目后端的过滤逻辑。根据我们测试时or 1=1失败而union select成功的情况,一个合理的推测是:开发者可能只对orand--#登录绕过常用的关键词进行了过滤(例如替换为空),但对unionselectfromwhere信息查询常用的关键词却疏于防范。这是一种典型的“不完全防护”,以为防住了万能密码就万事大吉,却留下了更危险的信息泄露漏洞。

如果这是一道更难的题目,可能会设置以下障碍,我们也有相应的绕过思路:

  1. 过滤unionselect:可以使用大小写混淆UnIoN SeLeCt,或者使用双写ununionion seselectlect(如果过滤函数只执行一次)。更高级的可以用||(连接符)或&&配合子查询。
  2. 过滤空格:可以使用注释符/**/代替空格,如union/**/select/**/1,2,3。Tab符%09、换行符%0a有时也能奏效。
  3. 过滤单引号:对于字符串,可以使用十六进制编码,如‘flag‘变为0x666c6167。对于数字,则无需引号。
  4. 完全关闭错误回显:这时报错注入就失效了。我们需要转向“盲注”(Blind SQLi)。通过构造逻辑判断,根据页面返回内容的不同(真/假、时间延迟)来逐位推测数据。例如,admin‘ and if(ascii(substr(database(),1,1))>100, sleep(2), 1) --,如果页面响应延迟2秒,说明数据库名第一个字符的ASCII码大于100。

6. 防御视角:开发者该如何避免此类问题?

作为开发者,从这道题能学到什么?仅仅过滤几个关键词是远远不够的。根本的解决方案是:

  1. 使用参数化查询(预编译语句):这是最有效、最根本的防御手段。让SQL语句的“骨架”和“数据”完全分离,用户输入永远只被当作数据处理,无法改变语句结构。在PHP中可以使用PDO或MySQLi的预处理功能。
  2. 最小权限原则:给Web应用数据库账户分配最小的、必要的权限。比如,只授予查询权限,不授予删除、修改表结构的权限。
  3. 关闭错误回显:在生产环境中,务必关闭数据库详细错误信息的前端展示,使用统一的、模糊的错误页面。
  4. Web应用防火墙(WAF):部署WAF可以帮助过滤和拦截常见的攻击Payload,但不应作为唯一防线。
  5. 定期安全审计与代码扫描:对代码进行人工审计或使用自动化工具扫描,及时发现潜在的注入点。

[gxyctf2019]babysqli这道题,就像它的名字一样,是一个引导初学者深入理解SQL注入的“婴儿步”。它从简单的报错注入入手,引导你思考过滤与绕过,实践联合查询的完整流程。真正掌握它,不在于记住最终的Payload,而在于理解每一步试探背后的原因,以及当某条路被堵死时,如何灵活地寻找另一条通路。这种在限制条件下寻找解决方案的思维,才是网络安全研究和CTF竞赛中最宝贵的收获。下次当你再遇到一个登录框,希望你能像解这道题一样,系统地观察、假设、测试、验证,而不仅仅是机械地输入几个所谓的“万能”Payload。

http://www.jsqmd.com/news/1083997/

相关文章:

  • 2025年网盘直链下载工具深度解析:LinkSwift如何提升你的下载体验
  • XSS攻击全解析:从原理到防御的Web安全实战指南
  • 6月24日豆包上线专业版!办公任务模式实测惊艳,2亿用户开启AI普惠办公新时代
  • 天行健与优胜劣汰:两种文明范式的哲学比较及其现代启示
  • Java基础进阶:位运算体系与字符串底层原理全解析
  • 如何让老旧Mac焕发新生?OpenCore Legacy Patcher终极指南
  • n8n表达式注入漏洞CVE-2025-68613:从原理到RCE的深度剖析与防御
  • 国产化视频会议安全加密:从国密算法到端到端加密的实战解析
  • 版权知识小科普:这些你一定要知道
  • 大模型微调算力选型:8 路 RTX 5090 服务器与单张 A100 80GB 性能、显存、成本场景对比
  • AI算力行情轮到玻璃基板,巨头布局加速商业化,量产还有哪些难关?
  • 北京时间与不同时区时间:来历、介绍与用途
  • 微信私域如何告别“拍脑袋决策”?从 WecomApi 拆解大规模 A/B 测试与增长实验中台架构
  • XXE漏洞深度解析:原理、利用与多语言防御实战
  • 实战指南:解锁Joy-Con手柄自定义功能的完整工具包
  • 文件上传漏洞攻防实战:从绕过检测到Webshell获取
  • 天河应用大讲堂 | 基于人工智能的天气预报技术发展趋势
  • LSR包胶技术深度解析:金属包胶、塑料包胶到底怎么做?
  • 打通企微接口,构建适配 GEO 检索规则的结构化素材库
  • 100个RPG Maker MV插件:零代码打造专业级游戏体验
  • OpenAI 9 个月自研芯片 Jalapeño,推理成本砍半,ChatGPT 体验将大升级!
  • 自动整形设备中的接近开关:让变形件回到标准位置
  • 从安装到调优,Strix Halo 本地大模型一周使用实录
  • C++跨平台(一):开发概述与策略选择
  • 终极指南:如何用ExtractorSharp高效编辑NPK游戏资源文件
  • 【Springboot毕设全套源码+文档】基于SpringBoot+Vue的学生交流互助平台的设计与实现(丰富项目+远程调试+讲解+定制)
  • 揭秘Wireshark:为什么它是全球第一的开源抓包工具?
  • 关于原客户业务部、产品管理部及生产厂人员划转的通知
  • 解决JSch SSH密钥格式不兼容:使用ssh-keygen生成PEM格式RSA密钥
  • Cesium 水波材质教程