Level 26 - Level 27
Overview
This time we got an login form with a link to the source code.
Source Code Analysis
Let's take a look at the source code.
This PHP code appears to be a simple authentication system with a MySQL database. Let's break down the main components:
Database Structure
There's a table named
users
with columnsusername
andpassword
.The
CREATE TABLE
statement in the comments defines the structure.
Functions
checkCredentials
: Takes a username and password, checks if the combination exists in the database, and returnsTrue
if valid.
validUser
: Checks if a given username exists in the database and returnsTrue
if it does.
dumpData
: Retrieves data for a given username from the database and returns it as a string.
createUser
: Creates a new user with a given username and password.
Form Handling
The script checks if the
username
andpassword
parameters are present in the$_REQUEST
.If submitted, it connects to the MySQL database and performs the following actions:
Checks if the user already exists.
If yes, it checks the credentials.
If valid, it displays a welcome message and the user's data.
If invalid, it shows an error message.
If the user doesn't exist, it creates a new user.
If not submitted, it shows an HTML form for entering a username and password.
Security Considerations
There are some security checks, such as ensuring the username doesn't contain extra whitespaces using the
trim()
function and limiting the length of usernames and passwords to 64 characters.The code uses
mysqli_real_escape_string
to prevent SQL injection.
The code mentions that the database is cleared every 5 minutes.
There's a comment indicating a bug in the
dumpData
function that was fixed by usingprint_r($row, true)
.
Identifying the Vulnerability
If we take a close look at the dumpData()
function, it first fetches all the users with the username $user
and it loops through the results, if it contains more than one value [ i.e. an array of values ], printing every value.
We know that there should be a username "natas28
", based on the previous natas levels, which has the password for the next level. Since, the dumpData()
function prints all the values, we can leverage this vulnerability by creating another user with the same username "natas28
" [ its possible, since username field in the database structure don't have the UNIQUE
constraint ], which will print all the passwords for the users with the same username, including the password for the next level.
Generating the Payload
Things to Bypass
Let's take a close look at the createUser()
function
The trim()
function removes any white-spaces in the beginning or end of the string.
Next, the mysqli_real_escape_string()
function, allows only 64 characters and if it is more than the limit, it takes only the first 64 characters, cutting off the remaining characters. Also it escapes /removes the following characters: NUL (ASCII 0), \n, \r, , ', ",
and Control-Z
To leverage the above mentioned vulnerability, we have to create another user with the name natas28
, but the validUser()
function checks whether the username already exists.
So, we have to generate a payload that,
Bypasses the
validUser()
function.Bypass the
trim()
function fromcreateUser()
function.Bypass the
mysqli_real_escape_string()
function from createUser() function.
and should result with the username natas28
.
Bypassing validUser()
Function
validUser()
FunctionWe can generate a username by appending a space or special character, which is not recognized by the validUser()
function.
Bypassing trim()
Function
trim()
FunctionSince the trim()
function removes leading and trailing white spaces, we can append another charcter/string at the end to the previously generated payload, so that the spaces aren't removed.
Bypassing mysqli_real_escape_string()
Function
mysqli_real_escape_string()
FunctionCreate a username that exceeds 64 characters or includes characters that are normally escaped, potentially bypassing the limitations imposed by mysqli_real_escape_string()
.
In this case, we can replace the white-spaces with null character [ ASCII 0 ] in url encoded format %00
Final Payload
Combine the above mentioned strategies to create a payload that includes all necessary elements for bypassing both validUser()
and trim()
functions, and potentially exploiting the limitations of mysqli_real_escape_string()
.
The following python script generates such a payload.
Getting the Password
I captured the login request with burpsuite and replaced the username value with the payload that we generated and the password as test
, which worked successfully.
Now to get the credential, login with the username natas28
and the password that we gave, test
, to get the password for the next level.
Last updated