宽字节注入漏洞成因与防护

参考链接:

(1)漏洞银行 [3期]浅析宽字节注入

https://www.bugbank.cn/live/view.html?id=109301

(2)大部分来自于SQL注入:宽字节注入(GBK双字节绕过)这篇文章,仅仅用于个人思路梳理与总结。https://lyiang.wordpress.com/2015/06/09/sql%E6%B3%A8%E5%85%A5%EF%BC%9A%E5%AE%BD%E5%AD%97%E8%8A%82%E6%B3%A8%E5%85%A5%EF%BC%88gbk%E5%8F%8C%E5%AD%97%E8%8A%82%E7%BB%95%E8%BF%87%EF%BC%89/

一、漏洞原因

宽字节注入的方法很简单,就是编码。

GBK编码导致宽字节注入漏洞。GBK编码是数据库编码,跟前台的编码无关。

GBK双字节编码:一个汉字用两个字节表示,首字节对应0x81-0xFE,尾字节对应0x40-0xFE(除0x7F),刚好涵盖了对应的编码0x5C。

构造如下语句进行sql注入。

?id=1%df' union select 1,user(),concat(name,0x7e,pass) from admin %23

等同于

?id=1%df%27 union select 1,user(),concat(name,0x7e,pass) from admin %23

这样的话id的参数传入代码层,就会在’前加一个\,由于采用的URL编码,所以
产生的效果是%df%5c%27

二、基本解释

因为%df的关系,\的编码%5c被吃掉了,也就失去了转义的效果,直接被带入到mysql中,然后
mysql在解读时无视了%df%5c形成的新字节,那么单引号便重新发挥了效果

其中%5c表示\,即转义符号。

%27表示’的url编码。

%23为#,代表注释。

三、分析过程

假设一个URL存在注入但是有addslashes,mysql_real_escape_string,mysql_escape_string等等函数实现转义就比如如下代码:

function check_addslashes($string)

{

 $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash

 $string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash

 $string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash


 return $string;

}

定义了一个过滤函数,然后使用它:

if(isset($_GET['id']))

{

$id=check_addslashes($_GET['id']);


mysql_query("SET NAMES gbk");

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

$result=mysql_query($sql);

$row = mysql_fetch_array($result);

这儿形成的URL应该是:

http://www.xxx.com/index.php?id=1

我们在后边这么构造URL:

http://www.xxx.com/index.php?id=1%df'and 1=2 union select 1,2,3%23

这样的话id的参数传入代码层,就会在’前加一个\,由于采用的URL编码,所以产生的效果是

%df%5c%27

关键就在这,%df会吃掉%5c,形成一个新的字节,举个例子就是%df遇到%5c会把%5c吃掉,形成%df%5c,这个编码经过代码解码后会形成一个汉字“運”

那么真正的原因是什么?

GBK双字节注入到底是怎么来的呢?

宽字节注入发生的位置就是PHP发送请求到MYSQL时字符集使用character_set_client设置值进行了一次编码。

http://www.xxx.com/index.php?id=1%df'and 1=2 union select 1,user(),3%23

按照这个参数,我们在页面输出$sql,看看
最终传入到mysql中的语句构造

SELECT * FROM users WHERE id='1運' and 1=2 union select 1,user(),3#' LIMIT 0,1

我们可以看到,单引号前并没有\,而是多了一个汉字運

那么这句
传入到mysql中运行的结果
是什么呢?
在这里插入图片描述
输出了user()

我们
追踪数据的变化过程

%df%27===>(addslashes)=== >%df%5c%27===>(GBK)====>運’

用户输入==>过滤函数==>代码层的$sql==>mysql处理请求==>mysql中的sql

mysql_query("SET NAMES gbk");

当这行代码在代码层被写入时,三个字符集(客户端、连接层、结果集)都是GBK编码。

那么便会发生如上的情况。

四、安全方案

对于宽字节编码,有一种最好的修补就是:

(1)使用mysql_set_charset(GBK)指定字符集

(2)使用mysql_real_escape_string进行转义

原理是,mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集,不会出现前面e5和5c拼接为一个宽字节的问题,但是这个“当前字符集”如何确定呢?

就是使用mysql_set_charset进行指定。

scape_string进行转义

原理是,mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集,不会出现前面e5和5c拼接为一个宽字节的问题,但是这个“当前字符集”如何确定呢?

就是使用mysql_set_charset进行指定。

上述的
两个条件是“与”运算的关系
少一条都不行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值