Refer to the post start DVWA with Docker to learn how to start DVWA. I will mostly use Burp Suite to solve the challenges. To configure Burp suite refer to the post configure burp suite for DVWA. Click on the Brute force button on the left menu to access the challenge.
We reach a page allowing us to log in something. We can put a username and password and click on the button login.
If we try the username and password test we get the error message Username and/or password incorrect.
As we can see from the URL, the username and password are passed as GET parameters.
We would like to connect to the application but we do not know what the credentials are. The administrator may have entered some default and predictable username and password. To try these predictable credentials we will use the Burp Intruder.
Please refer to the post setup burp intruder to learn how to configure the attack.
You can use the usernames.txt and passwords_quick.txt lists from IntruderPayloads for your attack.
In the end we can see that the credentials were "admin/password".
There are multiple ways to improve the security in this case. We can :
The medium level is basically identical except that the developer implemented a sleep() function to nag attackers. This is clearly useless as the same method used in the low level will work perfectly.
else {
// Login failed
sleep( 2 );
echo "<pre><br />Username and/or password incorrect.</pre>";
}
This level is a little bit different. When we send a request with the credentials test/test we can see that a new parameter is being sent along the credentials : the user_token.
Here is the form we have on the login page :
<form action="#" method="GET">Username:
<br />
<input type="text" name="username">
<br />
Password:
<br />
<input type="password" AUTOCOMPLETE="off" name="password">
<br />
<br />
<input type="submit" value="Login" name="Login">
<input type='hidden' name='user_token' value='76ec861542aa9bbe797a98e9b7d86300' />
</form>
To be able to brute force the application we must give the proper user_token
in our login request. Here is a login request sent from our browser:
GET /vulnerabilities/brute/?username=test&password=test&Login=Login&user_token=76ec861542aa9bbe797a98e9b7d86300 HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost/vulnerabilities/brute/
DNT: 1
Connection: close
Cookie: PHPSESSID=c8f9p19iv3b8s0cm58d7pm1e25; security=high
Upgrade-Insecure-Requests: 1
To do so with Burp Suite we will have to create a macro.
We go to Project options > Sessions > Macros > Add to record a new macro.
The Burp Macro Recorder window pops up. We select the item where the token is given to us in the response of the GET request, and we click OK.
We continue with the Macro Editor window. We change the description to Fetch token. And we click OK.
We now have a macro that is capable of retrieving the login page. We just have to extract the token from the login page now.
To define the rule that will extract the user token we navigate to Project options > Sessions > Session Handling Rules > Add.
We name our rule "Anti-CSRF token" and click Add under Rule Actions.
We select Run a macro in the drop down menu and then we select the macro Fetch token and click OK.
In the Scope tab we select Intruder : the tool the rule will be applied to.
Now we click the Up button to move the rule up.
We can test the rule with the repeater. If we get an error password incorrect then everything worked properly.
We start the brute force as usual. The vulnerability is the same as before.
In the impossible level, the developper implements a lockout mechanism to slow down attackers.
// Check to see if the user has been locked out.
if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) {
// User locked out. Note, using this method would allow for user enumeration!
//echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>";
// Calculate when the user would be allowed to login again
$last_login = strtotime( $row[ 'last_login' ] );
$timeout = $last_login + ($lockout_time * 60);
$timenow = time();
/*
print "The last login was: " . date ("h:i:s", $last_login) . "<br />";
print "The timenow is: " . date ("h:i:s", $timenow) . "<br />";
print "The timeout is: " . date ("h:i:s", $timeout) . "<br />";
*/
// Check to see if enough time has passed, if it hasn't locked the account
if( $timenow < $timeout ) {
$account_locked = true;
// print "The account is locked<br />";
}
}
Each time a failed attempt is made, the lockout time is increased.