SQL注入--宽字节注入

一.基本概念

1.字符编码

  • 原因:计算机中的一切计算都是用二进制进行的,早期操作计算机需要学会二进制,学习和操作成本比较大,为了更容易的操作计算机,专家们想将人们容易理解的数字、字母、常用符号等引入计算机,这就需要设置一个固定的二进制来代表这些字符。
  • 需求:具体用哪个二进制表示哪个符号,当然每个团体都可以约定自己的一套标准,这个标准就叫字符编码。

2.字符编码集

字符编码集(简称字符集),是各种符号(文字)与计算机二进制码之间对应关系的映射表

常见的字符编码

  1. ASCII
  2. Unicode
  3. GBK
  4. GB2312
  5. UTF8

3.常用编码介绍

1.ASCII 编码

ASCII码全称是“美国信息交换标准代码”,是一套用于显示英语和西欧语种的编码体系。它包含常用的英文字母、数字及一些特殊字符和控制符等共计128个字符,这128个符号只用了一个字节的后面七位,最前面的一位统一规定为0。是最通用的单字接编码系统,即一个字符对应一个唯一的ASCII码。

2.Unicode编码
  • 诉求:世界上有多种编码方法,同一个二进制数字可以被解释称不同的符号。因此,在打开一个文本文件时候,就必须知道它的编码方式,用错误的编码方式打开,就会出现乱码。

    • 假如,有一种编码,将世界上所有的符号都纳入其中,形成一种集合,每一种符号都给予独一无二的编码,那么乱码问题就不会存在了。因此,产生了Unicode编码,这是一种所有符号的编码。Unicode显然是一个巨大的集合,现在的规模可以容纳100多万个符号,每个符号的编码都不一样。

  • 缺陷:在Unicode庞大的字符集的优势下,还存在一个问题,比如一个汉字,“严”的Unicode是十六进制4e25,转成二进制足足有15位,也就是,这个符号需要2个字节,表示其他字符还存在3个字节或者更多。计算机怎么区别三个字节表示的是同一个符号而不是分开表示三个呢?如果Unicode统一规定,每个符号用3个字节表示,但是某些字母显然不需要3个,那么就浪费了空间,文本文件大小超出了很多,这显然是不合理的。直到UTF8字符编码出现了。

3.UTF8编码
  • 介绍:UTF8(8-bit Unicode Transformation Format)随着互联网的发展,强烈要求出现一种统一的编码方式。UTF8是Unicode的实现方式之一,也是最为常见的实现方式。UTF8的最大特点是,它是一种变长编码,可以使用1-4个字节表示一个符号,根据不同的符号来变化字节长度,用在网页上可以统一页面显示中文简体繁体及其它语言。

  • UTF8编码规则:

    1. 对于单字节的符号,字节的第一位设为0,后面的7位为这个符号的Unicode码。对于英文字母,UTF8编码和ASCII编码是相同的。
    2. 对于非单字节(假设字节长度为N)的符号,第一个字节的前N位都设为1,第N+1设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制,全部为这个符号的Unicode码。
  • PS:UTF8 规定1个英文字符用1个字节表示,1个中文字符用3个字节表示。

4.GBK编码

GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆和新加坡等地,1980年发布,支持汉字6763个和非汉字图形字符682个,每个汉字及符号以两个字节来表示。

GBK编码于1995年12月1日制订。采用两个字节编码方案,共收录汉字和图形符号21886个,它几乎完美支持汉字,因此经常会遇见GBK与Unicode的转换。

4.MySQL中的编码规则

二.宽字节注入

1.注入原理

一个GBK汉字占两个字节,每个字节有自己的取值范围,如果设置GBK编码后,遇到连续两个字节,都符合GBK取值范围,会自动解析为一个汉字。

Addslashes函数防止sql注入,将传入参数值进行转义。例如将 '转义为 \' ,这样我们在注入的时候闭合单引号就会变成 id='1\',这样会导致闭合失败从而注入失败。

  • 绕过方式:

    输入%df%27(%27解码后为单引号(')),本来会转义%27为 \' ,但 \ 遇上%df相当于%5c(%5c解码后为反斜杠())和%df相遇,两者会合起来被解析成一个汉字(運),这样变成 id='1運' ,在MYSQL中效果等同于 id= '1' ,因而成功绕过。


2.注入方法

  • 介绍:宽字节注入主要是源于程序员使用的数据库编码与PHP编码设置为不同的两个编码。如果PHP的编码为UTF-8,而 MySql的编码设置为了 SET NAMES 'gbk'​ 或是 SET character_set_client=gbk​ ,这样配置会引发编码转换从而导致的注入漏洞。

  • 具体示例:

    • 后端代码:

      mysql_query("SET NAMES gbk");#看到设置编码,说明可能存在宽字节注入
      $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
      $result=mysql_query($sql);
      $row = mysql_fetch_array($result);
      
    • 尝试普通注入:

      用户输入:1' or 1=1
      转义得到:1\' or 1=1
      实际执行语句:SELECT * FROM users WHERE id= '1\' or 1=1'

    • 宽字节注入:

      用户输入:1%df' or 1=1#
      转义后为: 1%df\' or 1=1#
      由于SET NAMES gbk后,属于gbk编码2字节的范围
      因此%df\成为一个字符:運
      执行语句:SELECT * FROM users WHERE id='1運' or 1=1#'

  • 传入URL

    http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,database(),version();%23
    
    • ​id=-1​:确保union左边的查询结果为空集。 确定显示位
  • 执行结果


  • PS:通过union操作符获取数据 --> 联合查询注入

3.防御措施

  1. addslashes() 函数转义 SQL 语句中使用的字符串中的特殊字符。

    • 受影响字符:

      • 单引号(')
      • 双引号(")
      • 反斜杠(\)
  2. mysql_real_escape_string()函数转义SQL语句中使用的字符串中的特殊字符。

    • 受影响字符:

      • \x00
      • \n
      • \r
      • \
      • '
      • "
      • \x1a
  3. 指定字符集,并进行转义

    (1)使用mysql_set_charset(GBK)指定字符集
    (2)使用mysql_real_escape_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、付费专栏及课程。

余额充值