http://www.laruence.com/2008/01/05/12.html
针对给定的字符 赋予一个数值,这个数值就是这个字符的编码,多个字符以及对应的编码,就组成了字符集
eg: A->1 B->2 A的字符编码是1 B的字符编码是2 当给定的字符是AB的时候,{A->1 B->2}就是字符集
mysql支持的字符集
mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
| dec8 | DEC West European | dec8_swedish_ci | 1 |
| cp850 | DOS West European | cp850_general_ci | 1 |
| hp8 | HP West European | hp8_english_ci | 1 |
mysql> SHOW CHARACTER SET WHERE Charset="utf8";
+---------+---------------+-------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+---------------+-------------------+--------+
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
+---------+---------------+-------------------+--------+或者
mysql> SHOW CHARACTER SET LIKE "utf8%";
+---------+---------------+--------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+---------------+--------------------+--------+
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |
+---------+---------------+--------------------+--------+
切换到要查看的数据库
mysql> SELECT @@character_set_database, @@collation_database;
+--------------------------+----------------------+
| @@character_set_database | @@collation_database |
+--------------------------+----------------------+
| gbk | gbk_chinese_ci |
+--------------------------+----------------------+或者 通过创建库的语句
mysql> SHOW CREATE DATABASE security;
+----------+------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------+
| security | CREATE DATABASE `security` /*!40100 DEFAULT CHARACTER SET gbk */ |
+----------+------------------------------------------------------------------+
通过查询创建表的语句mysql> SHOW CREATE TABLE users;
+-------+------------------------------------------------------------------------------
| Table | Create Table |
+-------+------------------------------------------------------------------------------
| users | CREATE TABLE `users` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=gbk |
是指同一字符集中,各字符之间的比较规则,确定了字符序之后,就可以比较字符集中字符的大小关系
在数据的存储上,MySQL提供了不同的字符集
在数据的比较上,MySQL提供了不同的字符序
SELECT TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = "security" AND TABLE_NAME = "users";
+-----------------+
| TABLE_COLLATION |
+-----------------+
| gbk_chinese_ci |
+-----------------+
mysql> SELECT CHARACTER_SET_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA="security" AND TABLE_NAME="users" AND COLUMN_NAME="username";
+--------------------+----------------+
| CHARACTER_SET_NAME | COLLATION_NAME |
+--------------------+----------------+
| gbk | gbk_chinese_ci |
+--------------------+----------------+
针对字符集和字符序的详情参考
https://www.cnblogs.com/chyingp/p/mysql-character-set-collation.html
MySQL字符集设置
– character_set_server:默认的内部操作字符集– character_set_client:客户端来源数据使用的字符集
– character_set_connection:连接层字符集
– character_set_results:查询结果字符集
– character_set_database:当前选中数据库的默认字符集
– character_set_system:系统元数据(字段名等)字符集
查看MySQL字符集设置
mysql> SHOW VARIABLES LIKE 'character_set_%';
+--------------------------+-----------------------------------------------+
| Variable_name | Value |
+--------------------------+-----------------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html
utf8编码处理一个汉字用3个字节表示,gbk编码处理一个汉字用2个字节表示
查看php中 使用的是那种编码
<?php echo strlen("和"); ?>
输出是2 就是gbk
输出是3 就是utf8
大多数程序会使用addslashes来转义单引号 ' == '
两种方式绕过
1 转义掉 这种 \'
单引号就可以逃逸出来
2 把 弄没有
利用宽字节就可以把弄没有 MySQL使用GBK编码时,会认为两个字符表示一个汉字,不过第一个字符的ascii值要大于128(%80),才能达到汉字的范围
把上面的代码稍微改动一下
$mysqli->query("set names gbk");
$username = addslashes($_GET['username']);
测试一下
加上单引号试一下
不行
加上%df试一下
payload
?username=admin%df%27%20or%201=1%23
ok了
这里%df还可以换成%a1 %81 等等 大于%80的 都可以
gb2312
gb23112编码就不存在宽字节的问题,因为gb2312编码的取值范围。它的高位范围是0xA1~0xF7
,低位范围是0xA1~0xFE
,而是0x5c,是不在低位范围中的。所以,
0x5c
根本不是gb2312中的编码 ,自然就不会存在宽字节注入的问题啦
转义单引号的函数不只有addslashes 还有 mysqlrealescape_string
该函数会考虑到当前使用的字符集,是不是就不存在宽字节注入的问题啦
试试看
char.php写入
<?php
@$conn = mysql_connect('localhost','root','root');
mysql_query("SET NAMES 'gbk'");
mysql_select_db('lianxi',$conn);
#mysql_set_charset('gbk',$conn);
$username = mysql_real_escape_string($_GET['username']);
$sql = "SELECT * FROM `user` WHERE name='{$username}'";
$result=mysql_query($sql,$conn);
$row=mysql_fetch_array($result);
var_dump($row);
mysql_free_result($result);
?>
payload还是能打通
指定一下php连接MySQL的字符集,
mysql_set_charset('gbk',$conn);
返回bool(flase)
结论
如果不加上mysqlsetcharset('gbk',$conn); 这一行代码 依旧存在
还有另外一个解决方案 通过设置客户来源字符集为binary 把数据保存为二进制,以二进制的形式传递,就不存在宽字节的问题了
SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
iconv转换编码
iconv('utf-8', 'gbk', $_GET['word']);
很多网站为了避免乱码,把utf8转成了gbk
后端代码
<?php @$conn = mysql_connect('localhost','root','root'); mysql_query("SET NAMES 'gbk'"); mysql_select_db('lianxi',$conn); mysql_query('SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary'); $username = addslashes($_GET['username']); $username = iconv('utf-8', 'gbk', $username); $sql = "SELECT * FROM `user` WHERE name='{$username}'"; $result=mysql_query($sql,$conn); $row=mysql_fetch_array($result);var_dump($row); mysql_free_result($result); ?>
连接层字符集设置了binary 并且转义了单引号
上面的payload已经不行了
再试一下第二种方法 转义掉
汉字 錦 utf8编码为 0xe98ca6 gbk编码为 0xe55c
试一下
可以打通,payload被转为gbk编码后,出现了5c 两个5c放到一起,就变成了这个字符,失去了转义的作用
如果是gbk转为utf8呢 是不是同样存在问题
修改一下 代码
$username = iconv('gbk', 'utf-8', $username);
直接用第一种方法 就行
gbk编码 2个字节一组 直接吞掉%5c
Note: 说明一下 utf8编码 不是3个字节一组嘛 为什么a%E9%8C没有放在一起转码,因为3个字节一组的是汉字 对于ASCII 是单字节 a被单独解码 后面的%E9满足大于128的条件被当作汉字解码,3个一组
而gbk编码 当第一个字节大于128的时候 表示的就是汉字 所以%df%5c才会放到一起
https://www.leavesongs.com/PENETRATION/mysql-charset-trick.html
MySQL默认的字符集是Latin1
Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
客户端输入一个字符,经过的编码过程如下
character_set_client -> character_set_connection -> character_set_server
这里三个编码 都设置为了utf8
mysql> SHOW VARIABLES LIKE 'character_set_%';
+--------------------------+-----------------------------------------------+
| Variable_name | Value |
+--------------------------+-----------------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
输入
admin%e4 admin%e4%db admin%e4%bd%ac
只有第一个能绕过 第二个和第三个都不行 貌似应该是凑不成一个字符 会被丢掉,
MySQL中的字符序名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感)、_cs(表示大小写敏感)或_bin(表示按编码值比较)结尾。
utf8generalci不区分大小写, 对于法语和德语校对有问题,例如
Ä/ä = A
Ö/ö = O
Ü/ü = U
A=a
这几种条件都成立,
对于utf8generalci下面的等式成立:ß = s ,但是,对于utf8unicodeci下面等式才成立:ß = ss 。
http://collation-charts.org/mysql60/mysql604.utf8generalci.european.html
在数据库中插入一条admin的记录
mysql> insert `user` values(212,'admin','sex',20190102,'programer'); Query OK, 1 row affected (0.00 sec)
连接数据库
<?php
$mysqli = new mysqli("localhost", "root", "root", "lianxi");
/* check connection */
if ($mysqli->connect_errno) {
printf("Connect failed: %sn", $mysqli->connect_error);
exit();
}
$mysqli->query("set names utf8");
$username = $_GET['username'];
/* Select queries return a resultset */
$sql = "SELECT * FROM `user` WHERE name='{$username}'";
if ($result = $mysqli->query( $sql )) {
printf("Select returned %d rows.n", $result->num_rows);
while ($row = $result->fetch_array(MYSQLI_ASSOC))
{var_dump($row);
}
/* free result set */
$result->close();} else {
var_dump($mysqli->error);}
$mysqli->close();
%C3%84是Ä的url编码
%C3%A4是ä的url编码
ADMIN = admin
utf8unicodeci和utf8generalci对中、英文来说没有实质的差别。
utf8generalci校对速度快,但准确度稍差。
utf8unicodeci准确度高,但校对速度稍慢。
如果你的应用有德语、法语或者俄语,请一定使用utf8unicodeci
本文作者:星盟安全团队
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/118629.html