Authentication is the process of verifying the identity of a user or client. There are three mechanisms:

  • Something you know (Knowledge factors): A password or the answer to a security question.
  • Something you have (Possession factors): A physical object such as a mobile phone or a security token.
  • Something you are or do (Inherence factors): Biometric data, behavioral patterns, etc.

Authentication vs authorization

Authentication verifies that a user is who they claim to be. Authorization verifies whether a user can perform an action.

How authentication vulnerabilities arise

Authentication vulnerabilities often arise in two ways:

  • They are weak and do not offer protection against brute-force attacks.
  • Logic flaws or poor implementation allow authentication mechanisms to be bypassed.

Password-based login

In a password-based login process, users have an account with a username and a secret password.

In this case, knowing the password is sufficient proof of the user’s identity. This means that security is compromised if an attacker manages to obtain or guess the credentials.

Brute-force attacks

An attacker uses a trial-and-error system to guess a user’s credentials. These attacks are usually automated using wordlists, making a large number of attempts at high speed.

These attacks can be refined using basic logic or public information.

Note

To automate brute-force attacks, use tools such as Hydra or Medusa. You can also use a script like the following:

Usernames

Usernames are easy to guess if they follow a pattern such as firstname.lastname@company.com or admin, administrator for administrator users.

During the audit, check whether the website publicly discloses possible usernames or email addresses.

Enumeration

Username enumeration is based on observing changes in the website to identify whether a user exists, either on login or registration pages.

When performing a brute-force attack, pay attention to:

  • Status codes
  • Error messages
  • Response times

Passwords

These are harder to crack because many websites force users to create high-entropy passwords that in theory are more difficult to crack by brute force.

However, many users tend to choose a password they can remember and then try to force it to comply with the password policy, for example Mypassword1! or Myp4$$w0rd.

Flawed brute-force protection

Brute-force protection focuses on making the process harder to automate and slowing down the rate at which the attacker can log in. There are two common approaches:

  • Locking the account that is being targeted.
  • Blocking the IP of the user attempting to log in.

The attempt counter may reset when the user logs in successfully. Therefore, an attacker would only need to log in to their own account after a number of attempts to avoid the restriction.

In this case, it is enough to include your credentials at various points throughout the wordlist.

Account locking

This restriction can be bypassed by creating a list of known usernames and a short list of passwords (if the lockout triggers after 3 failures, choose 3 passwords). This way, an attack can be performed against all accounts without triggering the lockout.

User rate limiting

In this case, making too many failed requests blocks the IP, and it can only be unblocked by:

  • A period of time
  • An administrator.
  • A CAPTCHA.

User rate limiting is usually preferred to prevent username enumeration and denial-of-service attacks.

Sometimes this restriction can be bypassed if it is possible to guess several passwords in a single request.

HTTP basic authentication

Although it is quite old, its simplicity means HTTP basic authentication is sometimes used.

It consists of building an authentication token from the login by concatenating the username and password and encoding it in Base64. That token is sent in subsequent requests in the Authorization header.

Authorization: base64(username:password)

This way, credentials can be captured through a man-in-the-middle attack, unless the website implements HSTS.

In addition, HTTP basic authentication implementations do not use protection against brute-force attacks.

It is normally vulnerable to session-related vulnerabilities, especially CSRF.

Multifactor authentication

Two-factor authentication (2FA), based on something the user knows and something they have, is increasingly common. It generally requires a password and a temporary verification code from a physical device.

Verification codes are usually read by the user from a physical device. High-security websites use dedicated devices for verification that generate the code directly, which is much safer than sending it to the device.

Bypassing multifactor authentication

Sometimes the user is first asked to enter the password and then a verification code, but the user is already logged in before entering the code. In this case, check whether restricted pages are accessible after the first step.

Another case is when the website does not verify that the same user is performing the second verification step.

For example:

A user tries to access their account by:

POST /login-steps/first HTTP/1.1
Host: vulnerable-website.com
 
username=carlos&password=qwerty

They are then assigned a cookie related to their account before moving on to the second step:

HTTP/1.1 200 OK
Set-Cookie: account=carlos
 
GET /login-steps/second HTTP/1.1
Cookie: account=carlos

When submitting the verification code, the website uses that cookie to determine the account that is being accessed.

POST /login-steps/second HTTP/1.1
Host: vulnerable-website.com
Cookie: account=carlos
...
verification-code=123456

In this case, the attacker could log in with their own credentials but change the cookie when submitting the verification code.

POST /login-steps/second HTTP/1.1
Host: vulnerable-website.com
Cookie: account=victim-user
...
verification-code=123456

This is especially dangerous because if the attacker manages to brute-force the code, they could access any account knowing only the username.

Note

Keep in mind that you also need to generate a verification code for the other user.

Keeping users logged in

Many websites implement a system to stay logged in after closing the browser session.

This feature is usually implemented by generating a token that is stored in a persistent cookie. The problem arises when this token is generated insecurely in such a way that the attacker can guess it based on their own token.

When the attacker cannot create an account, this vulnerability can also be exploited through techniques such as XSS, making it possible to steal another user’s cookie.

Note

If the website uses an open-source framework, the details of how the cookie is constructed may be publicly documented.

Password reset

If a user forgets their password, the website has to resort to alternative authentication methods, which makes this feature quite dangerous and it must be implemented securely.

Sending passwords by email

A site that manages passwords securely will never be able to send the current password to a user. Instead, some sites generate a new password and send it by email.

In this case, security depends on the password expiring within a short period of time. Otherwise, it is vulnerable to man-in-the-middle attacks.

URL-based reset

Insecure parameters

A more robust method is to send the user to a unique URL that redirects them to a password reset page.

The least secure implementations of this method use a parameter in the URL to identify the user who is resetting the password.

http://vulnerable-website.com/reset-password?user=victim-user

In this case, the attacker can modify the parameter to reference any username and reset their password.

Insecure token validation

A better implementation consists of generating a token that is hard to guess, and creating the URL from it. This URL should not provide any hint about which user is resetting the password.

http://vulnerable-website.com/reset-password?token=a0ba0d1cb3b63d13822572fcff1a241895d893f659164d4cc550b421ebdd48a8

This token should expire after a short period of time and be deleted immediately after the password is reset.

However, some websites do not validate the token when submitting the reset form. In this case, an attacker could simply access the form from their own account, remove the token, or change the username if it is sent in the request, and use that page to reset any user’s password.

Insecure email generation

If the reset URL is generated dynamically, it may be vulnerable to password reset poisoning.

Example: Imagine the request:

POST /forgot-password HTTP/1.1
Host: example.com
 
username=victim

The email is generated using the Host, X-Forwarded-Host, etc. headers from the previous request.

The user receives:

https://example.com/reset-password?token=XYZ

But if an attacker manipulates the header used to create the password reset URL so that it points to a domain controlled by the attacker, and the victim clicks the URL, the attacker would be able to steal the token and change their password.

POST /forgot-password HTTP/1.1
Host: attacker.com
 
username=victim

This way, the URL could end up being:

https://attacker.com/reset-password?token=XYZ

Password change

These pages are fundamentally based on the same process of verifying that usernames and passwords match as a normal login page. Therefore, these pages may be vulnerable to the same techniques.

The password change feature can be especially dangerous if the server uses the username provided in the request to determine which account to modify.

For example:

username=carlos&current-password=123456&new-password=123&confirm-password=123

If the server trusts username, two vulnerabilities can appear:

  • Username enumeration: an attacker can try different usernames and observe the server’s responses to find out which ones exist.
  • Password brute force: you can try different current passwords for a specific user and observe when the server indicates that the password is correct.

Interesting labs