This vulnerability consists of a variable type conversion by the appearance of some essential factors.

Some information

The php console interpreter can be open by typing php -a in your console. Otherwise, there are online projects such as onlinephpfunctions that will help you along. Furthermore, for this examples I will be using var_dump()php's function to propperly see every side of the results.


First of all, we need the presence of a loose comparison (==) operator. The main difference between it and the strict comparison is that only the second one checks that the same type is being compared. Then, both of the variables should be controlled by us. (Knowing the value of one of them we don't control can be sometimes useful too)

The key of this vulnerability

Imagine having this background:
if ($j == $e) {
This is obviously never gonna happen (at least it should), but it's a nice example to make up some ideas.
php > var_dump("0e1337" == 0);
php > var_dump("0e1337" == "0");
php > var_dump(0e1337 == "0");
php > var_dump("2e2" == "200");
As you can see, the conversion is quite easy to understand. XeY stands for print("X"+"0"*Y)represented in python.

A trick

To propperly see the value that the string will return after the conversion, the intval() function can be used.
php > var_dump(intval("2e1"));
php > var_dump(intval("2e2"));
php > var_dump(intval("0e1337"));
php > var_dump(intval("0e1337101"));

Involving hashing methods

As seen before, if both of the values are user-controlled, or at least one does and the other value is known/guessable, it is relatively easy to exploit this vulnerability. However, there are tons of cases where the user-controlled variable is being passed to a hash function like MD5 or SHA1 and then compared through the loose comparison operator.
For this, there's another trick we will be using called Magic hashes. Theese are strings whose specific hash returns a number like the ones we've seen before.
Imagine having this background:
if (md5($a) == sha1($b)) {
In this example, using $a = "0e1337" and $b = "0" won't return true, because after the loose comparison, a hash function is made.
Thanks to PayloadAllTheThings we have a list of magic strings that will return a value like the ones seen before. git repo
To finish with, $a = "240610708" and $b = "10932435112" will definetely return true!