2015-03-19: 积极联系厂商并且等待厂商认领中,细节不对外公开 2015-05-03: 厂商已经主动忽略漏洞,细节向公众公开
KingCms最新版(k9)越权添加管理员
朋友的公司想购买kingcms的授权,让我帮忙看下。发现kingcms很长一段时间没更新了,憋了一段时间放出了最新版的k9,官网下下来学习一下。在wooyun上看到了几个漏洞,如: WooYun: kingcms最新版sql注入漏洞 这里可越权添加管理员。问题文件在/user/manage.php0x00:先来看看获得相关权限的绕过方法吧Kingcms使用$u=new user;$u->auth_role('admin');来验证用户是否具有admin的权限,先来看看user类,主要用来判断用户是否登录,以及获得用户的各种属性。/user/user.class.phpuser的构造方法如下
public function __construct(){ $cookie=kc_cookie('userauth'); $cookiePass=substr($cookie,0,32); $ischeck=true; $GLOBALS['db']=new db; $GLOBALS['str']=new str; $GLOBALS['cache']=new cache; global $db,$str; if(empty($cookie) && !empty($_GET['jsoncallback']) && !empty($_GET['USERID']) && !empty($_GET['SIGN'])){ //第1处注释:这里很容易使条件成立,执行下面的if语句 $get_userid=$_GET['USERID']; $get_sign=$_GET['SIGN']; $sign=md5($get_userid.SITEURL.kc_config('system.salt')); $userid = $sign==$get_sign ? $get_userid : 0; //第2处注释:这里是唯一的一次简单验证 $ischeck=false; //第3处注释:在下面第4处注释处会用到 }else{ $userid=substr($cookie,32); } if(!kc_validate($userid,2)) $userid=0; if(empty($userid)){ $user=array('userpass'=>'x'); }else{ $user=$db->getRows_one('%s_user','*','userid='.$userid); if(empty($user)) $user=array('userpass'=>'x'); } //用户已登录 if (md5($user['userpass'])==$cookiePass || $ischeck==false) {//第4处注释无关代码
上面代码的第二处注释的地方,要获得需要操作的userid,要计量$sign=md5($get_userid.SITEURL.kc_config('system.salt')); 其中的参数$get_userid是用户输入,SITEURL是当前域名,不包含www等二级域名,[小写],kc_config('system.salt')是系统默认的,定值。这样,这里就可以绕过了。使得$ischeck=false。$_GET['SIGN']也即$sign计算过程是这样的
<?php$str="10000";//10000即POST参数中的USERID$str.="kingcms.com";//网站域名$SIGN=md5($str);?>
在第4处注释处,因为$ischeck=false,所以,用户已登陆,USERID输入10000(kingcms系统的超级管理员id),就获得了管理员的所有权限了。下面看看添加管理员的代码吧/user/manage.php
function _edit(){ $u=new user;$u->auth_role('admin'); $userid=kc_post('userid',2,0); $db=new db; $str=new str; if(empty($userid)){ if (empty($_POST['username'])) kc_tip('请填写用户名!','form'); if ($str->len($_POST['username'])>12) kc_tip('用户名太长,不能超过12字','form'); if(preg_match('/[<>\s\!\@\/\\\|\]\[\}\{\#\$\%\^\&\*\(\)\_\+\=\-]/',$_POST['username'])) kc_tip('用户名不能含有非法字符!','form'); $rs=$db->getRows_one('%s_user','userid','username=\''.$db->encode($_POST['username']).'\''); if(!empty($rs)) kc_tip('您要添加的用户已经存在!','form'); } if(empty($userid)){ if(empty($_POST['userpass'])) kc_tip('密码不能为空!','form'); } if(!empty($_POST['username'])){ if (strlen($_POST['userpass'])>30) kc_tip('您的密码太长,不能超过30个字符!','form'); if($_POST['userpass1']<>$_POST['userpass']) kc_tip('两次输入的密码不一致!','form'); } if(!empty($_POST['rid']) && !kc_validate($_POST['rid'],3)) kc_tip('所属角色参数错误!','form'); $rids=empty($_POST['rid']) ? array() : explode(',',$_POST['rid']); foreach($rids as $rid){ if(!empty($_POST['role_removedate'.$rid]) && !kc_validate($_POST['role_removedate'.$rid],9)) kc_tip('有效日期格式不正确!','form'); } if(!empty($_POST['gid']) && !kc_validate($_POST['gid'],3)) kc_tip('所属用户组参数错误!','form'); $gids=empty($_POST['gid']) ? array() : explode(',',$_POST['gid']); foreach($gids as $gid){ if(!empty($_POST['group_removedate'.$gid]) && !kc_validate($_POST['group_removedate'.$gid],9)) kc_tip('有效日期格式不正确!','form'); } if($str->len($_POST['name'])>20) kc_tip('真实姓名过长!','form'); if($str->len($_POST['tel'])>30) kc_tip('电话过长!','form'); if($str->len($_POST['email'])>50) kc_tip('邮箱过长!','form'); if(!empty($_POST['email']) && !kc_validate($_POST['email'],5)) kc_tip('邮箱地址格式','form'); if($str->len($_POST['qq'])>12) kc_tip('QQ号码过长!','form'); if($str->len($_POST['address'])>200) kc_tip('通信地址过长!','form'); if($str->len($_POST['qianming'])>250) kc_tip('个性签名过长!','form'); $array=array( 'name'=>$_POST['name'], 'tel'=>$_POST['tel'], 'email'=>$_POST['email'], 'qq'=>$_POST['qq'], 'address'=>$_POST['address'], 'qianming'=>$_POST['qianming'], ); if(!empty($_POST['userpass'])) $array['userpass']=md5($_POST['userpass']); if(empty($userid)){ $array['username']=$_POST['username']; $array['regdate']=TIME; $array['date']=TIME; $array['regip']=$str->ip(); $array['ip']=$str->ip(); $userid=$db->insert('%s_user',$array); kc_log(array('userid'=>$u->info['userid'],'app'=>'user','action'=>'USER_NEW','cid'=>$userid)); }else{ $db->update('%s_user',$array,'userid='.$userid); $db->delete('%s_user_group_bind','userid='.$userid); $db->delete('%s_user_role_bind','userid='.$userid); kc_log(array('userid'=>$u->info['userid'],'app'=>'user','action'=>'USER_EDIT','cid'=>$userid)); } //更新role和user绑定表信息 $array=array(); foreach($rids as $rid){ $removedate=empty($_POST['role_removedate'.$rid]) ? 0 :str_replace('-','',$_POST['role_removedate'.$rid]); $array[]=array( 'userid'=>$userid, 'rid'=>$rid, 'removedate'=>$removedate, ); } $db->insert('%s_user_role_bind',$array,1); //更新group和user绑定表信息 $array=array(); foreach($gids as $gid){ $removedate=empty($_POST['group_removedate'.$gid]) ? 0 :str_replace('-','',$_POST['group_removedate'.$gid]); $array[]=array( 'userid'=>$userid, 'gid'=>$gid, 'removedate'=>$removedate, ); } $db->insert('%s_user_group_bind',$array,1); $s='<ul class="goto">'; $s.='<li><a href="/?_=user">返回用户列表</a></li>'; $s.='<li><a href="javascript:;" onclick="$.kc_close();$(\'.Submit\').removeAttr(\'disabled\');">继续编辑</a></li>'; $s.='<li><a href="/?_=user_edit">+ 添加新用户</a></li>'; $s.='</ul>'; kc_ajax(array( 'TITLE'=>'继续您的操作', 'MAIN'=>$s, 'ID'=>'k_ajax', 'WIDTH'=>370, 'HEIGHT'=>120, ));}
过程见下图
添加成功后,登录,具有所有的权限哟
见 详细说明
权限验证
未能联系到厂商或者厂商积极拒绝