DVWA 通关指南:XSS(DOM)

XSS(DOM)

"Cross-Site Scripting (XSS)" attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application using input from a user in the output, without validating or encoding it.
跨站点脚本(XSS)攻击是一种注入攻击,恶意脚本会被注入到可信的网站中。当攻击者使用 web 应用程序将恶意代码(通常以浏览器端脚本的形式)发送给其他最终用户时,就会发生 XSS 攻击。允许这些攻击成功的漏洞很多,并且在 web 应用程序的任何地方都有可能发生,这些漏洞会在使用用户的输入,没有对其进行验证或编码。
An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted, and will execute the JavaScript. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by your browser and used with that site. These scripts can even rewrite the content of the HTML page.
攻击者可以使用 XSS 向不知情的用户发送恶意脚本,用户的浏览器并不知道脚本不应该被信任,并将执行 JavaScript。因为它认为脚本来自可信来源,所以恶意脚本可以访问浏览器并作用于该站点的任何 cookie、会话令牌或其他敏感信息,甚至可以重写 HTML 页面的内容。
DOM Based XSS is a special case of reflected where the JavaScript is hidden in the URL and pulled out by JavaScript in the page while it is rendering rather than being embedded in the page when it is served. This can make it stealthier than other attacks and WAFs or other protections which are reading the page body do not see any malicious content.
基于 DOM 的 XSS 是一种特殊的反射型 XSS,通过将 JavaScript 隐藏在 URL 中。基于 DOM 的 XSS 将在页面呈现时被 JavaScript 拉出,而不是在服务时嵌入到页面中。这会使它比其他攻击更隐蔽,WAF 或其他保护读取页面正文时看不到任何恶意内容。
Run your own JavaScript in another user's browser, use this to steal the cookie of a logged in user.
在另一个用户的浏览器中运行你自己的 JavaScript,用它窃取登录用户的 cookie。

Low Level

Low level will not check the requested input, before including it to be used in the output text.
在将请求的输入包含在输出文本中之前,Low level 将不检查请求的输入。

源码审计

源码如下,服务器没有任何防御措施。

<?php

# No protections, anything goes

?> 

接下来我们看一下前端的代码,该页面是个下拉页面,用于选择默认语言。F12 打开,点一点 HTML 标签看到如下 JS 代码。document 表示的是一个文档对象,Location 对象包含有关当前 URL 的信息,href 属性是一个可读可写的字符串,可设置或返回当前显示的文档的完整 URL。也就是说 “document.location.href” 的写法得到页面的 URL,而 indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置,这里用来判断 “default=” 是否在 URL 中。substring(start,stop) 方法用于提取字符串中两个指定下标之间的字符,然后存到 lang 变量中,decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。document.write 是 JavaScript 中对 document.open 所开启的文档流操作的 API 方法,它能够直接在文档流中写入字符串。

if (document.location.href.indexOf("default=") >= 0) {
    var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8);
    document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
    document.write("<option value='' disabled='disabled'>----</option>");
}

document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");

选择下拉列表内容,选择的值会赋给 default 并添加到 url 的末尾,再将其传给 option 标签的 value 结点。也就是说我们可以注入一些 JS 代码进去,然后这部分会被包含到 lang 变量中,最终回显到页面上。

攻击方式

HTML DOM 有个 alert() 方法,用于显示带有一条指定消息和一个 OK 按钮的警告框。document.cookie 里面可以读到 cookie 信息,我们可以把 cookie 放在一个 alert() 生成的警告框中,回显时就会得到我们想要的信息了。注入的payload 如下所示:

<script>alert(document.cookie)</script>


注入 payload 之后,前端的代码中会加入下面这个结点。

Medium Level

The developer has tried to add a simple pattern matching to remove any references to "<script" to disable any JavaScript. Find a way to run JavaScript without using the script tags.
开发人员尝试添加一个简单的模式匹配删除对 “<script” 的任何引用,以此禁用任何 JavaScript,攻击者需要找到一种不使用脚本标记运行 JavaScript 的方法。

源码审计

