网站地图    收藏   

主页 > 后端 > 网站安全 >

Discuz防护绕过分析 - 网站安全 - 自学php

来源:自学PHP网    时间:2015-04-17 11:59 作者: 阅读:

[导读] 最终防注入检查函数在discuz_database_safecheck::checkquery(%s)中,如下 protected static $checkcmd = array(#39;SELECT#39;, #39;UPDATE#39;, #39;INSERT#39;, #39;REPLACE#39;, #3......

 
最终防注入检查函数在discuz_database_safecheck::checkquery(%s)中,如下
        protected static $checkcmd = array('SELECT', 'UPDATE', 'INSERT', 'REPLACE', 'DELETE');
        protected static $config;
 
        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;
        }
 www.2cto.com
当%s中包含$checkcmd中关键字时就会调用_do_query_safe($sql)进行检查
        private static function _do_query_safe($sql) {
                
                $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);
                $mark = $clean = '';
                if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) 
                //当$sql中包含/、#、--等字符时就会进入对应替换代码{
                        $clean = preg_replace("/'(.+?)'/s", '', $sql);
                } else {
                        $len = strlen($sql);
                        $mark = $clean = '';
                        for ($i = 0; $i < $len; $i++) {
                                $str = $sql[$i];
                                switch ($str) {
                                        case '\''://防注入绕过出现在这里,当$sql中包含/*这样的字符串之后的内容会被替换为空,直到出现*/
                                                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;
                        }
                }
                //那么黑客提交/*xxx*/字符之间的xxx会被替换为空,或者#或者-- 时对应后面的内容替换为空保存到$clean变量中
                //被替换为空的$clean变量再做下面过滤
 
                $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));
 
                if (self::$config['afullnote']) {
                        $clean = str_replace('/**/', '', $clean);//这里使得/**/完全被替换为空,从而绕过下面$note变量的过滤
                }
.........
 
这里黑客可以提交/*! Sql */,把sql放到注释符中间替换为空,mysql中的/*!可以判断mysql版本决定是否执行,从而绕过了disczu内置的防注入检查,也可以使用注释#xxx%0a sql绕过,不过由于#号没有被替换为空,最终会被dnote中的关键字拦截.

所以这里提醒广大站长检查config配置(\config\config_global.php)文件中的
$_config['security']['querysafe']['afullnote'] = '0' //禁止 msyql 当中使用注释
复制代码
看这个afullnote的值是否是0,如果是1请改为0.
 
 
 
并非某些厂商说的那样只要是最新版本就没风险的说法。如下是一个最新版本的discuz环境,因为插件的sql注入原因结合配置项是$_config['security']['querysafe']['afullnote'] = '1'开启了mysql注释功能,导致一样受到sql注入攻击威胁。
 
所以再提醒广大站长安全问题的重要性。
由低版本升级过来的,即使现在是最新版本,由于不会自动修改配置项,导致这种升级全部存在安全隐患。
这是官方给出的低版本升级说明,提醒用户需要手动修改的一下配置项。
http://www.discuz.net/thread-2168918-1-1.html?adtag=fromedm
附加上官方给出的安全配置说明
http://faq.comsenz.com/library/safe/security/security_config.htm
 

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论