Mysql字符编码利用技巧

打印 上一主题 下一主题

主题 825|帖子 825|积分 2475


目录
一、MySQL字符编码概述
1.1UTF-8和UTF8MB4的区别
1.2字符编码的配置和修改
1.3字符集和校对规则
二、字符编码利用技巧
2.1代码
2.2创建MySQL
2.3初步访问
2.4从题目,探求缘故起因
三、漏洞成因
四、为什么只有部分字符可以使用
五、Mysql UTF8 特性


一、MySQL字符编码概述

MySQL数据库管理体系中的字符编码是用来确定数据库中字符数据的编码方式,它决定了怎样存储和检索数据。字符编码对于确保数据的精确存储和表现至关重要,尤其是在处置惩罚多语言数据时。MySQL支持多种字符编码,包括但不限于UTF-8、UTF8MB4、Latin1、GBK等。
1.1UTF-8和UTF8MB4的区别

MySQL中有两套UTF-8编码实现:utf8和utf8mb4。utf8编码只支持1-3个字节,而utf8mb4是UTF-8的完备实现,支持1-4个字节,可以存储全部的Unicode字符,包括emoji符号和一些复杂的汉字、繁体字。从MySQL 5.5.3版本开始引入了utf8mb4字符集,而在MySQL 8.0版本中,utf8mb4成为了默认的字符集。
1.2字符编码的配置和修改

在MySQL中,可以通过查询和修改变量来查看和设置数据库的字符编码。例如,SHOW VARIABLES LIKE '%character%';下令可以表现数据库的字符编码设置。如果需要修改数据库的字符编码,可以在创建数据库时指定,大概通过ALTER DATABASE下令更改现有数据库的字符编码。同样,创建表或修改表结构时也可以指定字符编码。
1.3字符集和校对规则

MySQL不仅支持差异的字符集,还支持多种校对规则(collation),这些规则决定了字符的排序和比较行为。校对规则通常与字符集一起使用,以确保数据的精确排序和比较。例如,utf8_general_ci是一个不区分巨细写的UTF-8字符集校对规则。
二、字符编码利用技巧

2.1代码

  1. <?php
  2. $mysqli = new mysqli("localhost", "root", "root", "cat");
  3. /* check connection */
  4. if ($mysqli->connect_errno) {
  5.     printf("Connect failed: %s\n", $mysqli->connect_error);
  6.     exit();
  7. }
  8. $mysqli->query("set names utf8");
  9. $username = addslashes($_GET['username']);
  10. if ($username === 'admin') {
  11.     die('Permission denied!');
  12. }
  13. /* Select queries return a resultset */
  14. $sql = "SELECT * FROM `table1` WHERE username='{$username}'";
  15. if ($result = $mysqli->query( $sql )) {
  16.     printf("Select returned %d rows.\n", $result->num_rows);
  17.     while ($row = $result->fetch_array(MYSQLI_ASSOC))
  18.     {
  19.         var_dump($row);//打印结果
  20.     }
  21.     /* free result set */
  22.     $result->close();
  23. } else {
  24.     var_dump($mysqli->error);
  25. }
  26. $mysqli->close();
复制代码
2.2创建MySQL

先在MySQL中创建表,再在表中创建字段,在其中一个字段当中,创建一个值。



2.3初步访问

通过127.0.0.1/demo.php进行查询,表现“Select returned 0 rows.”。表现没有传参,后面加入?usemame=admin进行传参。然后,我们访问http://localhost/test.php?username=admin%c2,即可发现%c2被忽略,Mysql查出了username=admin的结果。进入后的结果:说明已经绕过。

2.4从题目,探求缘故起因

造成这个Trick的根本缘故起因是,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_client、character_set_connection、character_set_results等与客户端相关的配置字符集都变成了utf8,但character_set_database、character_set_server等服务端相关的字符集照旧latin1。
这就是该Trick的核心,因为这一条语句,导致客户端、服务端的字符集出现了差异。既然有差异,Mysql在执行查询的时候,就涉及到字符集的转换。

  • MySQL Server收到哀求时将哀求数据从character_set_client转换为character_set_connection;
  • 进行内部操作前将哀求数据从character_set_connection转换为内部操作字符集
在我们这个案例中,character_set_client和character_set_connection被设置成了utf8,而内部操作字符集着实也就是username字段的字符集照旧默认的latin1。于是,整个操作就有如下字符串转换过程:
utf8 --> utf8 --> latin1
末了执行比较username='admin'的时候,'admin'是一个latin1字符串
utf-8---->utf-8---->gbk
三、漏洞成因

那么,字符集转换为什么会导致%c2被忽略呢?
个人分析缘故起因应该是,Mysql在转换字符集的时候,将不完备的字符给忽略了。
举个简朴的例子,佬这个汉字的UTF-8编码是\xE4\xBD\xAC,我们可以依次实验访问下面三个URL: b'\xe4\xbd\xac'
  1. http://127.0.0.1/mysql_1.php?username=admin%e4
  2. http://127.0.0.1/mysql_1.php?username=admin%e4%bd
  3. 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的结果。
四、为什么只有部分字符可以使用

测试这个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编码中的:

所以终极,UTF-8第一字节的取值范围是:00-7F、C2-F4,这也是我在admin后面加上80-C1、F5-FF等字符时会抛出错误的缘故起因。
关于全部的UTF-8字符,你可以在这个表中逐一看到: http://utf8-chartable.de/unicode-utf8-table.pl
五、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,再看看效果:

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

魏晓东

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表