PortSwigger靶场之 DOM XSS in innerHTML sink using source location.search通关秘籍
一、分析题目
这个靶场的目的是让你利用一个位于博客搜索功能中的 DOM 型 XSS (DOM-based Cross-Site Scripting) 漏洞。
它的工作原理和我们上一偏博客遇到的靶场类似,但关键技术细节有所不同:
漏洞类型: 仍然是 DOM 型 XSS。攻击发生在用户的浏览器中,由客户端的 JavaScript 代码处理不当引起。
数据来源 (Source): 和之前一样,是
location.search
。这意味着不安全的数据来自于 URL 的查询字符串(?
后面的部分),你可以完全控制这部分内容。危险函数 (Sink): 这次不再是
document.write
,而是innerHTML
。innerHTML
是一个 DOM 元素的属性,JavaScript 可以用它来设置或获取某个元素(在这个靶场里是一个<div>
元素)内部的 HTML 内容。当脚本把一个包含 HTML 标签的字符串赋值给
element.innerHTML
时,浏览器会解析这个字符串并据此生成 DOM 节点。漏洞点:如果将未经过滤的用户输入(比如你的搜索词)直接赋值给
innerHTML
,你输入的恶意 HTML(包括脚本)就会被插入到页面中并可能被执行。
总结一下: 这个靶场的场景是,你在搜索框输入内容后,页面上的某段 JavaScript 会获取你输入的词(从 URL 中),然后使用 innerHTML
将类似 “您搜索的结果是:[你的输入]” 这样的内容显示在页面的一个 <div>
区域里,从而造成了 XSS 漏洞。
二、解决方法
你的目标是构造一个 URL,将恶意的 JavaScript 载荷(payload)放在 URL 的查询参数中,当页面加载时,这段载荷被 innerHTML
写入页面并执行 alert()
函数。
<script>// 定义一个函数,名为 doSearchQueryfunction doSearchQuery(query) {// 找到页面上 ID 为 "searchMessage" 的元素// 然后,把这个元素的内部 HTML 内容 (innerHTML) 设置为你传入的 query 值document.getElementById('searchMessage').innerHTML = query;}// 从当前 URL 中获取名为 'search' 的参数值var query = (new URLSearchParams(window.location.search)).get('search');// 如果参数存在if (query) {// 就调用上面的函数,把参数值传进去doSearchQuery(query);}
</script>
这段代码就是漏洞的根源! 它会从 URL 中获取你的输入,然后不经过任何安全处理,直接使用 innerHTML
将其写入到页面中。
整个攻击流程总结
你在浏览器(或通过 Burp Suite)发起了攻击请求,URL 中包含了恶意 payload:
.../?search="><script>alert(1)</script>
。服务器响应,将包含那段有漏洞的 JavaScript 代码的页面返回给浏览器。
浏览器执行 JavaScript:
浏览器运行红框里的脚本。
脚本从 URL 中读取到
search
参数的值,也就是你的恶意 payload"><script>alert(1)</script>
。doSearchQuery
函数被调用,执行innerHTML = '"><script>alert(1)</script>'
。浏览器将你的恶意字符串当作 HTML 解析并插入到页面中,导致
<script>alert(1)</script>
被执行。
攻击成功:页面上弹出一个警告框。
但是关键点在于在这里直接使用 <script>alert(1)</script>
未成功成功。因为出于安全考虑,许多现代浏览器阻止通过 innerHTML
插入的 <script>
标签执行。
因此,我们需要使用其他方式来执行 JavaScript,最常用的方法是利用 HTML 事件处理器。
推荐的攻击载荷 (Payload):
一个非常可靠且经典的 payload 是使用 <img>
标签和它的 onerror
事件:
<img src=x onerror="alert(1)">
这个 Payload 是如何工作的?
<img src=x>
: 浏览器会尝试加载一个来源地址为x
的图片。加载失败: 因为
x
并不是一个有效的图片地址,所以加载必定会失败。触发
onerror
事件: 图片加载失败会触发onerror
事件。执行脚本:
onerror
事件中包含的 JavaScript 代码alert(1)
就会被执行。
三、具体步骤:
找到靶场中用于搜索的 URL 参数即
search
。将上述的 payload 作为
search
参数的值附加到 URL 后面。构造最终的攻击 URL:
https://[靶场地址]/?search=<img src=x onerror="alert(1)">
在浏览器中访问这个 URL。如果页面弹出了警告框,我们成功解决了这个靶场。