Not So Obvious PHP Vulnerabilities
Hey Everyone!
Today I am going to blog about 2 vulnerability types which are tough to detect and hence often over-looked.
Type Juggling
Before we get started on what’s “type juggling” vulnerability and how to exploit it we gotta understand what is even type juggling.
In PHP, there are two ways of comparing values ==
and ===
first one is used to compare “value” the variable holds and second one compares values as well but also accounts for “data type”.
Let’s use some code to understand what does this mean?
Now let’s get a little bit creative what happens if $b=’0'
what this does is essentially is making $b
a string and let’s see what happens.
The reason behind this behavior is simply because the 0
is extracted from the string and compared with value.
This issue however is fixed in php8.1
shown below.
What happens if there’s string and numbers? The comparison would still return true
. Depending on the order of in which the string is passed.
So ultimately we can loose ==
is really wacky and ===
should be used. A great way to depict all the various behaviors is attached below.
Magic Hashes
Another really interesting vulnerability is called “Magic Hashes” where passing certain values and applying hashing functions on them would lead to value turning 0
. In simple terms md5(input) = 0
so we can see how this is a problem combined with what we saw above.
A specific example is md5(specific-value) = e01234568 (as long as after e0 it’s followed by numbers) it will always be equal to zero.
Exercises
As always, let’s look at some type juggling examples and maybe even analyze some of the code running behind the screen.
To do this I am going to use https://github.com/TROUBLE-1/Type-juggling
Shout-out to @trouble1_raunak for this amazing exercise on type-juggling.
Example-1
The input string should be equal to “0” and it could be a number it’s easy to see answer is 0
Exercise-2
Passing test to the example-2 returns a hashes value in URL.
Let’s try to decode it and see what is this about?
With this knowledge we know passing any value that returns e0<numbers>
means it’ll be evaluated as zero. So let’s pass240610708
.
So take away is md5(240610708) = 0e462097431906509019562988736854 = 0 (when ==)
Example-3
This challenge expects you to enter a username and password.
Now it takes the inputs and calculates the hash and displays it, to detect the hashing I passed admin:admin
Found hash is again md5 but this time it essentially does name.password
So passing 240610708
as 24061
and 0708
would work.
Example-4
For final example, we see a couple of restrictions on the input expected.
Doing a little bit of reading, it turns out e0<numbers>
hash format can also be produced by alphanumeric
values thanks to @spazef0rze for an amazing blog post explaining the inner working and he was kind enough to provide a list of hashes too on https://github.com/spaze/hashes
Another amazing read to understand the inner workings can be found here https://offsec.almond.consulting/super-magic-hash.html
So something like hashcatyVgxeio33XWR
should do the trick let’s try it!
There’s few more exercises provided in the repo which involves brute-forcing values maybe I will revisit those some other day.
Looking at the code , it’s easy to notice the reason behind this mess was ==
and not using ===
.
So final conclusion, drawn is using ===
is better choice and updated version of php which has a better type juggle handling.
Additionally, performing salting to the hashes would randomize them and maybe such attacks can be avoided in that capacity too (overlooking small chances of hash collision) which is extremely remote.
Thank you!