Table of contents



Prerequisites

  • Know basic PHP
  • Be familiar with the concept of value “types” (string, integer, float…)

Introduction

PHP is a very famous and flexible backend programming language that aims to facilitate developer’s lives. Unfortunately, this flexibility can sometimes lead to more or less critical vulnerabilities.

In PHP, type juggling is a functionnality that allows developers to be more flexible when they use the language, but it can also be dangerous when it’s not used carefully. There are a ton of challenges about this subject so I hope this article will help you to understand it better.

I will first explain in more detail what type juggling is, why it can cause security issues and then we will see a better and more concrete example of an exploit that abuses it.

Comparisons in PHP

PHP has a functionnality called type juggling, which means that when you compare two values, PHP will change one’s type to match the other’s. For example:

<?php

if("1" == 1){
	echo "True";
} else {
	echo "False";
}

?>

This code compares a string with an integer and indicates if the values are equal or not.

In this case, the script will return True, and that is thanks to type juggling

When running the code, PHP will convert the string to an integer to be able to compare the two values. This condition can also we written like this

1 == 1

And that is True

This functionnality can really make your life easier when you’re working with multiple variables types and user inputs, but it can also be very dangerous, so use it carefully.

What causes the vulnerability

It is actually very simple and logical, probably even for someone that doesn’t know PHP. Let’s take the same example as before and tweak it a little bit:

<?php

if("1 2 3 foo" == 1){
	echo "True";
} else {
	echo "False";
}

?>

Now, what do you think this code will return ?

Well, because of type juggling, it will return True – but that’s false, right?

Yes, and no… What happens when the comparison is made is that PHP takes an integer from the string, and compares it with 1. And because our string contains “1”, the condition is True

What happens if we remove the “1” from the string ?

<?php

if("2 3 foo" == 1){
	echo "True";
} else {
	echo "False";
}

?>

This time, the condition will be False because PHP won’t find “1” in the given string.

But it doesn’t end there, here is what happens if instead of comparing a string to 1, we compare it to 0:

<?php

if("Hello World" == 0){
	echo "True";
} else {
	echo "False";
}

?>

In this case, the condition will be True because PHP is going to change the type of the string to an integer, which will be equal to 0 because a string doesn’t have “an integer value” and 0 is the default value.

Semi-Patched

Every example I just showed you works in PHP 7.X, but that is not the latest PHP version, 8.X is.

This new version added, among other things, modifications regarding type juggling. To make it as simple as I can, they made the functionnality “smarter” by changing the way value’s types are modified.

Let me explain this with an example:

<?php

if("Hello World" == 0){
	echo "True";
} else {
	echo "False";
}

?>

In PHP 8.X, instead of trying to make “Hello World” an integer, PHP will make 0 a string (thus making it “0”) and the condition will look like this in the end:

if("Hello World" == "0")

And that will return False

But this part would not be called “Semi-Patched” if the problem was fully solved. Here is another example:

<?php

if(123456789 == 123456789.0000000000){
	echo "True";
} else {
	echo "False";
}

?>

When comparing the two values, PHP will turn 123456789.0000000000 into an integer because it has no decimal value. The condition will then return True, which is mathematically correct but could allow an attacker to bypass length restrictions

Here is a table that shows the different results when a loose comparison (when PHP uses type juggling) occurs in PHP 7.X

Pasted image 20230107010517

Better example

I will use a “PHP Type juggling” challenge I made as an example for this part.

I will try to explain the code as much as I can, so don’t worry if you’re not comfortable with PHP.

Here is the backend of a login page:

<?php

session_start();

if(isset($_POST['password']) && isset($_POST['username'])
{

	$username = $_POST['username'];

	if($username === "admin" && strcmp(bin2hex(openssl_random_pseudo_bytes(10)),$_POST['password']) == 0)

	{

		$_SESSION['isAdmin'] = 1;

		header('Location:admin.php');

	} else {

		header('Location:index.php?error=credentials');

	}

}

?>

First, we make sure that the two POST parameters (used to pass the username and the password) are not empty. This line is not vulnerable.

The vulnerability is in the next condition, the one that checks the password. The strcmp function is used to compare a randomly generated password with the user’s input.

We compare the input with a randomly generated password because the goal of this challenge is not to figure out what the password is but rather to bypass the condition

The strcmp function compares two strings and returns 0 if they are equal. To know if they are, we have to check if the function returned 0 or not.

What we can see is that this verification is made using a loose comparison (only two = were used)

And you should know that strcmp returns NULL if one of the two passed arguments is not a string. Knowing that, we just have to enter something else than a string for the password, and the function will return NULL

By looking back the to loose comparison table, the condition NULL == 0 is True, so the whole comparison will also be True, like if the right password was entered.

How to avoid type juggling issues

There’s no magic method to avoid these problems all the time, but it is highly recomended to use strict comparisons (use three = instead of two) as often as you can, if not all the time.

Otherwise, you can also verify that the user entered two strings and not a string and an array (for example). Never trust user input

Conclusion

PHP is overall a good programming language, flexible and easy to get comfortable with. But all these advantages come at a cost, and one careless mistake can expose your application to critical vulnerabilities, that’s why it is important to know how PHP works.

I hope this post helped you understand what is type juggling, if you have any questions or if I made English mistakes feel free to contact me on discord.

Here are a few links if you want to practice exploiting type juggling vulnerabilities

https://theblackside.fr/challenges/web/PHP---Quirk

https://theblackside.fr/challenges/web/super_secure_local_access

https://www.root-me.org/en/Challenges/Web-Server/PHP-type-juggling

Further documentation

https://owasp.org/www-pdf-archive/PHPMagicTricks-TypeJuggling.pdf