SQL注入之宽字节注入

SQL注入之宽字节注入

0x01简介

SQL注入近几年来连续被OWASP当作十大漏洞中最最危险的漏洞而存在。无论是从数据库中获得敏感信息还是执行一系列的恶意操作甚至是直接获取整个数据库权限,都可能发生在一次小小的提交参数的过程中。为此大多数网站开始对于SQL注入做了一定的防御方法,最早有人提出,将用户提交的所有敏感字符进行过滤和转义,要么将提交参数中的敏感字符过滤掉后再提交给数据库,要么对那些敏感字符使用转义符号进行转义,使其丧失掉注入功能后再进行提交。但我们知道,如果不对源头进行处理,再怎么亡羊补牢也是无济于事。后来这些网站在面对黑客那些令人匪夷所思的Bypass技巧面前根本没有应对方法,最终无奈选择关闭。
本篇文章,美创安全实验室将给大家介绍一种当年绕过转义防御最好用的技巧即宽字节注入攻击。

0x02编码历史

一听到“宽字节注入”,那不可避免地就要提到有关字节编码方面的知识,所以在讲解注入原理之前,我们简单讲解一下有关编码的历史。

最早美国人决定用8个可以开合的晶体管来组成不同的状态,这些晶体管只有“亮”或“不亮”两种形态,也就是对应了二进制的0和1。而1个字节有8个比特位,可以组合成2^8=256种不同的方案,他们把编号从0开始的32种状态用在规定的特殊用途,这32个字符后来成为“控制码”;他们又把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号,而这96个字符也被称为”ASCII码”。

后来随着计算机不断发展,世界各国为了可以让计算机保存各国的文字,他们决定采用127号之后的空位来表示这些新的字母、符号,于是从第128字符到最后一个255字符被称为“扩展字符集”。

但是等到中国人民得到计算机时,已经没有多余的字节状态来存储汉字。于是国人自主研发,将127之后的字符全部去掉,并规定:一个小于127的字符意义与原来相同,若两个大于127的字符连在一起时,就表示一个汉字,这种方案被叫做“GB2312“。但中国的汉字实在太多GB2312已经无法满足,于是人们将规则放宽,规定只要第一个字节是大于127就固定表示这是一个汉字的开始,而不管后面跟的是不是扩展字符集的内容。这种方案也就是现在我们常用的“GBK”编码。

因为当时各国都有一套自己的编码标准,如果没有装其他国家的编码系统,就完全无法使用他国的语言,结果互相之间谁也不懂谁的编码,后来国际标准化组织ISO决定着手解决这个问题,他们废除了所有的地区性编码方案,并将字符的表示由原来的一个字节改成两个字节,也就是用16位来统一表示所有的字符,对于ASCII码这些半角字符,也从8位扩展到16位,也就是说他们的高8位永远是0。这一标准化方案也就是现在世界各国普遍使用的UNICODE编码。

0x03宽字节注入原理

所谓宽字节指的是类似于GB2312、GBK、BIG5等需要两个字节编码的字节,而宽字节带来的安全问题主要是“吃掉”ASCII字符的现象,即将两个ASCII字符误认为是一个宽字节字符。
在这里插入图片描述
以PHP和MYSQL为例,MySQL收到请求时将请求数据从character_set_client转换为character_set_connection;在进行内部操作前,将请求数据从character_set_connection转换为内部操作字符集,使用每个字段的character_set的值将操作结果从内部操作集转换为character_set_results。而宽字节注入发生的位置就是PHP将请求发送到MYSQL时字符集使用character_set_client设置值进行了一次编码。

如果PHP中编码为GBK,函数执行添加的是ASCII编码,MYSQL默认字符集是GBK等宽字节字符集就会发生宽字节注入的现象。
在这里插入图片描述
举例来说,如果在php为了防止SQL注入而使用了一些转义敏感字符的函数,类似于:addslashes()、mysql_real_escape_string()、mysql_escape_string()等。这些函数将敏感字符例如 ‘ ,转义成 \’ ,导致无法进行SQL注入。但如果在提交参数的时候在单引号前加上一个大于127的字符,比如 %df,那么提交的参数就变成了 %df’ ,php自动加上反斜杠将、转义变成 %df\’ ,再进一步变换成 %df%5c%27 ,再提交给MYSQL进行处理的时候问题来了,MYSQL要对接收到的数据进行编码,编码方式是GBK,所以他认为 %df%5c 是一个宽字符,而不是两个字符。也就是说 %df\’ = %df%5c%27 = 運’ 。
我们追踪一下数据变化的过程:
在这里插入图片描述
可以发现转义符号被%df给“吞掉”了,导致‘ 成功绕过转义限制,接下来就可以进行SQL注入了。

