这几天翻以前的php代码审计题练习,遇见了好几个php随机数安全问题,遂总结一下。

php 随机数函数

php有两个随机数函数rand()和mt_rand()。两个函数用法相同,接收两个参数rand(min, max) 返回之间的随机整数(没有参数则默认返回的随机数最大为getrandmax()函数返回值)。

这两个函数的播种函数分别为srand()和mt_srand().

随机数函数安全问题

可以想象,上面两个函数生成的都不是随机序列,实际上大多数编程语言随机函数生成的随机序列都是伪随机序列。它们都是通过一个种子,然后将种子进行各种线性变换生成的序列。这意味着,

  1. 如果知道了种子,那么就可以预测所有的随机数序列。
  2. 如果知道了足够多的随机数序列例子,那么就可以根据以上的随机数序列和随机数生成算法计算出接下来的随机数序列。

当然,如果此类随机数函数不用做类似加密安全功能位置,并不会影响程序的安全性,它的安全问题恰恰来自于开发者误将以上随机数函数当做了加密级的随机函数,这样才产生了安全问题。

php自动播种

自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 给随机数发生器播种 ,因为现在是由系统自动完成的。

那么问题来了,如果每次访问都自动重新播种,那么即使我预测出了同一个种子后面的随机数序列那也无济于事啊。其实php在一个请求进程只会播种一次(实测php5.6可以,php7.2不行),这样的话我们可以先收集随机序列然后在同一个请求进程中预测出接下来的随机序列并进行攻击。

rand()随机序列预测

这篇文章中提到了rand函数后面序列的变化state[i] = state[i-3] + state[i-31]

若是这样,我们就可以先收集rand()函数生成的32位以上随机序列,然后借此预测后面的随机序列。

mt_rand()种子猜解

对与mt_rand()函数我们一般采用种子猜解的方式,这一方面已经有了别人写的现成的工具,我们可以直接拿来使用。mt_rand()的取值最大为2^32,使用以上工具很快就能运算出来。

猜解出seed之后,一般会有好几个解,只要多对比后面几个随机序列,就能确定出其seed了。

相关ctf题

写这篇博客也是因为最近碰到了好几道这样的题目。

0ctf 2016 rand_2

这篇博客challenge29

WooYun Puzzle#3

这篇博客challenge33

Referer

https://xz.aliyun.com/t/31#toc-4 http://wonderkun.cc/index.html/?p=585%EF%BC%8C%E9%9A%8F%E6%9C%BA%E6%95%B0%E4%B9%8B%E5%89%8D%E4%B9%9F%E6%98%AFctf%E7%9A%84%E5%B8%B8%E8%A7%81%E5%A7%BF%E5%8A%BF https://www.freebuf.com/articles/web/99093.html