Blasting under DVWA (high difficulty)

Category: Tag:

1. Submit login request and capture package

2. Send to the Intruder module for processing

3. Fill in the attack payload and perform a blasting attack

The blasting failed, the status code is all 302, and the length is the same, indicating that the previous simple thinking can no longer solve the problem. If you look carefully, you can find that there is one more field, user_token.

The user_token has two main functions: ①: Prevent repeated submission of the form ②: Used for authentication, the user_token in each request is different and will change. The reason for the forced explanation is that there is a restriction of uesr_token, so every time you blast it, it is more than just enumerating the user name and password. Once your identity is not verified, even if you give you the correct password, the login will fail.

4. Return to the Intruder module and select a new attack mode

The attack mode is changed to pitchfork, and the value of user_token is tagged with $

5. Payload1 and payload2 can remain unchanged, just change the mode of payload3 to “Recursive grep”

6. In Options, find Grep-Extract and add user_token

Also remember the value of this user_token: 90c9a29a5f9d6e449e902914acae3ab9

7. Go back to payloads and add the initial value to payload3

8. Start blasting, find a special length, get the user name and password, and then manually log in to verify

9. Summary
The previous low and medium difficulty are relatively easy, but the high difficulty will not work. The specific reason depends on the source code.

<?php

if( isset( $_GET[ ‘Login’ ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ ‘user_token’ ], $_SESSION[ ‘session_token’ ], ‘index.php’ );

// Sanitise username input
$user = $_GET[ ‘username’ ];
$user = stripslashes( $user );
$user = ((isset($GLOBALS[“___mysqli_ston”]) && is_object($GLOBALS[“___mysqli_ston”])) ? mysqli_real_escape_string($GLOBALS[“___mysqli_ston”],  $user ) : ((trigger_error(“[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.”, E_USER_ERROR)) ? “” : “”));

// Sanitise password input
$pass = $_GET[ ‘password’ ];
$pass = stripslashes( $pass );
$pass = ((isset($GLOBALS[“___mysqli_ston”]) && is_object($GLOBALS[“___mysqli_ston”])) ? mysqli_real_escape_string($GLOBALS[“___mysqli_ston”],  $pass ) : ((trigger_error(“[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.”, E_USER_ERROR)) ? “” : “”));
$pass = md5( $pass );

// Check database
$query  = “SELECT * FROM `users` WHERE user = ‘$user’ AND password = ‘$pass’;”;
$result = mysqli_query($GLOBALS[“___mysqli_ston”],  $query ) or die( ‘<pre>’ . ((is_object($GLOBALS[“___mysqli_ston”])) ? mysqli_error($GLOBALS[“___mysqli_ston”]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . ‘</pre>’ );

if( $result && mysqli_num_rows( $result ) == 1 ) {
// Get users details
$row    = mysqli_fetch_assoc( $result );
$avatar = $row[“avatar”];

// Login successful
echo “<p>Welcome to the password protected area {$user}</p>”;
echo “<img src=\”{$avatar}\” />”;
}
else {
// Login failed
sleep( rand( 0, 3 ) );
echo “<pre><br />Username and/or password incorrect.</pre>”;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS[“___mysqli_ston”]))) ? false : $___mysqli_res);
}
// Generate Anti-CSRF token
generateSessionToken();
?>

 

The high-level code uses Anti-CSRF token to defend against CSRF attacks, and uses the stripslashes function and mysqli_real_esacpe_string to defend against SQL injection and XSS attacks.

Due to the use of Anti-CSRF token, the login page returned by the server will contain a random value of user_token each time, and the user must submit the user_token each time they log in. After the server receives the request, it will check the token first. Even if the username and password are correct, the login will fail.

Finally, let’s take a look at the source code of the impossible level

<?php
if( isset( $_POST[ ‘Login’ ] ) && isset ($_POST[‘username’]) && isset ($_POST[‘password’]) ) {
// Check Anti-CSRF token   checkToken( $_REQUEST[ ‘user_token’ ], $_SESSION[ ‘session_token’ ], ‘index.php’ );
// Sanitise username input
$user = $_POST[ ‘username’ ];
$user = stripslashes( $user );
$user = ((isset($GLOBALS[“___mysqli_ston”]) && is_object($GLOBALS[“___mysqli_ston”])) ? mysqli_real_escape_string($GLOBALS[“___mysqli_ston”],  $user ) : ((trigger_error(“[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.”, E_USER_ERROR)) ? “” : “”));
// Sanitise password input
$pass = $_POST[ ‘password’ ];
$pass = stripslashes( $pass );
$pass = ((isset($GLOBALS[“___mysqli_ston”]) && is_object($GLOBALS[“___mysqli_ston”])) ? mysqli_real_escape_string($GLOBALS[“___mysqli_ston”],  $pass ) : ((trigger_error(“[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.”, E_USER_ERROR)) ? “” : “”));
$pass = md5( $pass );
// Default values
$total_failed_login = 3;
$lockout_time       = 15;
$account_locked     = false;
// Check the database (Check user information)
$data = $db->prepare( ‘SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;’ );
$data->bindParam( ‘:user’, $user, PDO::PARAM_STR );
$data->execute();
$row = $data->fetch();
// 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 />”;
}
}
// Check the database (if username matches the password)
$data = $db->prepare( ‘SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;’ );
$data->bindParam( ‘:user’, $user, PDO::PARAM_STR);
$data->bindParam( ‘:password’, $pass, PDO::PARAM_STR );
$data->execute();
$row = $data->fetch();
// If its a valid login…
if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {
// Get users details
$avatar       = $row[ ‘avatar’ ];
$failed_login = $row[ ‘failed_login’ ];
$last_login   = $row[ ‘last_login’ ];
// Login successful
echo “<p>Welcome to the password protected area <em>{$user}</em></p>”;
echo “<img src=\”{$avatar}\” />”;
// Had the account been locked out since last login?
if( $failed_login >= $total_failed_login ) {
echo “<p><em>Warning</em>: Someone might of been brute forcing your account.</p>”;
echo “<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>”;
}
// Reset bad login count
$data = $db->prepare( ‘UPDATE users SET failed_login = “0” WHERE user = (:user) LIMIT 1;’ );
$data->bindParam( ‘:user’, $user, PDO::PARAM_STR );
$data->execute();
} else {
// Login failed
sleep( rand( 2, 4 ) );
// Give the user some feedback
echo “<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>”;
// Update bad login count
$data = $db->prepare( ‘UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;’ );
$data->bindParam( ‘:user’, $user, PDO::PARAM_STR );
$data->execute();
}
// Set the last login time
$data = $db->prepare( ‘UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;’ );
$data->bindParam( ‘:user’, $user, PDO::PARAM_STR );
$data->execute();
}
// Generate Anti-CSRF token
generateSessionToken();
?>

In summary, the safer the code, the more complex it is, and the more functions it calls, haha!

The impossible level limits the number of user logins on the basis of high. When the user fails to log in 3 times, the account will be locked for 15 seconds. At the same time, a more secure PDO (PHP Data Object) mechanism is used to prevent SQL injection. That’s why it’s safer. The reason I didn’t try to blast the impossible level is that I knew it would be no use, and I won’t waste time.

 

Reviews

There are no reviews yet.

Be the first to review “Blasting under DVWA (high difficulty)”

Your email address will not be published. Required fields are marked *