**说到随机函数的应用,作为一个菜鸟,理解的也不是很深刻,在这里之作为一个笔记来记录,以后慢慢将其掌握之后,再在内容上面进行加深。
成都创新互联制作网站网页找三站合一网站制作公司,专注于网页设计,网站建设、网站制作,网站设计,企业网站搭建,网站开发,建网站业务,680元做网站,已为近千家服务,成都创新互联网站建设将一如既往的为我们的客户提供最优质的网站建设、网络营销推广服务!随机函数的作用,常常是用来生成验证码、随机文件名、订单号,如果用来做安全验证的话常常用来生成加密key、token等等。**
1、rand()
常用的随机函数,默认生成0-getrandmax()之间的随机数,不过因为性能问题,已经被mt_rand()函数替代
相关函数:
rand(int $min,int $max)
srand(int $seed),生成时间种子,同一个时间种子下随机生成的随机数值是相同的。
getrandmax()获取大随机数,这里获取的随机数会随系统的不同而不同。如linux大2147483647
2、mt_rand
常用的随机函数,默认生成0-mt_getrandmax()之间的随机数, Mersenne Twister 算法生成随机整数
相关函数:
mt_srand(),生成种子,同一个种子下随机生成的随机数值是相同的。
该函数是产生随机值的更好选择,返回结果的速度是 rand() 函数的 4 倍(手册是是这么写的),我个人并不认同的,我感觉他说的4倍是很多年前的事了。因为mt_rand()使用的Mersenne Twister algorythm是1997的事,所以在很多年前,和rand()在速度上的差异可能是(4倍),自2004年,rand()已经开始使用algorythm,所以现在它们速度上没有太大的区别.
有时候手册也是骗人的,就像一会要说的这个函数造成的问题。
3、uniqid()
生成唯一ID的函数,精确到了微妙,较mt_rand精确。适用场景生成token和生成uuid
具体细节没做研究
4、openssl_random_pseudo_bytes()
适用于生成token,具体详情没做研究
--
今天重点记录一下mt_rand带来的问题,和在CTF中的具体解法。对于这个函数的介绍是有两个版本的,一个是英文版,一个是中文版,去对比一下,在英文版中会多出一个警告:
Caution:This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using random_int(), random_bytes(), or openssl_random_pseudo_bytes() instead.
意思是注意函数的安全,不能用来生成密码安全值,不要引用于加密,如果需要可以适用等等函数代替。其实函数本身是没有问题的,只是使用的方式不当而已。
我没有挖漏洞的经验,所以也不清楚大佬说的这方面的漏洞多不多,但以我个人而言,肯定只会选择看中文版的介绍,并且使用此函数去生成密码安全值。这样就不知道警告,也就会造成安全问题。
首先我们要知道,每一次调用mt_rand()函数的时候,都会检查一下系统有没有播种。(播种是由mt_srand()函数完成的),当随机种子生成后,后面生成的随机数都会根据这个随机种子生成。所以前面也说到,同一个种子下随机生成的随机数值是相同的。同时,也解释了我们破解随机种子的可行性。如果每次调用mt_rand()函数都需要生成一个随机种子的话,那根本就没办法破解。
做一个简单的测试,测试随机数种子相同,后面的每次执行的随机数也相同
脚本:
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
?>
两次执行结果:
可以看到得到的随机数是相同的。
同时我们应该注意,mt_srand()函数播种的时候,只有在第一次调用mt_rand()函数的时候才会使用。所以如果我们知道了第一次生成的随机数值,就可能爆破出随机数种子。
--
接下来就来验证一下
首先爆破出随机数种子,利用工具php_mt_srand
工具链接:https://github.com/lepiaf/php_mt_seed
这个工具的具体用法,也不再着解释,说起来还是挺复杂的,在这里推荐一个文章吧,看完就看一了解个大概,同时还有助于理解随机数
https://×××w.openwall.com/php_mt_seed/README
爆破随机数种子,我们将得到的第一组数进行爆破
得到三组seed值,里面就有我们使用的随机数种子,当然在正常情况下我们是不知道这个数值的,所以还需要去验证。
--
如何验证?
1、只需要将这个种子通过mt_srand()函数生成数值后再调用几组mt_rand()函数生成几组随机数\
2、然后将随机数和我们刚开始得到的随机数对比即可。
测试第一组
测试第二组
测试第三组
可以看到只有第二组的随机数和原来的相同,到这里便成功获取到了seed值。
题目来自于成都大学网络***演练平台--随机数
题目链接:http://ctf.cdusec.org/challenges
题目非常简单,直接就给出了题目随机数的源码以及前几组随机数:
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo mt_rand()."
";
echo "echo flag{".mt_rand()."}"
?>
984489752
619387123
2070958802
2105559368
1909473866
1679323715
1910332168
640569646
1103001695
1871111424
flag
So, Please guess the flag!
理解了上面所说的爆破步骤的话,对这个题目简直太容易了。
1、因为我们不知道××××代表那些数字,但是给出了第一组随机数。上面也说了,只有第一次调用mt_rand()函数的时候才会自动播种,接下来的就会根据这个种子生成随机数。所以我们来利用第一组爆破
2、将seed数值带入到脚本mt_srand()函数当中,去跑flag,因为只要得到seed,接下来不管怎么跑,跑几次,得到的几组数值都是相同的。这里得到两组seed值,测试两次,将得到的flag递交看一下那个正确即可。
随机数这个东西在系统之间和php版本之间是有削微的区别的,比如就CTF这道题目而言,开始我并没有注意php版本问题,当时的测试环境是php7的版本,同样的做法,答案却是不同的,所以结果也一直出不来。
同时也告诉我们,细节决定成败。
因为是刚刚学习这一知识点,可能讲解的也不够详细或者有些许错误。哪位大佬看到不准确的希望给指出,谢谢!
相关链接:
http://php.net/manual/en/function.mt-rand.php
http://php.net/manual/zh/function.mt-rand.php
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。