问题描述
有人知道是否有人使用rand()的弱点来预测利用它的时间或事件吗?诸如在电子游戏中生成代币或作弊之类的事情?
Does anybody know if there was a time or event where somebody used rand()'s weakness in order to predict exploit it? Something like generating tokens or cheating in video games?
在 PHP 7 之前,rand() 很容易被破解.事实上,这里有一些 C 代码,归功于 Peter Selinger,可以预测给定种子的值:
Since prior to PHP 7, rand() was very easy to crack. In fact here is some C code, credit to Peter Selinger, that predicts the values given a seed:
#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);
}
}
再说一次,有没有使用这个弱点来预测下一个随机数并利用某些东西的时候?
So once again, was there a time when this weakness was used in order to predict the next random number and exploit something?
谢谢!
推荐答案
在 PHP 7 之前,PHP 使用 LinearCongruential Generator 算法生成一个随机数或简称 LCG.该算法的工作原理如下:
Before PHP 7, PHP use Linear Congruential Generator algorithm to generate a random number or in short LCG. The algorithm works as follow:
next_random = (previous_random * a + c) % m
previous_random = next_random
当你第一次做随机数时,显然没有previous_random 数.这就是我们提供种子的原因.所以,种子只是第一个 previous_random 值.
When you first make a random, obviously, there is no previous_random number. That's why we provide seed. So, seed is just a first previous_random value.
现在,我们知道了算法,但我们需要知道 PHP 使用的 a
、c
和 m
的值是什么.我相信每个版本的 PHP 都使用不同的值.但是假设我们不知道这些值,我们如何猜测这个值.就我而言,我使用的是 PHP 5.6.15 Windows.
Now, we know the algorithm, but we need to know what the value of a
, c
, and m
that PHP use. I believe that each version of PHP use different value for those. But let say we do not know those value, how do we guess this value. In my case, I am using PHP 5.6.15 Windows.
srand(0);
var_dump(rand()); // 12345
var_dump(rand()); // 5758
所以,m = getrandmax() + 1
.由于我们的种子是 0,所以我们的 c = 12345
.为了得到值a
,我们可以使用简单的循环来猜测a
.
So, m = getrandmax () + 1
. Since our seed is 0, so our c = 12345
. To get value a
, we can use simple loop to guess a
.
$m = getrandmax () + 1;
for($a = 0; $a < $m; $a++)
if ((($a * 12345 + 12345) % $m) == 5758)
var_dump($a); // in my case, 20077
或者你可以像这样获得价值a
or you can get value a
like this
srand(0); rand(); // 12345
srand(1); rand(); // 32422
// so a = 32422 - 12345 = 20077
现在,我可以编写与当前 PHP 版本相同的随机函数.
Now, I am able to write the same random function as my current PHP version.
class visal_rnd
{
function __construct($seed = 0) {
$this->seed = $seed;
}
function rnd() {
$this->seed = ($this->seed * 20077 + 12345) % 32768;
return $this->seed;
}
}
不过
我能够预测我自己的 PHP 版本,因为我对我当前的环境有很多了解,我知道一些以前的随机,我知道种子.如果攻击者的知识几乎为零,就不容易被攻击.
However
I was able to predict my own PHP version because I have so much knowledge about my current environment, I know a few previous random, I know the seed. If the attacker has almost zero knowledge, it would not be easy to attack.
PHP 7.0+,默认使用 Mersenne Twister.有比线性同余生成器更多的参数需要猜测.所以,它需要更多的知识.
PHP 7.0+, by default, use Mersenne Twister. There are more parameters to be guessed than Linear Congruential Generator. So, it requires more knowledge.
取决于您向公众公开了多少信息.如果你只生成一个随机数,而攻击者不知道 a
、previous_random
、c
和 m
.攻击者不可能预测下一个随机数.
Depends on how much information you have exposed to the public. If you generate only one random number and attacker has no knowledge of a
, previous_random
, c
and m
. It is impossible for attackers to predict the next random number.
这篇关于PHP 的 rand() 函数是否曾被用作漏洞利用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!