写在前面
刚刚学习了伪随机数,正好四火师傅找了一道php伪随机数的题来练练手,解题后对伪随机数有了进一步的学习。
伪随机数之再学习
1、首先来解一道题目
枯燥的抽奖(题目地址:http://c8dcf522-27ac-4555-8a2d-4c198683e6d4.node3.buuoj.cn )
打开题目可以看到:
题目是猜字符串,当然是不可能才出来的。我们查看源码,发现了有用代码块:
这只是一个判断正误的代码,但是在第60行导入了check.php
,我们查看这个文件。
这就是产生字符串的代码。
代码审计:
- 开头从
(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)
运行结果:
然后我们将所得的结果用php_mt_seed
爆破得到随机种子。
接下来我们只需要把随机种子带回到check.php
中的mt_srand()
函数中,然后其余不变,输出全部字符即可得到抽奖码,提交后得到flag。
伪随机数再学习
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
,已经写好了,可以直接使用。