Implementation and Prediction Techniques of the rand function in the glibc Library
Thanks to 0CTF, I held a very deep CTF competition at Jiaotong University.
This competition has a web question. The question is very simple and is roughly as follows:
60) { session_destroy(); die('timeout');} else { $_SESSION['time'] = time();}echo rand();if (isset($_GET['go'])) { $_SESSION['rand'] = array(); $i = 5; $d = ''; while($i--){ $r = (string)rand(); $_SESSION['rand'][] = $r; $d .= $r; } echo md5($d);} else if (isset($_GET['check'])) { if ($_GET['check'] === $_SESSION['rand']) { echo $flag; } else { echo 'die'; session_destroy(); }} else { show_source(__FILE__);}
There is no other test site, that is, let you predict the output of rand. It looks really simple. The function named rand () is actually a pseudo-random function generator that can make predictions. In addition, there is no limit on the number of submissions for a question, and the interval between two submissions is limited. Even the competitor attack model is fixed: brute-force splitting should not be used (but I used it ), instead, the rand () function output after data prediction can be collected after several requests.
I found a lot of information in China and did not find details about the implementation of the rand () function. I am also self-defeating. Instead of looking for the source code, I listened to an article and cracked it. The result is not good luck. Only gg can be used.
The correct solution is available only after reading the blog posts from abroad. The original article elaborated in detail the glibc rand function usage, good English can directly read the original http://www.mscs.dal.ca /~ Selinger/random /. For future convenience, I will translate the general content as follows:
Rand () is initialized by a singned int seed. The generated process is non-linear. However, in linux, man is slightly misleading. After Initialization is complete, the generation of random numbers is linear, which is actually a linear shift feedback register. The simplest case for Amway, which has never learned cryptography, is that the linear shift feedback register actually extracts the output of some previous special positioning and performs an operation (mostly different or ), and then as the current output. It is common in the Generation Process of some stream passwords. This can be understood by analogy with the Fibonacci sequence.
In this way, rand () can be broken, and only enough old output can be obtained. So how does rand () work? The seed range of rand () is 0 ~ 2147483647 (2 ** 31-1), initialize the first 34 internal vectors r0 ~ R33:
(1) r0 = s(2) ri = (16807 * (signed int) r(i-1)) mod 2147483647 (for i = 1...30)(3) ri = r(i-31) (for i = 31...33)
Note that the step of multiplication 16807 is performed in a signed Int that is large enough, so no overflow will occur before the modulo operation. And before multiplication,RI-1 is also converted to signed 32-bit int. However, the only possible negative value of this value appears when I = 1, that is, when s> = 2 ** 31. It can be seen that the modulo operation is 0 ~ A value between 2147483646, even if the previous number is negative.
Therefore, r34 follows the following feedback loop:
(4) ri = (ri-3 + ri-31) mod 4294967296 (for i ≥ 34)
R0...R343 will be discarded. The first output Oi is actually:
(5) oi = r(i+344) >> 1
Note that this one-bit operation removes the last bit, and the actual number of valid bits is 31.
Linear Property Analysis:
Although the last bit is discarded, but the effect is not big, we can still get a linear output sequence. Combined with (4) and (5) Options:
(6.1) oi = o(i-31) + o(i-3) mod 2**31, for all i ≥ 31or (6.2) oi = o(i-31) + o(i-3) + 1 mod 2**31, for all i ≥ 31
The original article also provides a simple version of the random function implemented in C language, which is attached to the following:
#include
#define MAX 1000#define seed 1main() { 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
> 1); }}