Pages

August 22, 2012

Not So Random Numbers. Take Two

George Argyros and Aggelos Kiayias have published recently an awesome research concerning attacks on pseudo random generator in PHP. However, it lacked practical tools implementing this attack. That is why we conducted our own research which led to the creation of a program to perform the bruteforce of PHPSESSID.

If it happened, the microseconds between our requests zeroed. By sending requests with dynamic delays it is possible to synchronize local value of microseconds with the server one.

Request Twins

The principle of this technique is simple. The attacker needs to send two requests: the first one — to reset their own password and the second one — to reset that of an administrator. The gap between microseconds will be minimal.

To sum up, an MD5 PHPSESSID hash is bruteforced for microseconds, the deltas of subsequent time measurements, and pid. As for pid, the authors have not mentioned such a great helper as Apache server-status which reveals among other information the pids of the processes which serve the requests.

To realize the bruteforce, a module for the popular program PasswordsPro has been initially created. However, this solution made it impossible to take into account the positive linear correlation between deltas of microseconds, so it bruteforced the full range of values. The speed was about 12 million hashes per second.

The speed is about 16 million hashes per second, seed calculation takes less than an hour on 3.2 GHz Quad Core i5.

Having pid and php_combined_lcg one can compute the seed used in mt_rand. It is generated this way:

(timestamp x pid) XOR (106 x php_combined_lcg())

Besides, php_combined_lcg is used as additional entropy for the uniqid function (if it is called with the second argument being true).

So, if a web application uses standard PHP sessions, it is possible to obtain the random numbers generated via mt_rand(), rand(), and uniqid().

How can we get mt_rand seed through one of the random numbers leakage?
The seed used for mt_rand is an unsigned integer 2^32. If a random number leaked, it is possible to get the seed using PHP itself and rainbow tables. It takes less than 10 minutes.
The scripts to generate rainbow tables, search the seed, and ready-made tables are available here: http://www.gat3way.eu/poc/mtrt/

What to look for in the code?
All the mt_rand(), rand(), uniqid(), shuffle(), lcg_value(), etc. The only secure function is openssl_random_pseudo_bytes(), but it is rarely used in web applications. The main ways of defense against such attacks are the following:

MySQL function RAND() — it can be also predicted though.

Suhosin patch — does not patch mt_srand, srand. The Suhosin extension should also be installed.

1. connect to a web server and send request pairs: the first one to a non-existent page so that it will take a minimum time for the web-server to return the response, and the second one to our target web-application2. get an average time interval between sending an HTTP request and receiving the response (= RTT)3. when the seconds in Date HTTP-header of the two requests changed we begin to approximate the time of remote microseconds in local time using RTTs of the two requests divided by two and offsetting the delay between requests4. additionally if session_start() is called somewhere deeper in the code, you may try to install the web-app locally and get the approximate time when it is called.