0x04漏洞复现

  1. 以php客户端为例,当用户输入数据后,会通过php的默认编码生成sql语句发送给MYSQL服务器,在php没有开启default_charset编码时,php的默认编码为空
    在这里插入图片描述
    此时php则会根据数据库中所使用的编码来自动确定自己使用哪种编码,在测试的时候可以输出strlen()对单个汉字的返回结果。如果输出值是3代表是UTF-8编码,输出是2代表是GBK编码。
    在这里插入图片描述

  2. 服务器在接收到请求后会把客户端编码的字符串转换成连接层编码字符串,也就是由character_set_client指定的值变成character_set_connection指定的值。也就是宽字节发生注入时的位置
    在这里插入图片描述

  3. 假设在php页面中,php使用了addslashes()函数,将用户提交的敏感字符例如单引号,双引号,斜杠等全部转义导致这些符号无法被SQL注入利用。但是通过阅读php代码可以发现,mysql_query(“SET NAMES gbk”);这一句,使三个字符集(客户端,连接层,结果集)都采用GBK编码。经过前面的介绍可以知道GBK是双字节,如果此时再使用了addslashes()函数,那么一定可以触发宽字节注入。
    在这里插入图片描述
    在这里插入图片描述

  4. 为了绕过对单引号的转义限制,我们利用宽字节编码的漏洞,即提交一个大于127号字符的十六进制表示加上我们提交的单引号,%cc‘。
    在这里插入图片描述
    可以发现%cc与转义符号\经过GBK编码后成为了一个汉字,从而导致单引号绕过转义的限制,注入到SQL语句中。

  5. 现在拥有了可以利用的单引号,接下来的SQL注入就变得简单了,例如要获得数据库的库名,版本信息,用户信息等敏感信息可以使用union联合查询如下:%cc’ union select database(),version(),user() --+
    在这里插入图片描述

  6. 利用sqlmap可以更轻易的进行SQL注入
    Python sqlmap.py -u “127.0.0.1/zsxq-sql/sql-WideByte.php?token=1 %df’” --dbs
    在这里插入图片描述

0x05防御方法

  1. 使用Mysql_set_charset(‘gbk’);指定字符集。
    防御宽字节注入,除了要进行更严格的过滤之外,还需要一个字符集的设置,SET character_set_connection=gbk,character_set_results=gbk,character_set_client=binary;

  2. 使用mysql_real_escape_string进行转义
    mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集(使用mysql_set_charset指定字符集),不会出现前面的df和5c拼接为一个宽字节的问题
    在这里插入图片描述

  3. 使用pdo方式,在Php 5.3.6及以下版本中需要设置setAttribute(PDO:ATTR_EMULATE_PREPARES,false); 来禁用preparcd statements 的仿真效果

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
宽字节注入是一种常见的 SQL 注入技术,它利用了一些编码方式对非 ASCII 字符进行编码的特点,从而绕过某些安全机制,达到执行恶意 SQL 语句的目的。 宽字节注入的原理是将非 ASCII 字符编码为多个 ASCII 字符,然后将这些 ASCII 字符作为参数传递给应用程序,应用程序在解析这些参数时,可能会将其视为多个独立的字符,从而绕过一些安全机制。 例如,假设我们有一个包含语句的 Web 应用程序: ``` SELECT * FROM users WHERE username='admin' AND password='123456'; ``` 如果我们想使用宽字节注入技术来执行恶意 SQL 语句,我们可以将输入的用户名编码为 UTF-8 格式,并在其后面添加一个宽字节(%u00),这样就可以绕过应用程序的安全机制,注入额外的 SQL 语句,例如: ``` SELECT * FROM users WHERE username='admin%u00' OR 1=1 -- ' AND password='123456'; ``` 在这个例子中,%u00 是一个宽字节,它将 'a' 编码为 '%61%00',这样在应用程序解析这个参数时,它会将其视为两个独立的字符:'a' 和 '\u00'。因此,应用程序将执行以下 SQL 语句: ``` SELECT * FROM users WHERE username='admin' OR 1=1 -- ' AND password='123456'; ``` 其中,'--' 表示注释符号,它可以使后面的 SQL 语句被忽略,从而达到绕过验证的目的。 需要注意的是,宽字节注入是一种常见的 SQL 注入技术,但并不是万能的,它只能绕过一些简单的安全机制,对于一些高级安全机制可能无法生效。因此,在开发应用程序时,应该使用参数化查询或 ORM 框架等技术来防止 SQL 注入攻击。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值