Not So Obvious PHP Vulnerabilities

Coding_Karma
5 min readJun 29, 2022

--

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?

Basic Equal

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.

Type Casting

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.

php 7.4.3 vs php 8.1

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.

13 is passed before and returns true

So ultimately we can loose == is really wacky and === should be used. A great way to depict all the various behaviors is attached below.

Loose Comparison
Strict Comparison

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.

Magic Hash

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

Exercise-1

The input string should be equal to “0” and it could be a number it’s easy to see answer is 0

Solved E-1

Exercise-2

E-2

Passing test to the example-2 returns a hashes value in URL.

Hashed Value

Let’s try to decode it and see what is this about?

MD5 Hash

With this knowledge we know passing any value that returns e0<numbers> means it’ll be evaluated as zero. So let’s pass240610708 .

E-2 Solved

So take away is md5(240610708) = 0e462097431906509019562988736854 = 0 (when ==)

Example-3

This challenge expects you to enter a username and password.

Name and Password

Now it takes the inputs and calculates the hash and displays it, to detect the hashing I passed admin:admin

Hash

Found hash is again md5 but this time it essentially does name.password

Hash Found

So passing 240610708 as 24061 and 0708 would work.

E-3 Solved

Example-4

For final example, we see a couple of restrictions on the input expected.

E-4

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!

E-4 Solved

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!

--

--