转自360
最终防注入检查函数在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; }
当%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配置(configconfig_global.php)文件中的
$_config['security']['querysafe']['afullnote'] = '0' //禁止 msyql 当中使用注释
看这个afullnote的值是否是0,如果是1请改为0.
并非某些厂商说的那样只要是最新版本就没风险的说法。如下是一个最新版本的discuz环境,因为插件的sql注入原因结合配置项是$_config['security']['querysafe']['afullnote'] = '1'开启了mysql注释功能,导致一样受到sql注入攻击威胁。
所以再提醒广大站长安全问题的重要性。
由低版本升级过来的,即使现在是最新版本,由于不会自动修改配置项,导致这种升级全部存在安全隐患。
评论 (0)