MD5 in Projects0:00
Okay, so first up we have one of my old favourites, MD5. Now I've seen this a lot. Every project that I've ever worked on and audited has had MD5 in it somewhere. In some cases it's been used in a completely safe way, such as generating cache keys when using a caching system, but in other applications it's been used in a way that was really easily vulnerable to attack and modification. Okay so here we are in our Book model, and what's happening here is that when the Book is created, the developers wanted to have an easy way to generate a random unique key for the model, so that when they can use it as an authorization method for their API when requesting the Book record.
They're a 32-character string and they have hexadecimal, it's in a hexadecimal value, which means you've got the characters of 0 to 9 and then A to F. So if you see a 32-character string that has those characters only in it, then there's a good chance that it's an MD5, and if it's an MD5 then we can start looking around and trying to see if we can figure out how it was generated. Now as I mentioned before, MD5s are easy to generate, so there are lots of different lists around, and so much so that if you Google for hashes that you find, for MD5s and even SHA-1s and other hashes that you find in places, you will sometimes actually get the result and Google will tell you what it is. So if I go to this tab, for example, we can see here we Googled for this hash at the top,
Time-Based MD5 Slugs4:08
Okay, so let's generate slugs in a different method, and then we'll have a look at how we break into that. Okay, so in our code, we originally had this, we had bookSlug. Now another thing that I've seen around, which is incredibly, incredibly, incredibly common, is the generated MD5 from the time string. And I can see where the thinking of this is that, how do you know what time it was generated? It's going to give you a number, and unless you're generating multiple hashes per second, you're going to end up with a unique hash, and it's never going to repeat itself. So I can see the thinking behind it, but the problem is, if you know when the hash was generated, if you have a rough idea of when it was generated, then all you need to
Brute-Forcing the Hash4:34
So I can see the thinking behind it, but the problem is, if you know when the hash was generated, if you have a rough idea of when it was generated, then all you need to do is run the php script to work through all the different hashes, and that's what we're literally going to do right now. So I'm going to reset my database first, using the php artisan migrate:fresh command. Alright, we're setting the database, it's going to drop the tables, reset everything, and then it's going to give us our new hashes. So we'll grab the hash for the lotOfTheRings, just want to check it's working, so go back to the browser. In here, we're going to throw it in there, it's still working, and we'll just confirm.
checking the result. And as it runs through, it should eventually get to the hash for the Hobbit, the hash that was generated today for that record. Now it's worth pointing out that this is a small search because I know the day that it was generated, I know it was generated in the last couple of minutes, so that's not a huge thing for it to find. It's not that hard to find timestamps and get a rough ballpark of when a record was created in a database. If you think about an API response from Laravel, unless you're specifically hiding the timestamp values, you're going to have createdAt and updatedAt, and you can use those to identify
If you think about an API response from Laravel, unless you're specifically hiding the timestamp values, you're going to have created_at and updated_at, and you can use those to identify timestamps. Also, if you know the ID of the record is incrementing IDs, then you can look at records that were created before and created after to give you another ballpark of the creation time as well. So it's actually relatively easy to figure out a window of time, and then all you need to do in that window is generate a hash for each of the different seconds, and then check that on the site. And as we can see here, it finished a little while ago, it's given us the hash in here,
Predictable uniqueid() Values7:01
that on the site. And as we can see here, it finished a little while ago, it's given us the hash in here, and we can go back to the browser and put that in. In the browser, in the hobbit, going to replace the hash, we're now in here, we now have access. And we cracked that hash because we knew the rough timestamp and it went through all the different options. So that's relatively easy. Okay, so another thing that I often see used is the uniqueId method, which is a method that php has had for a long time. But the problem with uniqueId is it essentially just uses the current time in milliseconds.
And if you know what the predictable value is, you can work out what hash it is to use in order to guess it. And so I'm not going to bother showing you a script running trying to hack unique ID, but the fact is, you could do it exactly the same way that we just did with the md5 of time. And that's worth pointing out when you're looking at the PHP documentation page for this method, they have this big caution here. And to be honest, I really think this needs to be bigger and brighter and near the top and closer to the top than it is, because it's telling you that you should not use this method, and instead you should use random_int, random_bytes, or openssl_random_pseudo_bytes.
and closer to the top than it is, because it's telling you that you should not use this method, and instead you should use random_ints, random_bytes, or OpenSSL random pseudobytes. Because this method is not secure, and so it doesn't use secure randomization to generate its values. And another method I want to quickly mention is the rand() method, and you see this used a lot as well, rand() or mtrand(). And they have the same problem as unique ID in the sense that they're not based off cryptographically secure random generator. And so it is possible with enough input, with enough recon, to actually predict what values come out of there, but it's a lot more complicated, so it's a bit harder to attack.
Using Secure Randomness8:48
And so it is possible with enough input, with enough recon, to actually predict what values come out of there, but it's a lot more complicated, so it's a bit harder to attack than the time-based ones. But similar to what we had with unique ID, we also have the same caution here pointing us to random_int, random_bytes, and random_pseudo_bytes. So when you're generating a random number on php, go for random_int, always reach for this method. And it's really easy to use, all you need is random_int, then the minimum number and the maximum number, and it'll give you a random integer in that range. It's available since PHP 7, which means it's going to be available on any site you're working.
the maximum number, and it'll give you a random integer in that range. It's available since php 7, which means it's going to be available on any site you're working on, unless it's a really old site, in which case you might have other problems if you're running on something really really old, php 5, but you can also get, you can get php implementations of this method as well if you need to run it in your really old application. So this is what you need to use if you're running, if you want to generate random integers in php now. And if you want to do strings, you do have the option of the random_bytes method over here, which generates random, pseudorandom bytes, but that does give you just completely random data.
here, which generates random, pseudorandom bytes, but that does give you just completely random data. If you want to generate a random string in Laravel, then what you want is the Str::random helper. And that generates you a string of the length that you provide, of cryptographically secure random values. So when it comes to generating a key for an API like we had there, or generating any sort of secure token, or anything randomness based, or anything unique based, anything like that, the two methods you want are the Str::random method here, or the random function.
the two methods you want are the str_random method here, or the random function.
