是否有一段时间PHP的rand()函数被用作漏洞?

时间:2017-07-08 11:04:11

标签: php events random exploit weak

有人知道是否有时间或事件有人使用兰德()的弱点来预测利用它?在电子游戏中产生代币或作弊的东西?

自PHP 7之前,rand()很容易破解。事实上,这里有一些C代码,归功于Peter Selinger,它预测了种子的价值:

#include <stdio.h>

#define MAX 1000
#define seed 1

main() {
  int r[MAX];
  int i;

  r[0] = seed;
  for (i=1; i<31; i++) {
    r[i] = (16807LL * r[i-1]) % 2147483647;
    if (r[i] < 0) {
      r[i] += 2147483647;
    }
  }
  for (i=31; i<34; i++) {
    r[i] = r[i-31];
  }
  for (i=34; i<344; i++) {
    r[i] = r[i-31] + r[i-3];
  }
  for (i=344; i<MAX; i++) {
    r[i] = r[i-31] + r[i-3];
    printf("%d\n", ((unsigned int)r[i]) >> 1);
  }
}

再一次,有没有时间使用这个弱点来预测下一个随机数并利用某些东西?

谢谢!

1 个答案:

答案 0 :(得分:0)

在PHP 7之前,PHP使用Linear Congruential Generator算法生成随机数或简短的LCG。该算法的工作原理如下:

 next_random = (previous_random * a + c) % m
 previous_random = next_random

当你第一次随机出现时,显然没有previous_random数字。这就是我们提供种子的原因。因此,种子只是第一个previous_random值。

现在,我们知道算法,但我们需要知道PHP使用的acm的值。我相信每个版本的PHP都使用不同的值。但是,让我们说我们不知道那些价值,我们如何猜测这个价值。就我而言,我使用的是PHP 5.6.15 Windows。

srand(0);
var_dump(rand());  // 12345
var_dump(rand());  // 5758

所以,m = getrandmax () + 1。由于我们的种子是0,所以我们c = 12345。要获得值a,我们可以使用简单循环来猜测a

$m  = getrandmax () + 1;
for($a = 0; $a < $m; $a++)
   if ((($a * 12345 + 12345) % $m) == 5758) 
       var_dump($a);  // in my case, 20077

或者您可以像这样获得价值a

srand(0); rand(); // 12345
srand(1); rand(); // 32422
// so a = 32422 - 12345 = 20077

现在,我可以编写与当前PHP版本相同的随机函数。

class visal_rnd 
{
    function __construct($seed = 0) {
        $this->seed = $seed;
    }

    function rnd() {
        $this->seed = ($this->seed * 20077 + 12345) % 32768;
        return $this->seed;
    }
}

然而

我能够预测自己的PHP版本,因为我对当前的环境有如此多的了解,我之前知道一些随机的,我知道种子。如果攻击者的知识几乎为零,那么攻击就不容易了。

Mersenne Twister

默认情况下,PHP 7.0+使用Mersenne Twister。与线性同余生成器相比,有更多参数需要猜测。所以,它需要更多的知识。

线性同余生成器是否错误?

取决于您向公众公开了多少信息。如果您只生成一个随机数且攻击者不了解aprevious_randomcm。攻击者无法预测下一个随机数。