博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SQL注入防御绕过——宽字节注入
阅读量:5244 次
发布时间:2019-06-14

本文共 3134 字,大约阅读时间需要 10 分钟。

01 背景知识

字符集

在了解宽字节注入之前,我们先来看一看字符集是什么。字符集也叫字符编码,是一种将符号转换为二进制数的映射关系。

几种常见的字符集:

  • ASCII编码:单字节编码
  • latin1编码:单字节编码
  • gbk编码:使用一字节和双字节编码,0x00-0x7F范围内是一位,和 ASCII 保持一致。双字节的第一字节范围是0x81-0xFE
  • UTF-8编码:使用一至四字节编码,0x00–0x7F范围内是一位,和 ASCII 保持一致。其它字符用二至四个字节变长表示。

宽字节就是两个以上的字节,宽字节注入产生的原因就是各种字符编码的不当操作,使得攻击者可以通过宽字节编码绕过SQL注入防御。

MySQL字符转换

数据提交到MySQL数据库,需要进行字符集的转换,使得MySQL数据库可以对数据进行处理,这一过程一般有以下三个步骤:

  1. 收到请求,将请求数据从 character_set_client ->character_set_connection
  2. 内部操作,将数据从character_set_connection-> 表创建的字符集
  3. 结果输出,将数据从表创建的字符集 -> character_set_results

当执行set names "charset",相当于执行

set character_set_client = charset
set character_set_connection = charset
set character_set_results = charset

client 指的是PHP程序

connection 指的是PHP客户端与MySQL服务器之间连接层
results 指的是MySQL服务器返回给PHP客户端的结果

MySQL常见的乱码问题就是这三个字符集的设置不当所引起的。

02 宽字节注入

这里的演示环境为 sqli-labs\Less-32

"; //logging the connection parameters to a file for analysis. $fp=fopen('result.txt','a'); fwrite($fp,'ID:'.$id."\n"); fclose($fp); // connectivity mysql_query("SET NAMES gbk"); $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result); if($row) { echo ''; echo 'Your Login name:'. $row['username']; echo "
"; echo 'Your Password:' .$row['password']; echo "
"; } else { echo ''; print_r(mysql_error()); echo ""; } } else { echo "Please input the ID as parameter with numeric value";} ?>

普通注入

当用户提交

http://127.0.0.1/Less-32/?id=1'
此时,发生如下转换
第一步:'check_addslashes 函数转义为 \'

第二步:在执行sql查询之前,也即\'代入MySQL服务器之前,mysql_query("SET NAMES gbk");将MySQL的三个字符集设置为 gbk 编码

第三步:character_set_client告诉MySQL Server,传入的是gbk编码,也就是\'被当做了%5C%27传入

第四步:character_set_client -> character_set_connection编码完全一致,数据没有做任何转换,所以输入是%5C%27,输出的是%5C%27

第五步:character_set_connection-> table charset这里我们需要关注下所使用的表的字符集

 
table_charset

 

可以看到id参数没有设置编码方式,不会对%5C%27进行处理。在这里MySQL服务器将查询语句执行,并返回结果。

执行的SQL语句为:
$sql="SELECT * FROM users WHERE id='1\'' LIMIT 0,1";
'被转义无法进行注入

第六步:table charset -> character_set_results由于character_set_results字符集也设定为 gbk ,保证了输出内容没有乱码。

通过上面的分析,我们发现用户提交的数据实际上只被处理了两次,一次是check_addslashes对危险字符的处理,另一次是gbk编码。所以,我们可以将以上步骤简化为:

数据 ==== (check_addslashes)====XXX====(GBK)====代入数据库执行的内容

宽字节注入

提交:

http://127.0.0.1/Less-32/?id=1%df'('浏览器自动进行url编码%27)
根据以上分析,发生如下转换:
%df%27====>(check_addslashes)====>%df%5c%27====>(GBK)====>運'
MySQL执行的语句为:
$sql="SELECT * FROM users WHERE id='1運'' LIMIT 0,1";成功将单引号闭合,可以进行SQL注入。

宽字节注入2.0

为了避免漏洞,网站一般会设置UTF-8编码,然后进行转义过滤。但是由于一些不经意的字符集转换,又会导致漏洞。

使用set names UTF-8指定了UTF-8字符集,并且也使用转义函数进行转义。有时候,为了避免乱码,会将一些用户提交的GBK字符使用iconv函数先转为UTF-8,然后再拼接入SQL语句。

mysql_query(“set names UTF-8”) ;  $bar =iconv(“GBK”,”UTF-8”, addslashes($_GET[‘’bar])) ;

提交:

http://127.0.0.1/Less-32/?id=1%e5%5c%27
转换:(%e5%5c转为UTF-8为e9%8c%a6
%e5%5c%27====>(addslashes)====>%e5%5c%5c%5c%27====(iconv)====>%e9%8c%a6%5c%5c%27
可以看到,多出了一个%5c,将转义符(反斜杠)本身转义,使得后面的%27单引号发挥了作用

03 宽字节注入防御

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

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

(2)使用mysql_real_escape_string进行转义

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

就是使用mysql_set_charset进行指定。

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

<meta charset="utf-8">

测试;

 
1

输出:

 
 

转载于:https://www.cnblogs.com/fengshui/p/9266830.html

你可能感兴趣的文章
Soot生成代码控制流图
查看>>
linux 不同服务器之间复制文件
查看>>
类加载机制
查看>>
R作图系列-----ggplot2语法
查看>>
【转】MFC中用CFile读取和写入文件2
查看>>
使用python实现名字管理系统
查看>>
仿函数可配接性探讨
查看>>
黑马程序员:java基础学习——标示符、关键字、保留字、常量与变量
查看>>
zookeeper入门(3)-Zookeeper命令行操作
查看>>
按位与,按位或,按位异或,左移右移运算符
查看>>
php中遇到include_path='.;C:\php5\pear'的错误
查看>>
MarkdownPad注册码
查看>>
再谈javascript图片预加载技术
查看>>
[转载]Bloom filter 以及[转载]中文详解
查看>>
css reset
查看>>
三栏布局-两边固定,中间自适应,中间层优先显示
查看>>
Linux "历史"命令
查看>>
.NET题目(收集来自网络)
查看>>
PHP字符串处理和时间格式化整理
查看>>
回文素数
查看>>