CTF Web安全

PHP mt_rand 随机数安全

Posted on 2020-01-02,3 min read

函数介绍

mt_rand(),用于产生一个随机数,用Mersenne Twister算法的特性,有两个可选参数(min,max)
mt_rand(5,15)随机产生5-15之间的随机数
mt_rand()随机产生0-mt_getrandmax()之间的伪随机数

伪随机数:

伪随机数,并不是真正的随机,如果种子不变,那么这个伪随机数存在一定风险

mt_rand()安全问题:

mt_rand就是一个伪随机数生成函数,通过一个种子产生伪随机数,如果知道了种子,或者已经产生的随机数,都可能获得其他随机数的信息
假设mt_rand()生成算法为,rand=seed+(i*10),seed是种子,这是我们不知道的,i是第几次调用,如果我们知道rand(结果)和i(第几次调用)那么就能反推出来seed(种子)的值,拿到种子,就能利用种子,自己调用mt_rand()生成结果

[GWCTF 2019]枯燥的抽奖
进入题目,随手翻翻有什么东西。robots.txt。源代码。源码泄露。都看看

找到一个php文件。访问看看

OK。程序源码

这段代码就是根据rand函数随机生成一个seed(种子),然后去mt_rand生成随机数。然后把字符串前十个输出给我们
很明显。这题就是伪随机数。由于我们已经知道了前面10个字符。那么就可以通过php_mt_rand工具来破解
https://www.openwall.com/php_mt_seed/
我们先来通过那10个字符串转换为php_mt_seed可识别的格式

str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
#源代码中的字符串
str2='xaLyvX6QTh'
#给你的10个字符串
str3 = str1[::-1]
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)

得到结果

23 23 0 61 0 0 0 61 47 47 0 61 24 24 0 61 21 21 0 61 59 59 0 61 32 32 0 61 52 52 0 61 55 55 0 61 7 7 0 61

使用php_mt_seed来获取seed的值,这里我的seed值为751184378

用seed的值重新播种。注意。这里用PHP7.1.0+版本。才能获取正确结果

<?php
mt_srand(751184378);
$str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$len=20;
$str2='';
for($i=0;$i<$len;$i++){
	$str2.=substr($str1,mt_rand(0,strlen($str1)-1),1);
}
echo $str2;
?>

就是照着源代码打一遍。只不过mt_srand换成我们已知的
拿到flag

下一篇: pwnable.kr(collision)→