Many of the security breaches associated with Mt_rand () have been dug up in the previous period, largely as a result of the erroneous understanding of random number usage. Here again to mention the PHP website manual A pit, see About Mt_rand () Introduction: Chinese version ^cn English version ^en, you can see the English version of a yellow Caution warning. Mt_rand () Use the Mersennetwister algorithm to return random integers, this everyone knows, but the following this article mainly introduces to you about PHP Mt_rand () random number of security related data, the article introduced in very detailed, the need for friends can reference, Follow the small series to learn together.
Many domestic developers are expected to look at the Chinese version of the introduction and the use of Mt_rand () in the program to generate security tokens, core decryption key and so on, causing serious security problems.
Pseudo-Random number
Mt_rand () is not a true random number generation function, in fact the random number functions in most programming languages are generated by pseudo-random numbers. On the difference between true and pseudo-random numbers here, it's just a little bit easier to understand.
Pseudo-Random is a pseudo-random number produced by a deterministic function (common linear congruence), which is generated by a seed (a common clock). This means that if you know the seed, or the random number that has already been generated, it is possible to get the information (predictability) of the next sequence of random numbers.
Simply assume that the function for generating random numbers inside Mt_rand () is: Rand = seed+ (i*10) where seed is a random number seed, I is the number of times that the random numbers function is called. When we know both I and Rand two values, it's easy to figure out the value of the seed. For example rand=21, i=2 into function 21=seed+ (2*10) to get seed=1. It is not very simple, when we get seed, we can calculate the value of Rand when I is any value.
Automatic seeding of PHP
From the previous section we already know that every time Mt_rand () is called, a pseudo-random number is calculated based on the number of seed and current calls. And seed is automatically seeded:
Note: Since PHP 4.2.0, it is no longer necessary to sow the random number generator with Srand () or Mt_srand (), since it is now done automatically by the system.
Then the question comes, in the end when the system automatically completes seeding is when, if each call Mt_rand () will be automatically seeded so cracked seed is meaningless. The manual does not give detailed information on this point. Online to find a circle is not the answer can only go through the source ^mtrand:
Phpapi void Php_mt_srand (uint32_t seed) {/* seed the generator with a simple UInt32 */php_mt_initialize (seed, BG (state)); Php_mt_reload (); /* Seed only once */BG (mt_rand_is_seeded) = 1; }/*}}} *//* {{{Php_mt_rand */phpapi uint32_t php_mt_rand (void) {/* pull a 32-bit integer from the generator state every Other access function simply transforms the numbers extracted here */register uint32_t s1; if (Unexpected (!BG (mt_rand_is_seeded))) {Php_mt_srand (Generate_seed ());} if (BG (left) = = 0) {php_mt_reload ();}--bg (Le FT); S1 = *BG (next) + +; S1 ^= (S1 >> 11); S1 ^= (S1 << 7) & 0x9d2c5680u; S1 ^= (S1 <<) & 0xefc60000u; Return (s1 ^ (S1 >> 18));}
You can see that each call to Mt_rand () will first check if it has been seeded. If you have sown directly to generate random numbers, otherwise call Php_mt_srand to sow. This means that only the first call to Mt_rand () will be seeded automatically during each PHP CGI process. A random number is then generated based on the seed of the first seeding. There are several modes of operation in PHP except CGI (each request starts a CGI process and closes after the request is finished.) Each time you re-read the php.ini environment variable, which leads to inefficiency, it should not be used more, basically, after a process has finished processing the request, standby waits for the next one, processing multiple requests before it is reclaimed (timeouts are also recycled).
Write a script and test it.
<?php//pid.phpecho Getmypid ();
<?php//test.php$old_pid = file_get_contents (' http://localhost/pid.php '); $i =1;while (True) {$i + +; $pid = file_get_ Contents (' http://localhost/pid.php '); if ($pid! = $old _pid) {echo $i; break;}}
Test Result: (Windows+phpstudy)
Apache 1000 Request
Nginx 500 Request
Of course, this test only confirms the number of requests that Apache and nginx processes can handle, and then verifies the conclusion of the automatic seeding just now:
<?php//pid1.phpif (Isset ($_get[' rand ')) {echo Mt_rand ();} else{echo Getmypid ();}
<?php//pid2.phpecho Mt_rand ();
<?php//test.php$old_pid = file_get_contents (' http://localhost/pid1.php '); echo "old_pid:{$old _pid}\r\n"; while ( True) {$pid = file_get_contents (' http://localhost/pid1.php '), if ($pid! = $old _pid) {echo "new_pid:{$pid}\r\n"; for ($i =0 , $i <20; $i + +) { $random = Mt_rand; Echo file_get_contents ("Http://localhost/pid". $random. ". Php?rand=1 "). "; } Break }}
By PID, when the new process starts, randomly gets the output of one of the Mt_rand () two pages:
old_pid:972 new_pid:7752 1513334371 2014450250 1319669412 499559587 117728762 1465174656 1671827592 1703046841 464496438 1974338231 46646067 981271768 1070717272 571887250 922467166 606646473 134605134 857256637 1971727275 2104203195
Take the first random number 1513334371 to blast the seeds:
smldhz@vm:~/php_mt_seed-3.2$./php_mt_seed 1513334371 Found 0, trying 704643072-738197503, speed 28562751 seeds per seco nd seed = 735487048 Found 1, trying 1308622848-1342177279, speed 28824291 seeds per second seed = 1337331453 Found 2, tr Ying 3254779904-3288334335, speed 28811010 seeds per second seed = 3283082581 Found 3, trying 4261412864-4294967295, s Peed 28677071 seeds per second Found 3
Bursting out of 3 possible seeds, the number is rarely manually one test:
<?phpmt_srand (735487048);//manual seeding for ($i =0; $i <21; $i + +) {echo Mt_rand (). " ";}
Output:
The first 20 bits are exactly the same as the script above, confirming that the seed is 1513334371. With the seed we can figure out the random number of calls to Mt_rand () at any number of times. For example, this script I generated 21 bits, the last one is 1515656265 if you have not visited the site after the script has been run, then open http://localhost/pid2.php can see the same 1515656265.
So we get the conclusion:
The automatic seeding of PHP takes place during the first call to Mt_rand () in the PHP CGI process. Regardless of the page visited, as long as the same process processing requests, will share the same original automatic seeding seed.
Php_mt_seed
We already know that the generation of random numbers is dependent on a particular function, which was once assumed to be Rand = seed+ (i*10). For such a simple function, we can of course directly calculate (mental arithmetic) out a (group) solution, but Mt_rand () actually use the function is quite complex and can not be inverse operation. The effective way to solve this is to do a poor job of all the seeds and verify that the seed is correct by making a sequence of random numbers from the seed and then doing a comparison with a known sequence of random numbers. Php_mt_seed^phpmtseed is such a tool that it is very fast and runs 2^32 bit seed for a few minutes. It can blast out the possible seeds directly from the output of a single mt_rand () (example above), and of course it can be exploded like Mt_rand (1,100), which limits the seed of Min max output (which is useful in the example below).
Security issues
With all that said, how can a random number be unsafe? In fact, the function itself is not a problem, the official also explicitly suggested that the generated random number should not be used for secure encryption purposes (although the Chinese version manual not written). The problem is that developers are unaware that this is not a true random number. We already know that the seeds can be burst by a known sequence of random numbers. That is, whenever an output random number or its derived value (reversible push random value) exists on any page, the random number of any other page is no longer a "random number". Examples of common output random numbers such as verification codes, random filenames, and so on. Common random numbers are used for security verification such as retrieving password checks, such as encryption key, and so on. An ideal attack scenario:
In the dead of night, Waiting for Apache (Nginx) to recover all the PHP process (to ensure that the next visit will be re-seeding), access to a verification code page, according to the verification code character inverse introduction of random numbers, and then burst out random number seeds according to random numbers. Then visit the Retrieve Password page, generate a link to retrieve the password is based on the random number. We can easily calculate this link, get back the administrator's password .... Xxoo
Instance
Phpcms mt_rand SEED crack authkey leak rain cows write better than me, look at him is enough
Discuz x3.2 Authkey Leaked this is actually similar. The official has been patched, interested can be analyzed by themselves.