[Network Security] DVWA's CSRF attack posture and problem-solving detailed analysis collection
CSRF
CSRF (Cross-Site Request Forgery, cross-site request forgery) is a common web application security vulnerability, which takes advantage of the user's identity in an authenticated website and deceives the user to initiate an unexpected request.The attacker will construct a malicious webpage, so that when the user visits the webpage in the browser, a request that is not authorized by the user is automatically sent to the target website.
The principle of CSRF attack is to use the web application's trust in user requests, the attacker constructs a malicious request and induces the user to trigger it, so as to achieve the purpose of the attack.
Common CSRF attacks include modifying user passwords, sending emails, and transferring funds.
Low level
source code
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
code audit
$_GET['Change']
Existence is first checked to see if there is a password change request.- The code gets the new password entered and the confirmation password.
- Determine whether the new password and the confirmation password match.
- If it matches, the new password is processed:
mysqli_real_escape_string
Function used to database escape new passwords to prevent SQL injection attacks.md5
The function is used to encrypt the new password with MD5 hash.
- A statement to update a user's password in the database is constructed, and the update operation is performed.
- Provide corresponding feedback information to the user according to the operation result.
dvwaCurrentUser
Additionally, a function called in the code returns the username of the current user.
posture
Enter 1 respectively, and the echo is as follows:
Discovery parameters are submitted in GET mode
So the parameter can be modified as password_new=2&password_conf=2
Open the link again:
It can be seen from the page echo that if the password is changed successfully,
it means that CSRF has been successfully implemented.
Medium level
source code
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Checks to see where the request came from
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
}
else {
// Didn't come from a trusted source
echo "<pre>That request didn't look correct.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
code audit
- First, the code checks to see if a GET parameter named is set
Change
to see if there is a password change request. - The code uses
stripos()
a function to check that the origin of the request is on the same server to ensure that the request is from a trusted source. - If the source of the request is legitimate, get the input of the new password and confirm the password.
- Check that the new and confirmed passwords match.
- If the passwords match, the new password is processed:
- First, use
mysqli_real_escape_string()
a function to database-escape the new password to prevent SQL injection attacks. - Then, use
md5()
the function to MD5 hash the new password. Note that MD5 is no longer considered a secure hashing algorithm.
- First, use
- Construct the SQL statement to update the user's password in the database, and execute the update operation.
- Provide corresponding feedback information to the user according to the operation result.
dvwaCurrentUser()
Additionally, a function called in the code returns the username of the current user.
posture
Different from the Low level, this statement is added to the source code of the Medium level
stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ])
即判断 HTTP_REFERER中是否包含SERVER_NAME,即检查请求来源是否在同一服务器上。
HTTP_REFERER is the Referer parameter value, that is, the source address
SERVER_NAME is the host parameter and the host ip name
Idea: dvwa的www目录下
Write an html file that contains a CSRF link, capture the packet so that the request packet includes the file
So write an html file and name it host address.html
The content is:
<img src=“http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=2&password_conf=2&Change=Change#” border=“0” style=“display:none;”/>
The host address can be entered cmd
in ipconfig
to get
Modify parameters after packet capture:
After sending the package, you can see from the echo on the right that the password has been changed successfully.
High level
source code
<?php
$change = false;
$request_type = "html";
$return_message = "Request Failed";
if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {
$data = json_decode(file_get_contents('php://input'), true);
$request_type = "json";
if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&
array_key_exists("password_new", $data) &&
array_key_exists("password_conf", $data) &&
array_key_exists("Change", $data)) {
$token = $_SERVER['HTTP_USER_TOKEN'];
$pass_new = $data["password_new"];
$pass_conf = $data["password_conf"];
$change = true;
}
} else {
if (array_key_exists("user_token", $_REQUEST) &&
array_key_exists("password_new", $_REQUEST) &&
array_key_exists("password_conf", $_REQUEST) &&
array_key_exists("Change", $_REQUEST)) {
$token = $_REQUEST["user_token"];
$pass_new = $_REQUEST["password_new"];
$pass_conf = $_REQUEST["password_conf"];
$change = true;
}
}
if ($change) {
// Check Anti-CSRF token
checkToken( $token, $_SESSION[ 'session_token' ], 'index.php' );
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '" . $pass_new . "' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert );
// Feedback for the user
$return_message = "Password Changed.";
}
else {
// Issue with passwords matching
$return_message = "Passwords did not match.";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
if ($request_type == "json") {
generateSessionToken();
header ("Content-Type: application/json");
print json_encode (array("Message" =>$return_message));
exit;
} else {
echo "<pre>" . $return_message . "</pre>";
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
code audit
- First, the code checks that the request is a POST method and has a content type of application/json. If the conditions are met, the request will be parsed into JSON format and the corresponding parameters will be obtained.
- If the JSON request condition is not met, the parameters of the non-JSON request are checked.
- If the conditions for password change are met, do the following:
- Check for Anti-Cross-Site Request Forgery (Anti-CSRF) tokens.
- Check that the new and confirmed passwords match.
- Database escape and MD5 hash encryption of new passwords.
- Construct the SQL statement to update the user's password in the database, and execute the update operation.
- Provide corresponding feedback information to the user according to the operation result.
- Close the database connection.
- Based on the request type, a new Anti-CSRF token is generated and a response is returned.
posture
From the code audit:
The generateSessionToken() function is used to generate a random token and store it in the session (session), ensuring that each user has a unique token.
The checkToken() function is used to verify that the token passed to the server matches the token stored in the session. This function is called before handling password change requests to ensure only legitimate requests are processed.
Through these two steps, the server will first verify the validity of the token, and only after the verification is successful will the user's password change request be processed.
Therefore, you should obtain the user_token returned by the server before initiating the request, and then use the user_token to bypass the verification.
method 1
Install in BurpCSRF Token Tracker
Add the host name, the token name obtained by capturing the packet is the token value
, and then capture the packet again, replay the packet, and modify the password arbitrarily, and the token value in the plug-in will be automatically updated.
method 2
Use DVWA xss(stored)
to realize token pop-up.
Enter 1, 1 in the xss(stored) page and capture the package
Modify the textName parameter to<iframe src="../csrf/" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>
At this time, put the package and close the interception, and the token will pop up on the page:80edcbac43cd9594f29999a0692a608f3
Then grab the package of the CSRF page:
Modify the password and token, and release the package:
The page echo shows that the password has been changed successfully.
Impossible level
source code
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$pass_curr = $_GET[ 'password_current' ];
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Sanitise current password input
$pass_curr = stripslashes( $pass_curr );
$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_curr = md5( $pass_curr );
// Check that the current password is correct
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
$data->execute();
// Do both new passwords match and does the current password match the user?
if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
// It does!
$pass_new = stripslashes( $pass_new );
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update database with new password
$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->execute();
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match or current password incorrect.</pre>";
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
code audit
- First, the code checks
$_GET['Change']
to see if there is a password change request. - Next, the code calls
checkToken
the function to validate the Anti-CSRF token.checkToken
The function will compare the match between the requestuser_token
and the sessionsession_token
to confirm the legitimacy of the request. - The code obtains the current password, new password and confirmation password entered, and performs a series of processing on the current password:
stripslashes
Function to remove backslashes from the current password.mysqli_real_escape_string
The function is used to perform database escape on the current password to prevent SQL injection attacks.md5
The function is used to perform MD5 hash encryption on the current password.
- The code performs a database query to check that the current password entered by the user is correct.
- If the new password and the confirmed password match, and the current password is correct, update the password in the database with the new password.
- Finally, output corresponding feedback information according to the operation result.
Additionally, two additional functions are called in the code:
generateSessionToken
Function to generate and set the Anti-CSRF token to ensure that every time the form is rendered a new token is generated and stored in the session.dvwaCurrentUser
The function returns the username of the current user.
Summarize
The above is[Network Security] DVWA's CSRF attack posture and problem-solving detailed analysis collection, Investigation CSRF
, Burp使用
and PHP代码审计
other relevant knowledge.
I am Qiu said , see you next time.