一、靶场描述
这个靶场在搜索查询的跟踪功能中,包含一个基于DOM的跨站脚本(DOM-based XSS)漏洞。
该漏洞的产生是因为网站使用了一个名为 document.write
的 JavaScript 函数,这个函数会把数据直接写入到页面中。而写入的数据来源于 location.search
,也就是网站 URL 中问号 (?
) 之后的部分,这部分内容是你可以完全控制的。
衍生一下,标签<img>是在在网页中插入图片的意思,主要属性包括:
- src:图片的地址,必填,比如:src="example.jpg"
- alt:图片无法显示时的替代文本
- width、height:设置图片大小
<img src="logo.png" alt="网站LOGO" width="100" height="50">
其中:
<img src=xxx οnerrοr=" ">:当src="xxx" 是不存在或无法加载的资源时,浏览器会触发 onerror 事件,可以利用图片加载失败触发 JavaScript 执行
<img src=xxx οnlοad=" ">:当src="xxx" 是有效且能正常加载的资源时,浏览器会触发 onload 事件,可以利用图片加载成功触发 JavaScript 执行
我们访问/resources/images/tracker.gif可以访问
所以本靶场可以利用图片加载成功触发 JavaScript 执行通关,但是主要使用的是下面三、攻击思路,这种也是一种办法。
" onload="alert(1)"
当你的输入被拼接到原始代码中后,最终生成的HTML字符串变成了:
<img src="/resources/images/tracker.gif?searchTerms="" onload="alert(1)">
二、漏洞原理详解
1、基于DOM的跨站脚本 (DOM-based XSS):
这是一种特殊的XSS攻击。与存储型和反射型XSS不同,DOM型XSS的攻击载荷(payload)不一定会发送到服务器。
整个攻击过程发生在用户的浏览器端。具体来说,是页面的客户端JavaScript代码,在处理数据时不够安全,导致了漏洞。
在这个靶场中,流程是这样的:
a. 浏览器加载页面的合法JavaScript代码。
b. 这段代码从URL中读取数据 (通过 location.search)。
c. 代码没有对读取到的数据进行安全处理(过滤或编码),就直接使用 document.write 将其写入到页面的文档对象模型(DOM)中。
d. 如果URL中包含了恶意脚本,这个脚本就会被写入页面并执行。
2、危险函数 (Sink):
document.write
这是一个非常经典的导致DOM-XSS的函数。它会把传入的字符串当作HTML来解析并插入到文档流中。如果字符串里包含 <script>
标签,浏览器就会执行它。
3、数据来源 (Source):
location.search这是指URL中从 ?
开始的所有内容(查询字符串)。例如,在 http://example.com/search?query=apple
这个URL中, location.search
的值就是 ?query=apple
。攻击者可以随意构造这个部分。
4、解决目标
要成功完成这个靶场,你需要构造一个特殊的URL。当这个URL被访问时,它能够触发DOM-XSS漏洞,并成功执行 alert
函数(即在浏览器中弹出一个警告框)。
三、攻击思路:
在输入框随便输入字符串,发现我们的输入被拼接到url,然后函数 document.write() 将从url中获取的search参数写入页面中
这是一段 JavaScript 代码,它的主要功能是跟踪用户在网站上的搜索行为,但它包含一个严重的安全漏洞。
1、代码详解
<script>
// 定义一个名为 trackSearch 的函数,它接收一个参数叫 query
function trackSearch(query) {
// 使用 document.write 向页面写入一段 HTML 代码
document.write(
// 这段 HTML 是一个 <img> 图像标签
// 图像的源(src)指向一个跟踪像素(tracker.gif)
// 关键在于,它把用户输入的搜索词(query)作为参数拼接到了图像的 URL 后面
'<img src="/resources/images/tracker.gif?searchTerms=' + query + '">'
);
}
// 从当前页面的 URL 中获取名为 'search' 的参数值
// 例如,如果 URL 是 https://example.com/?search=1
// 那么 query 变量的值就是 '1'
var query = (new URLSearchParams(window.location.search)).get('search');
// 判断 query 是否存在 (即 URL 中是否有 'search' 参数)
if (query) {
// 如果存在,就调用上面定义的 trackSearch 函数,并将获取到的搜索词传进去
trackSearch(query);
}
</script>
2、功能总结
这段代码的目的是:
从当前页面的 URL 地址栏里,寻找一个名为
search
的参数 (例如:.../?search=关键词
)。如果找到了这个参数,就把它的值(也就是用户搜索的关键词)取出来。
然后,它会动态地在页面上创建一个看不见的图像(一个1x1像素的跟踪GIF)。这个图像的 URL 地址会把用户的搜索关键词作为
searchTerms
参数附加上去。当浏览器尝试加载这个图像时,就会向服务器发送一个请求,服务器通过分析这个请求日志,就能知道用户刚刚搜索了什么关键词,从而实现搜索行为跟踪。
3、严重的安全问题 (DOM-based XSS)
这段代码最关键的问题在于它使用了 document.write()
函数来处理从URL中获取的用户输入,并且没有任何安全过滤。
一个攻击者可以构造一个恶意的 URL,如下所示:
https://[网站地址]/?search="><script>alert('XSS')</script>
当用户访问这个 URL 时,代码的执行流程会变成这样:
query
变量获取到的值是:"><script>alert('XSS')</script>
trackSearch
函数被调用,document.write()
执行的内容就变成了:<img src="/resources/images/tracker.gif?searchTerms=""><script>alert('XSS')</script>">
浏览器在解析这段 HTML 时,会先闭合
<img>
标签,然后遇到<script>
标签,就会立即执行里面的 JavaScript 代码,导致弹出一个警告框。
结论: 这段代码实现了一个简单的搜索跟踪功能,但由于直接将 URL 参数写入页面,导致了严重的基于DOM的跨站脚本(DOM-XSS)漏洞,允许攻击者在网站上执行任意脚本。
你需要将一个恶意的JavaScript载荷(payload)放在URL的查询字符串中。当页面上的脚本读取这个查询字符串并用 document.write 将其写入页面时,你的脚本就会被执行。
一个典型的攻击URL会类似这样:
https://......./?search=<script>alert('XSS')</script>
至此,成功通关。