-5

it is possible to brute-force this token (MD5 Hash) of the following script (PHP) in a realistic time (0,5h - 24h)? If the answer is YES, how could I do it, for example with PHP or Python?

$time = microtime();
$secret = MD5('$time' . rand(1, 100));
user126623
  • 159
  • 3
  • 8
  • i want to write a login and register system for my local website, and I asked myself how to crack reset tokens actually @Law29 – user126623 Jun 25 '16 at 21:16

2 Answers2

2

As written, it is quite easy, because PHP will not expand variables inside single quotes. So '$time' is the five constant characters '$', 't', 'i', 'm', 'e', instead of a very long, increasing number.

So this might have been a trick question, to lead someone to say "it's very difficult" when actually it is not.

Supposing it was written

md5("{$time}".rand(1, 100));

then much would depend on the actual timer precision of the attacked platform. microtime() will return a time with microseconds, but it does so by calling gettimeofday. You might therefore only have 100,000 attempts in a single second timespan.

So you need to crack ten million MD5 hashes for every second in your timespan. If you know that the hash was generated in a given hour (today between 15:30 and 16:30), that's 36 000 000 000 attempts you need to run.

On a good hardware you can get about 2-8 million MD5s per second, which means that your cracking needs to run for a time 1-10 times as long as the timespan you need to crack. Of course, using multiple computers would proportionally decrease the time required.

In the worst case (true microsecond resolution) you need about one day for every hour of timespan. If you know that a hash has been generated between 15:30:00 and 15:30:15 today (15 seconds), you can crack it in about six minutes.

Update

From your comment, if this is for your site's security, then I'd strongly suggest you switch to bcrypt hashes (also, check out the link and the documentation it references).

Then, to confirm that such a token is secure, you can send a token built like this:

$secret = 'YourSiteVerySecretPassword';
$date   = date('YmdHis');
// Put whatever you want in the $token.
$token  = "{$username}:{$date}";
$send   = $token . '-' . $bcrypt->hash($secret . $token);

The user will send you back a link which you can explode('-') in two parts separated by a dash:

list($token, $hash) = explode('-', $receivedToken);
if ($bcrypt->verify($secret . $token, $hash)) {
    // Token is valid. You can further explode it using ':',
    // and for example extract the date and time and verify that
    // it is within 24 hours of the current timestamp. Otherwise
    // the token is valid, yes, but it is "stale".
}
LSerni
  • 22,670
  • 4
  • 51
  • 60
0

This was going to be a comment but it got too long,and it's actually an answer: you're probably going about this the wrong way.

What possible use can an attacker have of brute-forcing the token? The only secret protected by the token is the time and the result of the rand() call.

If you send these tokens by mail to the the requesting user and require him to produce the token in order to reset his password, the user will have no difficulty figuring out what the $time it was when he made the request and getting the result of your rand() call, but he won't care either. However, for you to know that the token is valid, you need to record it in your website database. (There are ways that you could avoid recording things in your website database, but those are either even worse from a security point of view or excessively complicated.)

If an attacker makes a fake request, he does not have the token, but he knows the time to within less than a second or so, and so with less than a hundred thousand website requests he can hit on the correct token. The time to do the md5 (whether on a watch or on a supercluster) is irrelevant. If you don't implement some more protection, someone could probably manage to reset somebody else's password, which I assume is what you are trying to avoid.

Since you need to record the request for a password reset in your database anyway, why don't you record and send a totally random token (along with username or request ID and expiry date)?

Law29
  • 721
  • 1
  • 5
  • 10