作品发布     邀请码    设为首页  收藏 

当前位置:文章编程 → 文章内容 >> PHP多字节编码漏洞小结


PHP多字节编码漏洞小结

更新时间:2012-2-18 15:45:12   作者:华中帝国整理  来源:华中帝国
如果小结中有理解错误的地方,麻烦大家提出。漏洞本质: php 使用 php_escape_shell_cmd这个函数来转义命令行字符串时是作为单字节处理的而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将 ...
如果小结中有理解错误的地方,麻烦大家提出。

漏洞本质:
  1. php 使用 php_escape_shell_cmd这个函数来转义命令行字符串时是作为单字节处理的
  2. 而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将这些命令行字符串传递给MySQL处理时是作为多字节处理的
复制代码
先看个简单的例子
  1. <?php
  2. header('Content-type: text/html; charset=gbk');
  3. //连接MySQL
  4. $conn = mysql_connect("localhost", "root", "");
  5. //选择数据库
  6. mysql_select_db("test", $conn);
  7. //设置字符集编码
  8. mysql_query("SET CHARACTER SET 'gbk'", $conn);

  9. //创建DEMO表如果不存在
  10. mysql_query("CREATE TABLE IF NOT EXISTS `demo` (
  11. `uid` int(10) NOT NULL AUTO_INCREMENT,
  12. `username` varchar(32) NOT NULL,
  13. `password` varchar(32) NOT NULL,
  14. PRIMARY KEY (`uid`)
  15. ) ENGINE=MyISAM DEFAULT CHARSET=gbk AUTO_INCREMENT=1;", $conn);
  16. //插入个测试数据
  17. mysql_query("REPLACE INTO `demo` VALUES('','admin','admin888') ",$conn);
  18. //获取用户输入
  19. $username = isset($_REQUEST['username']) ? $_REQUEST['username'] : '';

  20. //执行查询并且DEBUG
  21. $sql = "SELECT * FROM demo WHERE username = '{$username}' LIMIT 1";
  22. echo "sql: ".$sql."<br />";
  23. $res = mysql_query($sql, $conn);
  24. $row = mysql_fetch_array($res);
  25. echo "result: <br/>";
  26. var_dump($row);
  27. ?>
复制代码
当GPC=OFF时:
username未经任何过滤,这是个典型的字符型SQL注入
测试地址:
http://localhost/gbk.php?username=' or 1%23
http://localhost/gbk.php?username=' or 0%23

当然很多情况下GPC=OFF时候都会使用一些函数来过滤用户的输入
  1. // 对用户传入的变量进行转义操作
  2. if (!get_magic_quotes_gpc())
  3. {
  4.     $username = addslashes($username);
  5. }
复制代码
看上去貌似没问题了,但是由于多字节编码问题,同样还是可以注入的

测试地址:http://localhost/gbk.php?username=%df%27
使用mysql_real_escape_string函数对用户输入进行转义存在同样的问题

目前的很多开源的系统都是通过设置客户端的字符集为二进制来防止多字节编码问题的。
  1. //使用上面这句来替换DEMO中的 mysql_query("SET CHARACTER SET 'gbk'", $conn);
  2. mysql_query("SET character_set_connection=gbk, character_set_results=gbk, character_set_client=binary", $conn);
复制代码
再次测试:http://localhost/gbk.php?username=%df%27

OK,这样一来,多字节编码问题就不存在了吗?不见得

当使用mb_convert_encoding、iconv对字符集进行错误的转换时候,漏洞再次的出现了(GPC=ON时问题同样存在)

例如:
  1. $username = iconv('gbk','utf-8',$username);

  2. $username = mb_convert_encoding($username,'utf-8','gbk');
复制代码
来看下T00ls上看到的ECSHOP 2.6.x/2.7.x GBK版本的漏洞吧

漏洞文件在api/checkorder.php line 28
  1. $sql = "SELECT COUNT(*) ".
  2.         " FROM " . $ecs->table('admin_user') .
  3.         " WHERE user_name = '" . trim($_REQUEST['username']). "' AND password = '" . md5(trim($_REQUEST['password'])) . "'";
复制代码
我们来看下$_REQUEST['username'] 的获取过程
  1. $_REQUEST['username'] = json_str_iconv($_REQUEST['username']);
复制代码
json_str_iconv()这个函数在includes/lib_base.php中定义,其功能是将非UTF-8编码的字符串进行转换,然后return ecs_iconv('utf-8', EC_CHARSET, $str);
ecs_inonv这个函数也在 includes/lib_base.php中定义,看下函数吧:
  1. function ecs_iconv($source_lang, $target_lang, $source_string = '')
  2. {
  3.     static $chs = NULL;

  4.     /* 如果字符串为空或者字符串不需要转换,直接返回 */
  5.     if ($source_lang == $target_lang || $source_string == '' || preg_match("/[\x80-\xFF]+/", $source_string) == 0)
  6.     {
  7.         return $source_string;
  8.     }

  9.     if ($chs === NULL)
  10.     {
  11.         require_once(ROOT_PATH . 'includes/cls_iconv.php');
  12.         $chs = new Chinese(ROOT_PATH);
  13.     }

  14.     return $chs->Convert($source_lang, $target_lang, $source_string);
  15. }
复制代码
先是引入了includes/cls_iconv.php这个文件,然后实例化了Chinese这个类,在调用类的Convert的方法见line 127
  1. $string = $this->_convert_iconv_mbstring($this->SourceText, $this->config['target_lang'], $this->config['source_lang']);
复制代码
又调用了另外一个函数_conver_iconv_mbstring见line 278
  1. //这里错误的吧字符集从gbk转为了utf8,所以漏洞产生了
  2. $return_string = @mb_convert_encoding($string, $target_lang, $source_lang);
复制代码

   免责声明:本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

责任编辑:华中帝国        



本文引用网址: 

PHP多字节编码漏洞小结的相关文章
发表评论

用户名: 查看更多评论

分 值:100分 85分 70分 55分 40分 25分 10分 0分

内 容:

         (注“”为必填内容。) 验证码: 验证码,看不清楚?请点击刷新验证码