DVWA靶场通关笔记-DOM型XSS(Impossible级别)
目录
一、DOM型XSS
二、代码分析
1、index.php
2、Impossble.php
三、DOM型XSS安全级别分析
四、Impossble防范分析
1、禁用 URI 解码,依赖默认编码输入
2、无需服务器端额外过滤
3、尝试注入脚本1
4、尝试注入脚本2
本系列为通过《DVWA靶场通关笔记》的DOM 型 XSS关卡(low,medium,high,impossible共4关)渗透集合,通过对相应关卡源码的代码审计找到讲解渗透原理并进行渗透实践。本文为DOM 型 XSS impossible关卡的原理分析部分,讲解相对于low、medium和high级别,为何对其进行渗透测试是Impossible的。
一、DOM型XSS
DOM 型 XSS(Document Object Model Cross-Site Scripting) 是一种特殊的 XSS 攻击,其注入点存在于客户端 JavaScript 代码中,而非服务器端。攻击者通过操控网页的 DOM 环境(如 URL 参数、表单输入等),诱导浏览器执行恶意脚本,无需服务器参与。
<
, >
)二、代码分析
1、index.php
进入DVWA靶场DOM 型 XSS源目录,找到index.php源码。
这段代码是DVWA(Damn Vulnerable Web Application)中DOM型XSS的演示页面,主要功能是:
- 根据用户选择的语言生成一个下拉菜单。
- 当用户提交选择后,URL中会包含default=参数。
- 页面JavaScript会读取URL参数并动态生成选项。
详细注释后的代码如下所示。
<?php// 设置根目录路径define( \'DVWA_WEB_PAGE_TO_ROOT\', \'../../\' );// 引入DVWA页面初始化文件require_once DVWA_WEB_PAGE_TO_ROOT . \'dvwa/includes/dvwaPage.inc.php\';// 启动页面,要求认证和PHPIDS保护dvwaPageStartup( array( \'authenticated\', \'phpids\' ) );// 创建新页面$page = dvwaPageNewGrab();// 设置页面标题$page[ \'title\' ] = \'Vulnerability: DOM Based Cross Site Scripting (XSS)\' . $page[ \'title_separator\' ].$page[ \'title\' ];$page[ \'page_id\' ] = \'xss_d\';$page[ \'help_button\' ] = \'xss_d\';$page[ \'source_button\' ] = \'xss_d\';// 连接数据库dvwaDatabaseConnect();// 根据安全等级选择对应的级别文件$vulnerabilityFile = \'\';switch( $_COOKIE[ \'security\' ] ) { case \'low\': $vulnerabilityFile = \'low.php\'; break; case \'medium\': $vulnerabilityFile = \'medium.php\'; break; case \'high\': $vulnerabilityFile = \'high.php\'; break; default: $vulnerabilityFile = \'impossible.php\'; break;}// crequire_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/xss_d/source/{$vulnerabilityFile}\";// 对于impossible级别,不进行URI解码$decodeURI = \"decodeURI\";if ($vulnerabilityFile == \'impossible.php\') { $decodeURI = \"\";}// 构建页面主体$page[ \'body\' ] = <<<EOF Vulnerability: DOM Based Cross Site Scripting (XSS)
Please choose a language:
// 检查URL中是否包含default参数 if (document.location.href.indexOf(\"default=\") >= 0) { // 提取default参数值 var lang = document.location.href.substring(document.location.href.indexOf(\"default=\")+8); // 动态写入选项 document.write(\"\" + $decodeURI(lang) + \"\"); document.write(\"----\"); }// 写入固定选项 document.write(\"English\"); document.write(\"French\"); document.write(\"Spanish\"); document.write(\"German\"); EOF;// 添加更多信息链接$page[ \'body\' ] .= \" More Information
- \" . dvwaExternalLinkUrlGet( \'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)\' ) . \"
- \" . dvwaExternalLinkUrlGet( \'https://www.owasp.org/index.php/Testing_for_DOM-based_Cross_site_scripting_(OTG-CLIENT-001)\' ) . \"
- \" . dvwaExternalLinkUrlGet( \'https://www.acunetix.com/blog/articles/dom-xss-explained/\' ) . \"
\\n\";// 输出页面dvwaHtmlEcho( $page );?>
2、Impossble.php
进入DVWA靶场源目录,找到Impossible.php源码,打开源码Impossible.php,如下所示。
Impossible的含义是服务器端不需要做任何防御措施,防御的关键在于客户端。我们查看index.php对impossible.php的特别处理,即不对其传入内容进行URI解码,这样注入语句就会失败。
三、DOM型XSS安全级别分析
四个安全级别(Low、Medium、High、Impossible)在 DOM 型 XSS 防护上的区别主要体现在对用户输入的处理方式和防护严格程度上,具体如下表所示。
-
Low 级别
- 无任何防护措施,对用户输入的
default
参数完全信任,直接将其嵌入到页面的 JavaScript 代码中并执行。 - 例如,攻击者可以直接构造包含恶意脚本的 URL,如
/vulnerabilities/xss_d/?default=Englishalert(1)
,脚本会被直接执行。
- 无任何防护措施,对用户输入的
-
Medium 级别
- 尝试通过简单的模式匹配进行防护,会检测
default
参数中是否包含<script
(不区分大小写),如果包含则重定向到?default=English
。 - 攻击者可以不使用
标签,通过其他方式执行脚本,比如利用
img
标签的onerror
事件,如/vulnerabilities/xss_d/?default=English>/option>
。
- 尝试通过简单的模式匹配进行防护,会检测
-
High 级别
- 采用白名单机制,只允许
default
参数的值为French
、English
、German
、Spanish
这几个预设的语言选项,若为其他值则重定向到?default=English
。 - 不过,由于 URL 中
#
后面的片段(fragment)不会发送到服务器,因此攻击者可以将恶意脚本放在#
之后,如/vulnerabilities/xss_d/?default=English#alert(1)
,从而绕过服务器端的白名单检查。
- 采用白名单机制,只允许
-
Impossible 级别
- 防护在客户端进行,浏览器会对从 URL 中获取的内容进行默认编码,使得注入的恶意 JavaScript 无法被执行,从而彻底防止了 DOM 型 XSS 攻击。
四、Impossble防范分析
在 DVWA 的 DOM 型 XSS(Cross Site Scripting)场景中,Impossible
级别的防范方法主要通过客户端编码处理和浏览器默认安全机制实现。Impossible
级别的核心防范思路是利用浏览器对动态插入 DOM 的内容进行默认编码,避免将用户输入直接作为原始 HTML/JavaScript 执行,从而彻底阻断 DOM 型 XSS 攻击的可能性。具体如下所示。
1、禁用 URI 解码,依赖默认编码输入
在impossible.php对应的逻辑中,通过设置$decodeURI = \"\"
,移除了对 URL 中default
参数的decodeURI
解码操作。此时,浏览器会对从 URL 中获取的内容进行默认编码(如将特殊字符转换为 HTML 实体),使得注入的恶意脚本(如标签)无法被解析为可执行代码。
关键代码逻辑(来自xss_d/index.php
):
$decodeURI = \"decodeURI\";if ($vulnerabilityFile == \'impossible.php\') { $decodeURI = \"\"; // 禁用解码,依赖浏览器默认编码}
对应的前端脚本部分:
// 当为impossible级别时,$decodeURI为空,等价于直接输出lang(被浏览器自动编码)document.write(\"\" + $decodeURI(lang) + \"\");
2、无需服务器端额外过滤
服务器端(impossible.php)未添加任何主动过滤逻辑(代码为空),完全依赖客户端浏览器对动态插入的内容进行编码,从根源上阻止恶意脚本的执行。
3、尝试注入脚本1
注入Payload:alert(\'mooyuan\')
http://127.0.0.1/dvwa/vulnerabilities/xss_d/?default=alert(\'mooyuan\')
如下所示注入失败,页面显示为注入语句的URL编码后效果。
4、尝试注入脚本2
注入Payload:
http://127.0.0.1/dvwa/vulnerabilities/xss_d/?default=
如下所示注入失败,页面显示为注入语句的URL编码后效果。