在sql编码注入里,最常见的编码注入是MySQL宽字节以及urldecode/rawurldecode函数导致的。
一、宽字节注入
在使用PHP连接mysql的时候,设置了“set character_set_client=gbk”,告诉MySQL服务器客户端来源数据编码是GBK,然后服务器对SQL查询语句进行GBK转码,导致当注入参数里带入%df%27时,可将程序中过滤的\(5c)吃掉。简单的例子如下:
假如http://www.a.com/a.php?id=1里面的id参数存在宽字节注入漏洞,
当我们提交http://www.a.com/a.php?id=1' and 1=1%23时,执行的SQL语句为:
select * from user where id='1\' and 1=1#'
此时提交的单引号被转义导致注入失败;
当我们提交http://www.a.com/a.php?id=1%df' and 1=1%23时,执行的SQL语句为:
select * from user where id='1運' and 1=1#'
此时提交的%df'被转义为%df\',而%df\也就是%df%5c,共同组成了“運”字,保留了单引号,进而闭合了前面的单引号,注入成功。
我们常见的都不是直接设置set character_set_client=gbk,而是SET NAMES gbk,这同样是存在漏洞的,SET NAMES gbk其实干了三件事,等同于:
SET character_set_sonnection='gbk', character_set_results='gbk', character_set_client='gbk'
关于这个漏洞的解决方法推荐如下三种:
1.使用mysql_set_charset('gbk')设置编码,然后使用mysql_real_escape_string()函数对参数过滤。
2.在执行查询之前先执行SET NAMES 'gbk',然后character_set_client=binary设置character_set_client为binary。
3.使用PDO方式,在PHP5.3.6及以下版本需要设置setAttribute(PDO::ATTR_EMULATE_PREPARES, false);来禁用prepared statements的仿真效果。
二、二次urldecode注入
现在的web程序大多都是会进行参数过滤,通常使用addslashes()、mysql_real_escape_string()、mysql_escape_string()函数或者开启GPC的方式来防止注入,也就是给单引号(')、双引号('')、反斜杠(\)和NULL加上反斜杠进行转义。如果某处使用了urldecode或者rawurldecode函数,则会导致二次解码生成单引号引起注入。
例如:当我们提交http//www.a.com/a.php?id=1%2527时,如果开启了GPC等,web服务器会自动解码一次,由于%25解码的结果为%,所以变成了http//www.a.com/a.php?id=1%27,如果程序里面使用了urldecode或者rawurldecode函数,则又会进行第二次解码,结果为http//www.a.com/a.php?id=1',成功注入。
测试代码:
<?php
$a=addslashes($_GET['id']);
$b=urldecode($a);
echo '$a='.$a;
echo '<br />';
echo '$b='.$b;
?>
测试结果: