如果小结中有理解错误的地方,麻烦大家提出。漏洞本质: php 使用 php_escape_shell_cmd这个函数来转义命令行字符串时是作为单字节处理的而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将 ...
如果小结中有理解错误的地方,麻烦大家提出。
漏洞本质:
php 使用 php_escape_shell_cmd这个函数来转义命令行字符串时是作为单字节处理的
而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将这些命令行字符串传递给MySQL处理时是作为多字节处理的
先看个简单的例子
复制代码代码如下:
header('Content-type: text/html; charset=gbk');
//连接MySQL
$conn = mysql_connect("localhost", "root", "");
//选择数据库
mysql_select_db("test", $conn);
//设置字符集编码
mysql_query("SET CHARACTER SET 'gbk'", $conn);
//创建DEMO表如果不存在
mysql_query("CREATE TABLE IF NOT EXISTS `demo` (
`uid` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL,
`password` varchar(32) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=gbk AUTO_INCREMENT=1;", $conn);
//插入个测试数据
mysql_query("REPLACE INTO `demo` VALUES('','admin','admin888') ",$conn);
//获取用户输入
$username = isset($_REQUEST['username']) ? $_REQUEST['username'] : '';
//执行查询并且DEBUG
$sql = "SELECT * FROM demo WHERE username = '{$username}' LIMIT 1";
echo "sql: ".$sql."
";
$res = mysql_query($sql, $conn);
$row = mysql_fetch_array($res);
echo "result:
";
var_dump($row);
?>
当GPC=OFF时:
username未经任何过滤,这是个典型的字符型SQL注入
测试地址:
http://localhost/gbk.php?username=' or 1%23
http://localhost/gbk.php?username=' or 0%23
当然很多情况下GPC=OFF时候都会使用一些函数来过滤用户的输入
复制代码代码如下:
// 对用户传入的变量进行转义操作
if (!get_magic_quotes_gpc())
{
$username = addslashes($username);
}
看上去貌似没问题了,但是由于多字节编码问题,同样还是可以注入的
测试地址:http://localhost/gbk.php?username=%df%27
使用mysql_real_escape_string函数对用户输入进行转义存在同样的问题
目前的很多开源的系统都是通过设置客户端的字符集为二进制来防止多字节编码问题的。
//使用上面这句来替换DEMO中的 mysql_query("SET CHARACTER SET 'gbk'", $conn);
mysql_query("SET character_set_connection=gbk, character_set_results=gbk, character_set_client=binary", $conn);
再次测试:http://localhost/gbk.php?username=%df%27
OK,这样一来,多字节编码问题就不存在了吗?不见得