利用数据库编码特性绕过

创建一个test.php文件

在数据库下创建demo数据库,在里面建表,并插入一条字段

访问test.php

尝试利用username=admin绕过,但是被拒绝,因为代码不允许

所以我们只能利用数据库编码特性绕过,下面是一些这方面的知识点:

Mysql字段的字符集和php mysqli客户端设置的字符集不相同

set names utf8 的意思是将客户端的字符集设置为utf8。我们打开mysql控制台,依次执行

SHOW VARIABLES LIKE 'character_set_%';set names utf8;SHOW VARIABLES LIKE 'character_set_%';,即可得到如下结果:

如上图,在默认情况下,mysql字符集为latin1,而执行了set names utf8;以后,character_set_clientcharacter_set_connectioncharacter_set_results等与客户端相关的配置字符集都变成了utf8,但character_set_databasecharacter_set_server等服务端相关的字符集还是latin1。(一般mysql下载下来就是第一次查询的样子,但是如果用到PHP study可能就会改掉一些字符集就变成第二次查询的样子了)

这就是该Trick的核心,因为这一条语句,导致客户端、服务端的字符集出现了差别。既然有差别,Mysql在执行查询的时候,就涉及到字符集的转换。

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

  2. 进行内部操作前将请求数据从character_set_connection转换为内部操作字符集

在我们这个案例中,character_set_client和character_set_connection被设置成了utf8,而内部操作字符集其实也就是username字段的字符集还是默认的latin1。于是,整个操作就有如下字符串转换过程:

utf8 --> utf8 --> latin1

最后执行比较username='admin'的时候,'admin'是一个latin1字符串

utf-8---->utf-8---->gbk

0x03 漏洞成因

那么,字符集转换为什么会导致%c2被忽略呢?

个人分析原因应该是,Mysql在转换字符集的时候,将不完整的字符给忽略了。

举个简单的例子,佬这个汉字的UTF-8编码是\xE4\xBD\xAC,我们可以依次尝试访问下面三个URL: b'\xe4\xbd\xac'

http://127.0.0.1/mysql_1.php?username=admin%e4
http://127.0.0.1/mysql_1.php?username=admin%e4%bd
http://127.0.0.1/mysql_1.php?username=admin%e4%bd%ac

可以发现,前两者都能成功获取到username=admin的结果,而最后一个URL,也就是当我输入佬字完整的编码时,将会被抛出一个错误:

为什么会抛出错误?原因很简单,因为latin1并不支持汉字,所以utf8汉字转换成latin1时就抛出了错误。

那前两次为什么没有抛出错误?因为前两次输入的编码并不完整,Mysql在进行编码转换时,就将其忽略了。

这个特点也导致,我们查询username=admin%e4时,%e4被省略,最后查出了username=admin的结果。

0x04 为什么只有部分字符可以使用

测试这个Trick的时候发现,username=admin%c2时可以正确得到结果,但username=admin%c1就不行,这是为什么?

简单fuzz了一下,如果在admin后面加上一个字符,有如下结果:

\x00~\x7F: 返回空白结果 \x80~\xC1: 返回错误Illegal mix of collations \xC2~\xEF: 返回admin的结果 \xF0~\xFF: 返回错误Illegal mix of collations 这就涉及到Mysql编码相关的知识了,先看看维基百科吧。

UTF-8编码是变长编码,可能有1~4个字节表示:

一字节时范围是[00-7F] 两字节时范围是C0-DF 三字节时范围是E0-EF[80-BF] 四字节时范围是F0-F780-BF 然后根据RFC 3629规范,又有一些字节值是不允许出现在UTF-8编码中的:

avatar

所以最终,UTF-8第一字节的取值范围是:00-7F、C2-F4,这也是我在admin后面加上80-C1、F5-FF等字符时会抛出错误的原因。

关于所有的UTF-8字符,你可以在这个表中一一看到: http://utf8-chartable.de/unicode-utf8-table.pl

0x05 Mysql UTF8 特性

那么,为什么username=admin%F0也不行呢?F0是在C2-F4的范围中呀?

这又涉及到Mysql中另一个特性:Mysql的utf8其实是阉割版utf-8编码,Mysql中的utf8字符集最长只支持三个字节,

所以,我们回看前文列出的UTF-8编码第一字节的范围,

三字节时范围是E0-EF[80-BF] 四字节时范围是F0-F780-BF

F0-F4是四字节才有的,所以我传入username=admin%F0也将抛出错误。

如果你需要Mysql支持四字节的utf-8,可以使用utf8mb4编码。我将原始代码中的set names改成set names utf8mb4,再看看效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值