前端代码不变,后端代码如下所示。array_key_exists() 函数检查某个数组中是否存在指定的键名,如果键名存在返回 true,键名不存在则返回 false。stripos(string,find,start) 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写),header() 函数向客户端发送原始的 HTTP 报头。也就是说现在服务器通过一个模式匹配,过滤了 “script” 标签,我们就不能直接注入 JS 代码了。

<?php

// Is there any input?
if (array_key_exists("default", $_GET) && !is_null ($_GET[ 'default'])){
    $default = $_GET['default'];
    
    # Do not allow script tags
    if (stripos ($default, "<script") !== false){
        header ("location: ?default=English");
        exit;
    }
}

?> 

攻击方式

这种防御形同虚设,因为我们可以直接注入标签将 cookie 显示出来。HTML 的 < img > 标签定义 HTML 页面中的图像,该标签支持 onerror 事件,在装载文档或图像的过程中如果发生了错误就会触发。使用这些内容构造出 payload 如下,因为我们没有图片可供载入,因此会出错从而触发 onerror 事件输出 cookie。

English</option></select><img src = 1 onerror = alert(document.cookie)>

注入 payload 之后,前端的代码中会加入下面这个结点。

High Level

The developer is now white listing only the allowed languages, you must find a way to run your code without it going to the server.
开发人员现在设置了白名单,只允许传递语言单词作为参数.你必须找到一种方法来运行你的代码,不要让它传到服务器上。

源码审计

前端代码不变,后端代码如下所示。服务器设置了白名单,default 参数只接受 French,English,German 以及 Spanish 这几个单词。

<?php

// Is there any input?
if (array_key_exists("default", $_GET) && !is_null ($_GET['default'])){

    # White list the allowable languages
    switch ($_GET['default']){
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");
            exit;
    }
}

?> 

攻击方式

可以在注入的 payload 中加入注释符 “#”,注释后边的内容不会发送到服务端,但是会被前端代码所执行。

English #<script>alert(document.cookie)</script>

Impossible Level

The contents taken from the URL are encoded by default by most browsers which prevents any injected JavaScript from being executed.
大多数情况下浏览器都会对 URL 中的内容进行编码,这会阻止任何注入的 JavaScript 被执行。

<?php

# Don't need to do anything, protction handled on the client side

?>

服务器不需要多做什么,在客户端会对 URL 进行编码。

if (document.location.href.indexOf("default=") >= 0) {
    var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8);
    document.write("<option value='" + lang + "'>" + (lang) + "</option>");
    document.write("<option value='' disabled='disabled'>----</option>");
}

document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");

总结与防御

DOM 型 XSS 是特殊的反射性 XSS,是基于 DOM 文档对象模型的漏洞。DOM (Document Object Model) 译为文档对象模型,是 HTML 和 XML 文档的编程接口,可以使程序和脚本能动态访问和更新文档的内容、结构和样式。HTML 标签作为结点构成了 DOM 节点树,树中的节点都可以通过 JavaScript 进行访问。

当网页被浏览器请求是,浏览器会为页面创建一个顶级的 Document object 文档对象,然后生成各个子文档的对象,每个页面都会对应一个文档对象,每个文档对象都包含属性、方法和事件。Document object 文档对象可以通过 JavaScript 脚本进行编辑,客户端可以通过 DOM 修改页面的内容,从而获取 DOM 中的数据在本地执行。由于这个漏洞存在于前端,因此 DOM 型 XSS 漏洞不需要和服务器交互。
XSS 的攻击方式为攻击者请求一个带有 payload 的 URL,服务器的响应不会以任何形式包含攻击者的脚本。当时当用户的浏览器处理这个响应时,DOM 对象就会处理 XSS 代码。XSS 漏洞的修复方式有以下 2 种:

  1. 过滤输入的字符,例如 “ ' ”,“ " ”,“<”,“>” 等非法字符;
  2. 对输出到页面的数据进行编码

参考资料

dvwa-XSS(DOM)超详细
DVWA系列(三)DOM型XSS
HTML DOM 教程
HTML < img > 标签

posted @ 2020-09-20 11:33  乌漆WhiteMoon  阅读(2609)  评论(0编辑  收藏  举报