伪随机数之再学习

写在前面

刚刚学习了伪随机数,正好四火师傅找了一道php伪随机数的题来练练手,解题后对伪随机数有了进一步的学习。

伪随机数之再学习

1、首先来解一道题目

枯燥的抽奖(题目地址:http://c8dcf522-27ac-4555-8a2d-4c198683e6d4.node3.buuoj.cn

打开题目可以看到:

1

题目是猜字符串,当然是不可能才出来的。我们查看源码,发现了有用代码块:

2

这只是一个判断正误的代码,但是在第60行导入了check.php,我们查看这个文件。

3

这就是产生字符串的代码。

代码审计:

  • 开头从(0,999999999)中任取一个数用mt_srand()函数作为随机种子
  • 然后定义了一个长字符串$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  • 定义最后结果的长度为20,for循环来抽取20个字符
  • for循环内每次用mt_rand()函数$str_long1中随机出开始抽取一个字符然后拼接起来。
  • 最后$str_show只展示了10个数,也就是题目显示的前十个字符。

既然是伪随机,如果mt_srand()使用的随机种子相同,那么之后生成的字符串一定是一样的。

目前,可以使用种子爆破工具php_mt_seed来获取,但是我们首先需要的到所需的参数。

我们用脚本反解,需要修改少量题目代码:

str1 =  'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'   #待抽取字符串
str2 = '2wiBLXc8VJ'     #生成的前十个字符
length = len(str2)     #已生成的长度
res = ''
for i in range(len(str2)):
  for j in range(len(str1)):
     if str2[i] == str1[j]:
            res += str(j) + ' ' + str(j) + ' ' + '0' + ' ' + str(len(str1) - 1) + ' '   #逆向出参数
          break

print(res)

运行结果:

4

然后我们将所得的结果用php_mt_seed爆破得到随机种子。

5

接下来我们只需要把随机种子带回到check.php中的mt_srand()函数中,然后其余不变,输出全部字符即可得到抽奖码,提交后得到flag。

6

7

伪随机数再学习

php伪随机数漏洞

1、php伪随机数的两个函数
mt_srand(seed); 
函数播种 Mersenne Twister 随机数生成器。
参数:seed 可选,规定播种值。

mt_rand();
函数使用 Mersenne Twister 算法生成随机整数。
参数:
min    可选。规定返回的最小数。默认是 0。
max    可选。规定返回的最大数。默认是 mt_getrandmax()。

我们来写一段代码:

<?php
mt_srand(12345);
echo mt_rand()."<br/>";
?>

输出:1996335345

改写代码为:

<?php
mt_srand(12345);
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
?>

输出结果:

1996335345
1911592690
679411342
280691776
394962642
85382868

注意到,第一个结果与第一次的结果相同。如果结论还不够明显的话。

我们再次修改代码:

<?php
mt_srand(12345);
echo mt_rand()."<br/>";
mt_srand(12345);
echo mt_rand()."<br/>";
mt_srand(12345);
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
echo mt_rand()."<br/>";
?>

输出结果:

1996335345
1996335345
1996335345
1911592690
679411342
280691776

结论显而易见了,当随机种子确定时,生成的伪随机数就会确定。

其实,这就是伪随机数的漏洞,存在可预测性。

生成伪随机数是线性的,你可以理解为y=ax,x就是种子,知道种子和一组伪随机数不是就可以推y(伪随机数了吗),当然实际上更复杂肯定。

即:

我知道种子后,可以确定你输出伪随机数的序列。

知道你的随机数序列,可以确定你的种子。

对于种子爆破就可以使用php_mt_seed,已经写好了,可以直接使用。

相关连接:

php_mt_seed种子爆破安装
php_mt_seed种子爆破使用

-------------本文结束感谢您的阅读-------------