Home

Home / Web App Security / PortSwigger

Authentication: Vulnerabilities In Password Based Login; Brute-Force Attacks

· Matthew Crum

For web applications that adopt a password based login process users either register for an account themselves or they are assigned an account by an administrator. This account is associated with a unique username and a secret password that the user enters in a login form to authenticate. In this scenario just the fact that they know the password is taken as proof of the user’s identity. Often times though an attacker is able to either obtain or otherwise guess the login credentials of a user.

For example a brute-force attack is when an attacker uses a system of trial and error in an attempt to guess valid user credentials. These attacks are typically automated using wordlists of usernames and passwords in what is known as dictionary attacks. Automating the process potentially enables an attacker to make a vast number of guesses at a high speed. Attackers can fine-tune brute force attacks to make much more educated guesses considerably increasing the efficiency of the attack.

Usernames are especially easy to guess if they conform to a recognizable pattern, such as an email address. It is very common to see business logins in the format firstname.lastname@companyname.com. Even high privileged accounts are often created using predictable usernames such as admin or administrator. HTTP responses may also disclose email addresses of high privileged users like admins or IT support.

An attacker may be able to observe changes in a the website’s behavior in order to identify whether a given username is valid. Username enumeration typically occurs on the login page, for example error messages indicating entering a valid username but an incorrect password, or on registration forms when you enter a username that is already taken. Attackers can take advantage of any differences in:

Passwords can similarly be brute-forced with varying difficulty based on the strength of the password. Many web applications have some form of password policy that force users to create high entropy passwords that are harder to cracked using brute force alone. Attackers use a basic knowledge of human behavior to exploit vulnerabilities users unwittingly introduce into the system. Users often take a password that they can remember and try to crowbar it into fitting the password policy. For example p@$$w0RD1 instead of password. In cases where regular password changes are required it is common for users to just make minor, predictable changes for example changing password1! to password2!. It is this knowledge of likely credentials and patterns that allow brute force attacks to become much more effective than simply iterating through all possible character combinations.


Labs

Username Enumeration Via Different Responses

lab1

To start this challenge I’m going to capture a login request with an obviously fake username crumbles to see how the application responds.

login

request

The application responds with an Invalid username message.

invalid username

Sending the captured login request to the intruder I can test against the provided list of usernames until the application responds with a different error message. I start off by editing the Payload positions so that there are section sign payload markers around the username since that is what I want to enumerate.

intruder

I also need to go to the Payloads tab and paste the provided username wordlist into the *Payload Settings [Simple list] section.

username payloads

Then I went to the Settings tab and attempted to add the string Invalid password to the Grep – Match section so that any user name that contained that response would be flagged.

grep match

Unfortunately that wasn’t the correct error message to grep for. There was still a slight difference in the response with the valid user name and I was able to easily find it sorting the results by Length.

length

I can see that username aq triggered a different response and the string in the error message was Incorrect password, not exactly what I thought it would be but still different enough to verify that aq is a valid username. Now that I know that I just need to use the Intruder function to enumerate the password.

Back in the Payload positions tab I need to edit the request so that the username is now aq and the section signs indicating the payload position are now around the password.

password position

I will also need to modify the Payload settings [Simple list] and clear the list of usernames so that I can paste in the provided list of passwords.

password payloads

I also removed the Grep – Match settings I set up earlier as I didn’t know what a successful login response would look like. Eventually I get a response for the password yankees that is of a much shorter length than the others and a 302 redirect status code instead of 200 like all of the failed attempts.

yankees

Back in the lab logging in with the credentials aq:yankees solves the challenge and completes the lab.

solved1


Username Enumeration Via Subtly Different Responses

lab2

This time the error message for an invalid log in is Invalid username or password. Since response I’m trying to catch will be a much more subtle difference I will go ahead and start by setting up the Intruder with a captured request, mark the username payload positions, and set the provided wordlist as the payload just as I did in the previous challenge.

login

intruder

usernames payload

Once the attack finished it was pretty hard to notice any significant difference in the responses, they all seemed to have varying response times and lengths with the status code always being 200. Adding the error message “Invalid username or password.” to the Grep-match settings and the sorting the results by that column reveals just one entry didn’t match. A very subtle typo in the error message where it did not contain a period at the end for the user auth.

auth

Now that I know the difference I’m looking for and have the username in hand I can set up the Intruder to enumerate the password parameter for username auth with the provided password list and see which string generates a login.

password position

passwords payload

Interestingly something I didn’t catch at first is that since the error message is always missing the period for user auth my previous string pattern that I grepped for “Invalid username or password.” won’t generate in any of the responses. Luckily the correct password generates a 302 redirect and still stands out.

baseball

Logging in with the credentials auth:baseball completes the challenge for this lab.

solved2


Username Enumeration Via Response Timing

lab3

To start this off I captured a request to login using the provided credentials and sent it to the repeater, noting that the response time was 133 milli seconds.

wiener login

I then tried to login with a username I made up that I know does not exist in the system and the application took slightly longer to respond but it wasn’t significant enough to go off of at 143 mill seconds.

crumbles login

By editing the password for the username I know exists, wiener, I am able to see the more characters I use for an existing users password the longer the application takes to respond.

wiener:peter123456789 216 milli seconds

216 milli sec

wiener:peter12345678900000000000 265 milli seconds

265 milli seconds

I can verify that this delayed response only occurs with a known user by testing the long password with my fake user and noting that the response time is back down to normal.

crumbles:peter12345678900000000000 137 milli seconds

crumbles 137 milli seconds

This means I should now be able to brute force usernames on the system by using the intruder to test against the provided list of usernames and noting which ones have an increased response time with my long password.

However the web application has some protection set up against too many login attempts and then locks you out for 30 minutes after about 7 or 8 attempts.

rate limited

Luckily this challenge has a hint related to this issue.

hint

When a web application relies solely on IP addresses for rate limiting the X-Forwarded-For header can be manipulated to change the perceived IP address that is making the request. By adding this header to the request I can bypass the applications rate limiting.

x-forwarded-for

Eventually my fake IP address will also be blocked by the rate limiter meaning that I need to account for that as well when I set up the payload in the Intruder. Since I will need to use different payloads for multiple defined positions simultaneously I’ll need to set the Attack type to Pitchfork.

pitchfork

I’ll need to set the payload markers around the values of the parameters X-Forwarded-For and username since those are what I will want to modify for each request.

2 positions markers

In the Payloads tab with the Payload set option set to 2, since the username parameter was the second position I added, I paste the provided username list into the Payload settings [Simple List] section. Doing this gives me the payload count, so I will know how many requests I’ll need to edit the X-Forwarded-For parameter as to not get rate limited by the system.

payload set 2

Once I started creating my list for the Payload Set: 1 option it occurred to me that since any value that hasn’t been seen by the system yet will trick the limiter into thinking it is a request from a new IP address I could just use the same list containing the usernames. I did have to go in and paste the list a second time though.

payload set 1

With that all set up I can start the attack.

user user

I can see from the results of the attack that the username with the longest response is user meaning they are likely a user on the system. Now I just need to edit the Intruder options so that username value is set to user and the payload 2 position is marked around the value of the password parameter.

password positions

Then I need to set the *Payload Set: 2, Payload settings [Simple list] up so that it’s enumerating through the provided password list instead of usernames. I can leave Payload Set: 1 alone for now since none of my “fake IP addresses” should be locked out by the rate limiter yet.

password payload 2

Once the attack finishes I can see from the results that the password that prompted the 302 redirect was 000000.

000000

Logging in with the credentials user:000000 completes the challenge for this lab.

solved 3