【转】宽字节注入详解

摘要:
首先,宽字节注入与HTML页面编码无关。作者曾看到<元字符集=utf8>我放弃了尝试。这是一个错误。SQL注入不是XSS。互联网上的许多资料都说程序使用宽字节来处理程序,但它们没有指定程序是什么。宽字节GB2312、GBK、GB18030、BIG5、Shift_JIS等通常被称为宽字节。实际上,只有两个字节。宽字节造成的安全问题主要是吃ASCII字符(一个字节)的现象。
前言

在mysql中,用于转义的函数有addslashes,mysql_real_escape_string,mysql_escape_string等,还有一种情况是magic_quote_gpc,不过高版本的PHP将去除这个特性。

首先,宽字节注入与HTML页面编码是无关的,笔者曾经看到

<meta charset=utf8>

就放弃了尝试,这是一个误区,SQL注入不是XSS。虽然他们中编码的成因相似,不过发生的地点不同。

很多网上的材料都说程序使用了宽字节来处理程序,却又不指出具体是指什么程序。本文就介绍一下具体漏洞发生的原理与简单的利用。在这里我们限定使用的语言是PHP5.4,数据库MYSQL5.6。

涉及到的一些概念

字符、字符集与字符序

字符(character)是组成字符集(character set)的基本单位。对字符赋予一个数值(encoding)来确定这个字符在该字符集中的位置。

字符序(collation)指同一字符集内字符间的比较规则。

UTF8

由于ASCII表示的字符只有128个,因此网络世界的规范是使用UNICODE编码,但是用ASCII表示的字符使用UNICODE并不高效。因此出现了中间格式字符集,被称为通用转换格式,及UTF(Universal Transformation Format)。

宽字节

GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象。

MYSQL的字符集转换过程

1. MySQL Server收到请求时将请求数据从character_set_client转换为character_set_connection;

2. 进行内部操作前将请求数据从character_set_connection转换为内部操作字符集,其确定方法如下:

• 使用每个数据字段的CHARACTER SET设定值;

• 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);

• 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

• 若上述值不存在,则使用character_set_server设定值。

  1. 将操作结果从内部操作字符集转换为character_set_results。

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

PHP测试代码:

<!DOCTYPE html>
 
<meta charset="gbk"><!--仅用于基础的显示,换成utf8也行就是不好看-->
 
<?php 
 
error_reporting(0);
 
$conn = mysql_connect('127.0.0.1','root',''); 
 
mysql_select_db('mysql',$conn);
 
mysql_query("set names gbk");  //不安全的编码设置方式
 
$res = mysql_query("show variables like 'character%';"); //显示当前数据库设置的各项字符集
 
while($row = mysql_fetch_array($res)){
 
var_dump($row);
 
}
 
$user = addslashes($_GET['sql']); //mysql_real_escape_string() magic_quote_gpc=On addslashes() mysql_escape_string()功能类似
 
$sql = "SELECT host,user,password FROM user WHERE user='{$user}'"; 
 
echo $sql.'</br>';
 
if($res = mysql_query($sql)){ 
 
while($row = mysql_fetch_array($res)){
 
var_dump($row);
 
}
 
} 
 
else{ 
 
echo "Error".mysql_error()."<br/>"; 
 
} 
 
?>
http://localhost/xl.php?sql=root%df%27%20or%201=1%23

是可以执行成功的!

【转】宽字节注入详解第1张

URL解码sql=rootß’ or 1=1#

解析过程:

$_GET[‘sql’] 经过 addslashes编码之后带入了‘’
 
1、root%df%5C%27%20or%201=1%23
 
2、带入mysql处理时使用了gbk字符集
 
%df%5c -> 運 成功的吃掉了%5c
 
 
%27 -> ‘ 单引号成功闭合

执行了插入的sql语句。

怎么吃的:

GBK编码,它的编码范围是0x8140~0xFEFE(不包括xx7F),在遇到%df(ascii(223)) >ascii(128)时自动拼接%5c,因此吃掉‘’,而%27、%20小于ascii(128)的字符就保留了。

补充:

GB2312是被GBK兼容的,它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE(0x5C不在该范围内),因此不能使用编码吃掉%5c。

其它的宽字符集也是一样的分析过程,要吃掉%5c,只需要低位中包含正常的0x5c就行了。

安全过滤

上文中代码使用了mysql_query(“set names gbk”)来设置编码,其实在mysql中是推荐mysql_set_charset(“gbk”);函数来进行编码设置的,这两个函数大致的功能相似,唯一不同之处是后者会修改mysql对象中的mysql->charset属性为设置的字符集。

同时配套的过滤函数为mysql_real_escape_string()。上面代码中列出了几个过滤的函数,他们之间的区别就是mysql_real_escape_string()会根据mysql对象中的mysql->charset属性来对待传入的字符串,因此可以根据当前字符集来进行过滤。

