Random
Last updated
Was this helpful?
Last updated
Was this helpful?
So first thing to do is to check how the login is working on the web browser
We are sending a HTTP request with JSON data of username and password, now lets look at the code base
In red we are checking if the username and password fields are set, then we pass the username into the get_user
function, which we check out soon
In blue, we see a type juggling vulnerability, with the ==
, we can try and set both values equal to each other, for the password, this can be achieved by setting it as an array which will be null
, so now we have to set the $user
variable to null
as well. Lets look at the get_user
function.
So we're basically checking if the username we provided is within in the database, if not, it will return null
, that is good to know as we want to be able to return the username value as null
. Next lets check how the username is being checked in profile.php
So it looks like we are using the strpos
function to check if admin is in the username, and if not, return false, if yes, then run the function to get the flag
Based on this, it is looking for the string admin
within the username we provide. This is flawed as we can pass in something like 1234admin
and that would work.
So we know that we have to set the value of username to have admin in the string and also pass in a username that is not valid so that we can set the value of username to null
We can achieve this by setting the username to 1234admin
and also set the password to null
by making it an array
And this should get you admin access and also the flag!
Now that we have discussed what type juggling is and under which conditions it is performed, let us explore how it can lead to an unexpected outcome of a comparison that can result in an authentication bypass.
Before analyzing our sample web application, let us establish how type juggling can lead to an authentication bypass in PHP.
Strcmp Bypass
As a first simple example, let us consider the following code snippet:
Code: php
Code: http
Note: The behavior of strcmp
was changed in PHP 8.0.0 to throw an error if any argument is not a string. Thus, the bypass only works in PHP versions prior to 8.0.0.
Magic Hashes
In a more realistic scenario, the password is hashed before the comparison, resulting in the comparison of two variables of the data type string
. Consider the following code snippet:
Code: php
Now that we discussed how type juggling could lead to an authentication bypass, let us jump into our sample web application:
Logging in with the provided credentials for the user htb-stdnt
, we can see that we are unauthorized to access the post-login page:
Looking at the network traffic, we can see that the web application sends our login data in JSON format, which is interesting for a PHP web application:
Let us investigate the login logic in the provided PHP code in index.php
:
Code: php
Furthermore, we have the following PHP code in profile.php
:
Code: php
Analyzing the source code, we see two loose comparisons leading to potentially unexpected cases of type juggling. The first is in the password check in index.php
, and the second is in the username check in profile.php
. The username check grants access to all users containing the string admin
in the username. Since we cannot change our username, there is no way to bypass this check easily.
Authentication Bypass
Looking at the file config.php
referenced in the error message it contains the following code:
Code: php
Authentication Bypass
This creates a new MySQL server with the credentials given in config.php
. However, the database is empty. So, let us create a users
table with a dummy user. To do so, we need to create a file called db.sql
with the following contents:
Code: sql
Afterward, kill the docker container we started previously and start a new one with the following command from the directory containing the db.sql
file:
Authentication Bypass
Afterward, we can run the web application using PHP's built-in web server by clicking on Create new launch.json
and selecting the Launch Built-in web server
debugger in the drop-down menu on the left. Then, we can access the web application at the URL printed in the debug console.
Note: Keep in mind that the behavior of type juggling differs depending on the PHP version. Thus, we need to ensure that our local PHP version matches the PHP version used by the target web server.
Since the web application supports JSON parameters, we are not limited to the data type string
, enabling us to bypass the authentication check due to type juggling. The password is not hashed, thus, we can provide any data type to the comparison. Looking back at the table in the previous section, we can see that the comparison 0 == "php"
evaluates to true
in PHP versions before 8.0.0. Thus, if we provide the number 0
as the password and it is compared to the admin user's password, we can bypass the authentication check due to type juggling:
Since we are now logged in as the admin
user, we can access the post-login page.
The prevention of vulnerabilities resulting from type juggling is simple - use the strict comparison operators ===
and !==
instead of the loose ones ==
and !=
. In most cases, the result of a loose comparison is unexpected and undesired. In particular, strict comparisons should always be used for sensitive operations such as authentication.
The function returns 0
if the two compared strings are equal. How can we bypass this authentication check without knowing the admin password? If we supply a variable of the data type array
, the function strcmp
returns null
, resulting in the comparison null == 0
, which is true
after type juggling. We can send an array as a POST variable by sending a request like this:
Our provided password is hashed using SHA-256 and loosely compared to the hashed admin password. If we look at the correct password hash, we can see that it starts with a 0e
followed by only numbers. As discussed in the previous section, PHP will compare two strings numerically if both can be treated as numbers. Since the hashed password is of a valid number format (in this case, the scientific float notation is equal to 0
), we simply need to provide a password for which the hash follows the same format. These hash values are called magic hashes
. Luckily for us, there are pre-compiled lists of values that result in such magic hashes, for example, is a collection on GitHub. Selecting SHA-256, we can see that the password 34250003024812
results in the hash 0e46289032038065916139621039085883773413820991920706299695051332
, which follows the correct format for our bypass. PHP then compares the two hashes numerically, converting both strings to the number 0
and thus evaluating the comparison to true
such that we successfully bypass authentication.
To debug the web application locally, we need to install the VS Code extension. Afterward, we can open the file index.php
in VS Code, click Debug and Run
, and select the PHP Debugger. However, doing so results in an error message. In the debug console, we can see the following error:
The web application attempts to connect to a MySQL instance on localhost, which is currently not running. Instead of installing a MySQL server on our local machine, we can use a container. To match the parameters provided in config.php
, we can start the docker container using the following parameters: