[网络安全]DVWA之XSS(Stored)攻击姿势及解题详析合集
- XSS(Stored)-low level
- 源代码
- 姿势
- 基于Message板块
- 基于Name板块
- XSS(Stored)-medium level
- 源代码
- 姿势
- 双写绕过
- 大小写绕过
- Xss标签绕过
- XSS(Stored)-high level
- 源代码
- 姿势:Xss标签绕过
- XSS(Stored)-Impossible level
- 源代码
- 代码审计
- 总结
免责声明:本文仅分享XSS攻击相关知识,不承担任何法律责任。
DVWA请读者自行安装,本文不再赘述。
XSS(Stored)-low level
源代码
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$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)) ? "" : ""));
// 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)) ? "" : ""));
// 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();
}
?>
trim()
函数移除字符串两侧的空格,以确保数据在插入到数据库时没有多余的空白字符。
使用 stripslashes()
函数去除反斜杠,同时使用 mysqli_real_escape_string()
函数转义特殊字符。
使用 mysqli_real_escape_string()
函数将特殊字符转义为它们的 Unicode 编码,以确保它们不会被视为 SQL 语句的一部分。
从源代码来看,它没有明确的防御 XSS 攻击的措施。
姿势
基于Message板块
Payload:<script>alert("qiu")</script>
基于Name板块
Name只允许输入八个字符
,而XSS语句是比八个字符长
的。
绕开长度限制:
\color{#00FF00}{绕开长度限制:}
绕开长度限制: 将页面Name元素
的maxlength改为100
Payload:<script>alert("qiu")</script>
XSS(Stored)-medium level
源代码
<?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 = 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();
}
?>
对留言内容 $message 进行了三种过滤:
- 使用
strip_tags() 函数移除所有 HTML 和 PHP 标签
- 使用 addslashes() 函数将字符串中的特殊字符转义(例如单引号、双引号和反斜杠)
- 使用 htmlspecialchars() 函数将
message
中特殊字符(例如< > ' " &
)转换为相应的 HTML 实体,以防止 XSS 攻击。
对姓名 $name 进行了两种过滤:
- 使用 str_replace() 函数将字符串中的
<script>
替换为空字符串 - 使用 mysqli_real_escape_string() 函数转义字符串中的特殊字符(例如单引号和双引号)以防止 SQL 注入攻击。
姿势
双写绕过
以message为注入点,Payload:<scrip<script>t>alert(1)</scr<script>ipt>
无回显,原因:htmlspecialchars() 函数将message
中的特殊字符(例如 < > ' " &
)转换为相应的 HTML 实体
以Name为注入点:
大小写绕过
由于str_replace() 函数对大小写敏感,可通过大小写绕过限制。
以Name为注入点,Payload:<Script>alert(1)</sCript>
Xss标签绕过
由于针对Name
的str_replace() 函数只对<script>
起过滤作用,因此可使用不同的Xss标签进行绕过。
以Name为注入点,Payload:<img src=1 onerror=alert(1)>
XSS(Stored)-high level
源代码
<?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();
}
?>
对留言内容 $message 进行了三种过滤:
- 使用
strip_tags() 函数
移除所有 HTML 和 PHP 标签 - 使用
addslashes() 函数
将字符串中的特殊字符转义(例如单引号、双引号和反斜杠) - 使用
htmlspecialchars() 函数
将特殊字符如 < > ' " &
转换为相应的 HTML 实体,以防止 XSS 攻击
对姓名 $name 进行了两种过滤:
- 使用 preg_replace() 函数将字符串中的
<script>
替换为空字符串 - 使用
mysqli_real_escape_string()
函数转义字符串中的特殊字符(例如单引号和双引号)以防止 SQL 注入攻击。
姿势:Xss标签绕过
切换 X S S 标签 \color{#FF00FF}{切换XSS标签} 切换XSS标签
- 以Name为注入点,Payload:
<img src=1 onerror=alert(1)>
- 以Name为注入点,Payload:
<audio src=1 onerror=alert(1)>
XSS(Stored)-Impossible level
源代码
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$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)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$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 );
// Update database
$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();
?>
代码审计
if( isset( $_POST[ 'btnSign' ] ) ) {
该行通过 isset()
函数判断 PHP 脚本是否是由提交按钮 btnSign
触发的。如果是,则执行后续代码。
接着,代码调用了 checkToken()
函数,用于验证 Anti-CSRF token 是否匹配:
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
这个函数需要三个参数:用户提交的 CSRF token、服务器存储的 CSRF token 和当前页面的 URL。函数会检查两个 token 是否相同,以及请求是否来自于正确的来源,从而避免跨站点攻击。
接下来的代码获取了用户输入的姓名和留言信息:
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
trim()
函数移除字符串两侧的空格。这样可以确保数据在插入到数据库时没有多余的空白字符。
然后,使用 stripslashes()
函数去除反斜杠,同时使用 mysqli_real_escape_string()
函数转义特殊字符:
$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)) ? "" : ""));
$message = htmlspecialchars( $message );
$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 );
mysqli_real_escape_string()
将特殊字符转义为 Unicode 编码。
最后,使用 htmlspecialchars()
函数对用户输入的数据进行 HTML 编码,以防止 XSS 攻击。该函数将 HTML 特殊字符转义为实体,从而避免恶意代码在浏览器中执行。
接下来的代码,使用 PDO 对用户数据进行插入:
$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();
$db
是一个预先创建的 PDO 数据库连接。这个代码段使用了 PDO 的预准备语句(prepared statement)功能,这是一种避免 SQL 注入攻击的最佳方法之一。使用 bindParam()
函数将实际插入的值与数据库字段绑定起来,确保即使用户输入包含非法字符也不会对 SQL 查询产生影响。
最后,调用 generateSessionToken()
函数来生成 Anti-CSRF token:
generateSessionToken();
这个函数采用某些规则生成随机的 session_token,并将其存储在 PHP 会话中。
总结
以上为[网络安全]DVWA之XSS(Reflected)攻击姿势及解题详析合集,读者可躬身实践。
[网络安全]DVWA之XSS合集:
[网络安全]DVWA之XSS(DOM)攻击姿势及解题详析合集
[网络安全]DVWA之XSS(Reflected)攻击姿势及解题详析合集
我是秋说,我们下次见。