宽字节注入

涉及的东西比较多,单独做个记录。

字符集:
GBK是一种多字符的编码,通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节.

作用:绕过addslashes()

addslashes()效果是 ',绕过的思路一是去掉,二是在前再加个,形成偶数个\,抵消掉。

前端网页,php与mysql数据库字符编码

前端网页编码:

通过设置head标签内的meta来设置本网页的编码。

<head><meta charset="utf-8"/></head>

但是有些时候设置了这个不一定管用,因为服务器发过来的header也是可以指定网页编码的,并且优先级比上面那条高。

Content-Type:text/html;charset=utf-8

mysql数据库编码

mysql> show variables like 'character%';
+--------------------------+-----------------------------------+
| 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                              |
| character_sets_dir       | E:\phpstudy\MySQL\share\charsets\ |
+--------------------------+-----------------------------------+

数据库操作的各个层中使用的编码不尽相同。
字符集的优先级为:字段----->表------->库-------->服务器
一般只需要设置character-set-server 就可以实现统一了。

重点是下面3个:

character_set_client 客户端,php发送sql语句时用的编码
character_set_connection 连接层,服务器把sql语句转换为连接层的编码,与mysql里的数据交互
character_set_results 数据交互完成,以这种编码返回结果给客户端

只要设置这3个相同,就不会有乱码问题。

php编码

为了使从mysql存入和取出的数据不乱码,需要设置以下3个参数和character-set-server相同。

这3个参数可以通过执行sql语句:set names xxx来设置。
如 mysql_query("set names gbk"),这条实际是指定了上述的“客户端、连接层、结果集”的字符集都为gbk。
即相当于:

(1)set character_set_client = UTF-8
(2)set character_set_connection = UTF-8
(3)set character_set_results = UTF-8

宽字节注入产生的原因:

  • code1:

$id = addslashes($_GET['id']);
mysqli_query($conn, 'set names gbk');
$sql = "select * from users where id = '{$id}'";
$result = mysqli_query($conn, $sql);
  1. 客户端提交?id=1%df%27

  2. php检测到单引号(%27),在起前面加上反斜杠(%5C),变成?id=1%df%5C%27

  3. php利用character_set_client设置的编码(gbk)对sql语句编码,mysql用了gbk,认为两个字节(%df%5C)是一个汉字,使得单引号逃逸出来

GBK双字节编码把一个汉字用两个字节表示,首字节对应0x81-0xFE,尾字节对应0x40-0xFE(除0x7F),刚好涵盖了反斜杠(0x5C)。GB2312也属于宽字节,但却不能注入,原因是其范围为:首字节(0xA1~0xF7),尾字节(0xA1~0xFE),是0x5C,不在尾字节的范围内,'不会被吃掉。

关于iconv()

string iconv ($in_charset, $out_charset,$str )
将字符串 str 从 in_charset 转换编码到 out_charset。

有些程序为了避免乱码,常使用这个函数,iconv('utf-8','gbk',$_GET['id'])。
传入 id=%e5%5c%27,
数据变换:(e55c转为UTF-8为e98ca6)

e55c27====(addslashes)====>e55c5c5c27====(iconv)====>e98ca65c5c27

而e98ca65c5c27表示 錦\' 恰好使转义失效。

利用:

sqlmap下可使用 unmagicquotes.py

修复

  1. 使用mysql_set_charset(GBK)指定字符集,并且用mysql_real_escape_string进行转义。

  2. 把character_set_client设置为binary二进制

标签: none

添加新评论