Type Juggling Exploit Demo
Type juggling is a feature within PHP which provides developers some flexibility in comparing variables. It is derived from “loose comparison” (denoted with ==):
As one could determine from the comparison charts, “strict” comparison requires a value to be exactly accurate, whereas loose comparison allows for some wiggle room. An interesting point to note from the loose comparison chart above is that integer values are seen by PHP as equivalent to their string counterparts. When comparing strings to integers in loose comparisons, PHP will attempt to find a common type in order to compare them. Strings will always become integers, allowing for some weird functionality:
Despite $variable2 not being an actual integer, but rather a string, PHP converted both the variables to a common type when executing the code. But the variables don’t have to be string/integer counterparts. In fact, in PHP, they can be anything at all (note – strings not beginning with integers are represented by 0):
My PHP emulator actually threw a verbose statement alerting me to a “non well formed numeric value”, but still went on to subtract “3 slices of pizza” from the integer 1. Thus, the flexibility afforded by type juggling:
As a general rule of thumb, flexibility and convenience often lends itself to security concerns. John Hammond mentioned “PHP is just a bundle of bugs”, and type juggling does the language no favors in this regard. There are many vulnerabilities resulting from this feature, including authentication bypass and crypto/hash attacks. Trovebox and Express Engine serve as such examples. Authentication bypass attacks should be obvious given the examples above; depending on the implementation, the integer 0 could theoretically be computed as equal in value to a password not beginning with a numerical character. To demonstrate this, I spun up a Linux web server running a simple authentication form (huge thanks to Jonathon Schnittger at Developer Drive for providing the majority of the code). The program is simple enough: navigating to localhost/login.php and providing the appropriate credentials will authenticate you and redirect to another page confirming successful sign on:
I introduce a bug to the source code by allowing the variable $password to be compared to other variables:
At lines 2 and 3 we have embedded the administrator credentials for our program. Line 4 contains a rogue variable ($bug) with the value of 1. Line 12 goes on to tell the web app that, if $username == $username (‘admin’ in our example), and $password == $bug in the POST forms, the admin user has successfully authenticated. Even though $password and $bug have drastically different values, PHP type juggling computes them as the same. This allows a malicious actor to authenticate by guessing ‘1’ as the password:
Fortunately this demonstration is not a real world example. Usernames and passwords are (or at least should be) stored in a database with ciphertext values after being salted and hashed, rather than being embedded like in my example. Not to mention actual exploits against this type of vulnerability would be far more sophisticated. Although it is highly unlikely something as dull as this example exists in the wild, type juggling does present serious concerns in PHP applications. As with any development faux pas, there are secure coding concepts for protecting applications from these attacks. Ultimately your best protection comes in using strict comparison whenever possible. By altering my code to compute if($username === $username && $password === $bug), the simulated attack would have not been successful. Least privilege is one of the most foundational concepts in cyber security, and strict comparison arguably serves as an exemplary illustration.