Challenge #1: Bypassing Passwords with Integers!
This is a demo module, sign up for the course here!
PHP's loose typing and flexible type juggling is one of the features that makes it so flexible, but it also exposes extra risks within your apps. This was especially true before PHP 8.0 was released. As part of that release, some of the type juggling rules were swapped around to make them more secure and less prone to abuse.
We're going to start this module by exploring some of the classic type juggling vulnerabilities before PHP 8.0, and how they can be exploited. This will give us a good introduction to the topic and set the stage for the rest of the module. Plus, it should give you a wake-up call if you're still managing any PHP 7.x apps!
Your Challenge
You need to bypass the password prompt using type juggling, rather than guessing the password.
While this wouldn't normally be possible via a standard form input (even with PHP 7.4!), there are two important aspects to this demo that will work in your favour:
- All numeric inputs are automatically cast to integers or floats.
- The app tries to emulate PHP 7.4's type juggling rules.
Objectives
- Bypass the password prompt using type juggling.
Hint #1
Prior to PHP 8.0, loose comparisons between integers/floats and strings would convert the string into an integer/float. Combine this knowledge with the fact that all numeric inputs are automatically cast to integers or floats, and you should be able to figure out how to bypass the password prompt.
Hint #2
When PHP casts a string to an integer, it will take all the numeric characters from the start of the string and convert them to an integer, stopping at the first non-numeric character.
This means that if you have a string like 123abc
, it will be cast to the integer
123
, dropping the abc
entirely.
You can use this behaviour to quickly find a value that will bypass the password prompt.
Hint #3
In this challenge you need to bypass the password prompt by using type juggling that roughly follows the
type juggling rules from PHP 7.4. This means the correct password (i.e. the one hardcoded in the app)
is a lengthy string that starts with a numeric value (i.e. 7ec8d5879f1af867bd9e10688fd9f726
).
Your task is to trick PHP into casting this string to an integer, which will result in the
prefix being used as the integer value in the comparison.
For example, if the password is the string 7ec8d5879f1af867bd9e10688fd9f726
,
PHP will convert that into the number 7
when it's cast as an integer:
> (int) "7ec8d5879f1af867bd9e10688fd9f726";
= 7
Alongside this, the PHP 7.4 behaviour for loose comparisons between a string and an integer is to
cast the string to an integer. Therefore, with the example above, if you can get PHP 7.4 to loosely compare
the integer 7
to the string 7ec8d5879f1af867bd9e10688fd9f726
, you will end up with
the comparison 7 = 7
, which will evaluate to true
.
The final piece of the puzzle is that this app, for unknown reasons, will cast all numeric inputs to integers. We can abuse this behaviour by passing in integers, and forcing the app to cast the password to an integer for the comparison. This will allow us to bypass the password prompt.
Solution
The valid password is 5f4dcc3b5aa765d61d8327deb882cf99
, which is reduced down to the number
5
when it's cast as an integer.
Therefore, the number you're looking for to bypass the password is 5
.
(int) '5f4dcc3b5aa765d61d8327deb882cf99' == 5
= true
If you submit 5
as your password, it will force the loose comparison of integers, and let you
bypass the password prompt.