An Overview of PHP Type Juggling

Creating secure web applications is hard. There are a number of reasons for this, but one contributing factor is language-specific oddities. Specifically, different programming languages handle data differently and, in some cases, these differences can have a significant impact on security. Let’s take a look at one somewhat-exotic example of a language-specific idiosyncrasy within PHP, type juggling, and what that can mean for your application’s security posture.

PHP does not support explicit type definitions. This means that when you declare a variable in PHP, you don’t specify a type. The type is derived from the context in which is used, so if you assign a string to a variable it becomes a string, if you assign an integer it becomes an integer, etc. This makes developing easier and faster, to some extent.

Until you try and perform comparison operations in PHP. The idea of loose vs. strict comparisons is important here and worth diving into briefly. If you are familiar with any programming language, most have the idea that one equal sign (“=”) is an assignment operator, i.e. x = 5 makes x become the value 5. Then, two equal signs (“==”) is a comparison operator, i.e. x == 5 checks to see if x is 5 and returns True if so. Three equal signs (“===”) is also a comparison operator, but it is strict where two equals is considered loose. The difference between these two comparison operators is much more significant than just a single character, however, as loose comparisons result in implicit data type conversions that lead to Type Juggling.

The use of loose comparisons with user-controlled variables could allow an attacker to purposefully juggle the type of the variable being compared to result in an unintended result, subverting the intended application logic. The table below is fairly large, but if you look at the differences between the two, you’ll see a number of different outcomes from the same comparisons, depending on whether you are using loose or strict.

Different outcomes from loose vs. strict comparisons – https://www.php.net/manual/en/types.comparisons.php

So 1 lousy equal sign makes a difference, but what can an attacker actually do with this in practice? Well in PHP, researchers have discovered “magic hashes“. These are valid hashes (MD5, SHA1, etc.) that evaluate as integers, so for example a full MD5 hash that equates to “0” when doing a loose comparison. Depending on code logic, magic hashes can be passed in to cause unintended comparison results and allow an attacker to reach code which should be unreachable, bypassing application logic in order to gain unauthorized access. Whether or not this use case can be abused in any meaningful way is always going to be application-specific, and likely require some level of white-box testing to analyze the underlying application code.

In Summary – How Do You Prevent This?

Always use strict comparisons, particularly in languages like PHP that don’t support explicit variable type definitions, in order to avoid type juggling issues that can have unintended consequences. On a more broad note, language-specific developer training is important for organization’s doing custom software development for this reason. There are a ton of resources out there to do formal training or informal, self-guided training to accomplish these goals, through organizations such as Secure Code Warrior. If your concerned about your application’s security or want to take your security assessment game to the next level and get a more in-depth understanding of your current application security posture, talk to us about a white-box penetration test that includes code review.