postMessage安全性的一点点研究
postMessage安全性的一点点研究
说点废话
近期深刻认识到自己能力不足,水平有限,必须沉下心来进行学习和研究,否则一辈子除了搬砖什么都做不了。
postMessage是为了解决跨窗口跨域的情况,使用不当会存在一些安全问题(虽然我没挖到Orz)。
postMessage是什么
Syntax
1 | targetWindow.postMessage(message, targetOrigin, [transfer]); |
不造轮子了,mdn上说的比较清楚了。
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
当然了,发送消息是不行的,目标窗口肯定需要接受这个消息,所以需要在targetWindow添加一个Message的监听器。
1 | window.addEventListener('message',function(event){ |
这个MessageEvent除了data属性还有source属性和origin属性是比较常见的。source属性就是发送消息的窗口的window对象,origin属性顾名思义就是发送消息的源。
在我实际测试后,无法向使用window.open得到的window对象发送消息,就像这样的。
1 | var popup = window.open('http://www.target.com/listener.html'); |
神奇的是,在使用setInterval大法后就正常了,但是仍然收不到第一个请求。推测是originWindow发送message时,targetWindow监听器没有加载完成。从网上随便找了个sleep函数,就像下面这样。
1 | var popup = window.open("http://www.poc.com/listener.html"); |
但是sleep函数执行时,targetWindow也给sleep了。
神奇的js。
更正: 使用setTimeout可以完美解决这个问题。
postMessage有什么问题
伪造接收端
伪造接收端就比较简单了,如果你见到了下面这样的写法
1 | targetWindow.postMessage(message,'*') |
就意味着任意域可以接收到这条消息。现实往往不像看起来那么美好,主要问题不是人家让不让你收(origin),而是发不发给你(targetWindow)。也就是说如果人家的targetWindow是子窗口,那么你是根本收不到消息哒~
发送给父窗口的情况有可能存在于一些js的widget,或者iframe的页面中。如果是发送给window.parent.prames,那么很遗憾的告诉你,基本也是没希望的。因为大部分网站已经设置X-Frame-Options: Origin
,只有同源才可以使用iframe包裹。
伪造发送端
如果监听器(EventListener)没有校验消息的来源(origin),或者校验存在问题的时候,就意味着我们可以给它发送消息。并且会代入程序逻辑。
比如下面这样的
1 | window.addEventListener('message',function(event){ |
正确的写法应该是这样的
1 | window.addEventListener('message',function(event){ |
如何去挖
如何伪造接收端上面已经说得比较清楚了,使用chrome的search就可以全局搜索,但是有时候会有一些迷之搜不到的情况……
伪造发送端
在chrome的Global Listeners处看看当前页面存在几个监听器,打断点。使用window.postMessage(poc,'*')
去调就可以。
trick
- 有的时候全局搜索
addEventListener
会发现代码中存在但是却没有注册为Listener的情况,这个时候应该是没有触发响应的逻辑,具体什么时候会触发现在我也没有找到一定的规律(业务点)。 attachEvent('onmessage',funciton(e){})
也会处理响应的message数据,建议也给断上。- 对于无法是有iframe包裹的情况可以尝试使用使用以下几种方法
1 | window.open |
- window之间传送的消息如果是json的话有可能会有str2json的函数,这类函数中极有可能使用eval()
- message不仅仅可以传送string,同时可以传输object,传输过程中可能存在序列化和反序列化(挖CVE的同学划重点了 ps:个人瞎猜,不负责任)
写在后面
有的时候见到port1.postMessage(message)
的情况,不要奇怪,这是使用了messageChannel。messageChannel简单的说就是在两个窗口间创建一个通道,可以方便的发送消息。没有深入研究有没有伪造的可能。
更新: 看了一眼messageChannel感觉没什么新东西,在特定场景有可能会出漏洞。比如其中一个端口是window.parent。(看了一个比喻,说messageChannel是土电话,很贴切了,哈哈哈哈哈哈哈哈)
对于现在手上的项目进行挖掘后并没有很喜人的进展,我太菜了Orz…….
等我挖到洞相关洞了再更一波~