具体差别可参考:http://www.laruence.com/2010/04/12/1396.html

同理可得

由上文可得宽字节注入是由于转编码而形成的,那具有转编码功能的函数也成了漏洞的成因。

转码函数

mb_convert_encoding()

iconv()

 以下用iconv()来演示,修改上面的代码:

<!DOCTYPE html>
 
<meta charset="gbk">
 
<?php 
 
error_reporting(0);
 
$conn = mysql_connect('127.0.0.1','root',''); 
 
mysql_select_db('mysql',$conn);
 
mysql_set_charset("utf8"); //推荐的安全编码
 
$user = mysql_real_escape_string(($_GET['sql'])); //推荐的过滤函数
 
$user = iconv('GBK', 'UTF-8',$user);
 
$sql = "SELECT host,user,password FROM user WHERE user='{$user}'"; 
 
echo $sql.'</br>';
 
$res = mysql_query($sql);
 
while($row = mysql_fetch_array($res)){
 
var_dump($row);
 
}
 
?>

【转】宽字节注入详解第2张

http://localhost/xl.php?sql=root%e5%27or%201=1%23

同样可以执行成功,编码解析的过程依然如上。

总结一下漏洞成因:

代码一

1、使用了不安全的字符集设置函数与过滤函数。

2、漏洞发生在PHP请求mysql时使用character_set_client值进行一次转码。

代码二

1、使用了推荐的设置函数与过滤函数。

2、解析错误发生在iconv()函数转码时,GBK转向UTF8吃掉了“”

3、PHP请求mysql时转码安全。

另外:

当改变编码方向时$user = iconv(‘UTF-8’, ‘gbk’,$user);

通过访问http://localhost/xl.php?sql=root%e9%8c%a6可以带入一个,进而注释掉单引号。

这种情况下需要两个参数来配合注入。

例如:

http://localhost/xl.php?sql=root%e9%8c%a6¶=%20or%201=1%23

【转】宽字节注入详解第3张

总结:

宽字节注入跟HTML页面编码无关。

Mysql编码与过滤函数推荐使用mysql_real_escape_string(),mysql_set_charset()。

转编码函数同样会引起宽字节注入,即使使用了安全的设置函数。

参考文献

mysql字符集的设置:http://www.laruence.com/2008/01/05/12.html

免责声明:文章转载自《【转】宽字节注入详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇树莓派设置固定IP地址nginx 获取源IP 获取经过N层Nginx转发的访问来源真实IP下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

三篇文章了解 TiDB 技术内幕——说计算

在这我们将关系模型简单理解为 Table 和 SQL 语句,那么问题变为如何在 KV 结构上保存 Table 以及如何在 KV 结构上运行 SQL 语句。 假设我们有这样一个表的定义: CREATE TABLE User { ID int, Name varchar(20), Role varchar(20), Age int, PRIMARY KEY (...

linux mysql 查看默认端口号和修改端口号

如何查看mysql默认端口号和修改端口号2015-03-1917:42:18 1.登录mysql [root@test/]#mysql-uroot-p Enterpassword: 2.使用命令showglobalvariableslike'port';查看端口号 mysql>showglobalvariableslike'port'...

Centos6安装MySQL5.7(yum方式)

1. 下载并安装用来配置mysql的yum源的rpm包 # 下载 wget http://repo.mysql.com/mysql57-community-release-el6-10.noarch.rpm # 安装 yum -y localinstall mysql57-community-release-el6-10.noarch.rpm #...

Java实现文件复制的四种方式

背景:有很多的Java初学者对于文件复制的操作总是搞不懂,下面我将用4中方式实现指定文件的复制。 实现方式一:使用FileInputStream/FileOutputStream字节流进行文件的复制操作 1 private static void streamCopyFile(File srcFile, File desFile) throwsIOExce...

备份与恢复概述,冷备,热备

对于DBA来说,最基本的工作就是数据库的备份与恢复,在意外情况下(如服务器宕机、磁盘损坏等)要保证数据不丢失,或者是最小程度地丢失。每个DBA应该每时每刻都关心自己所负责的数据库的备份情况。MySQL数据库提供的大多数工具(如mysqldump、ibbackup、replication)都能很好地完成备份的工作,当然也可以通过第三方的一些工具来完成,如xt...

mysql日志文件开启及详解:General_log 和 Binlog

General_log 详解 1.介绍 开启 general log 将所有到达MySQL Server的SQL语句记录下来。 一般不会开启开功能,因为log的量会非常庞大。但个别情况下可能会临时的开一会儿general log以供排障使用。相关参数一共有3:general_log、log_output、general_log_file show var...