003-php mt_rand函数的安全问题探讨

# php mt_rand函数的安全问题探讨

### mt_rand() 函数的安全性问题

“`bash
php -r ‘echo getrandmax().”\n”.mt_getrandmax().”\n”; echo (pow(2,31)-1).”\n”;’
“`

![](/static/lingzu/images/15892023472397.png)

在我的 linux 64 位系统中,rand() 和 mt_rand() 产生的最大随机数都是2147483647,

正好是 2^31-1 , 也就是说随机播种的种子也是在这个范围中,0 – 2147483647 的这个范围是允许我们进行爆破的. 但是用 php爆破比较慢

这里放一个爆破poc的d地址

php_mt_seed爆破程序 https://github.com/ianxtianxt/php-mt_rand

下面演示一下它的用法:

![](/static/lingzu/images/15892023596635.png)

在例子中,我没有自己播种种子,而是让php自动去播种一个种子并产生一个随机数,然后用 php_mt_seed 这个工具把产生的随机数作为参数,去爆破种子,最后的得到了四个结果.
经过验证,四个结果都是对的.都会产生这样的一个随机数.

但是还有一个疑问,就是 php manual 中说,自动播种种子是指:在每次调用 mt_rand()函数之前都播种一次种子呢,还是多次调用 mt_rand()函数之前,只播种一次种子呢,这对于我们能否猜到产生的随机数序列至关重要.

看下面的测试:

![](/static/lingzu/images/15892023706093.png)

在测试中,在没有进行手工播种的情况下产生两个连续的随机数,然后去爆破种子,得到了四个可能种子,经过测试发现其中一个种子产生的随机数序列和预期的相同,所以可以猜想在php中产生一系列的随机数时,只进行了一次播种!

那请考虑下面代码的安全性:

“`php

“`

我们是否可以根据公开的key,猜到 `$private` 呢?

运行一次上面的代码:

“`bash
njctf$ php mtRand.php
[*] This is a key for public:uS66FDD9LCR62UV3
[*] Create a private key which you don\’t know:t3JSUHzYAv
“`

下面演示破解过程,首先获得public key在每一位在字符串中的位置:

“`php

“`

然后用 php_mt_seed 进行破解,这个需要的时间还是挺长的,几分钟左右.

![](/static/lingzu/images/15892024150318.png)

已经成功的破解了一个seed,下面看这个seed对不对:

“`php

“`

跟刚才的结果一模一样 :

![](/static/lingzu/images/15892024305616.png)

这样就说明了,我们只需要拿到public key,就可以预测到private key 的值了.

但是在有的一些环境中,public key可能在private key之后产生,但是知道private key的位数
怎么预测private key呢?

强大的php_mt_seed_4.0,支持一些统配的写法,把未知的都写成参数 0 0 0 0 就可以了php_mt_seed详细的使用说明。它就会跳过前面的mt_rand()的一些输出,直接匹配后面的:

下面测试我们获得了private key,来猜测public key的情况。

“`php

“`

下面就开始破解:

“`bash
➜ Desktop echo $(python -c “print ‘0 ‘*64”) $(php mtRand.php) | xargs ~/script/php_mt_seed-4.0/php_mt_seed
Pattern: SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62 EXACT-FROM-62
Version: 3.0.7 to 5.2.0
Found 0, trying 0xfc000000 – 0xffffffff, speed 65.2 Mseeds/s
Version: 5.2.1+
Found 0, trying 0xf0000000 – 0xf1ffffff, speed 5.5 Mseeds/s
seed = 0xf0430121 = 4030923041 (PHP 5.2.1 to 7.0.x; HHVM)
Found 1, trying 0xfe000000 – 0xffffffff, speed 5.5 Mseeds/s
Found 1
“`

可以看到破解得到的seed和之前的一样。

接下来看一个 njctf中的一个例子,只贴部分关键代码:

“`php

“`

我们的目标是猜测出filename.
这里 `$seed 是 rand(0,999999999)`生成的,我们不知道,但是`$hash = md5(session_id() . $ss);`我们却是知道的,在 cookie的SESSION中,当把cookie中的 PHPSESSID 设为空的时候,session_id()就也是空了,通过结hash,就可以获得 mt_rand() 产生的第一个随机数,然后用 php_mt_seed这工工具爆破种子,就可以直接算出文件名了.

rand() 函数的安全性问题

rand() 函数在产生随机数的时候没有调用 srand(),则产生的随机数是有规律可询的.

具体的说明请看这里http://www.sjoerdlangkemper.nl/2016/02/11/cracking-php-rand/

产生的随机数可以用下面这个公式预测 : `state[i] = state[i-3] + state[i-31] (一般预测值可能比实际值要差1)`写下面测试代码,验证一下:

“`php
=31) {
echo “$randStr[$i]=(“.$randStr[$i-31].”+”.$randStr[$i-3].”) mod 31″.”\n”;
}
}
?>
“`

看一下结果:

![](/static/lingzu/images/15892025160530.png)

发现预测的值,基本都是对的,这样就可以根据之前生成的随机数,预测之后产生的随机数.

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容