PostMessage Vulnerabilities
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
PostMessage uses the following function to send a message:
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.
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.
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:
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).
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.
event.isTrusted
attribute is considered secure as it returns True
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:
The search()
method from String.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:
The match()
function, similar to search()
, 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 acknowledge hasOwnProperty
, the escapeHtml
won't perform as expected. This is demonstrated in the examples below:
Expected Failure:
Bypassing the escape:
In the context of this vulnerability, the File
object is notably exploitable due to its read-only name
property. This property, when used in templates, is not sanitized by the escapeHtml
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.
When embedding a web page within a sandboxed iframe using %%%%%%, it's crucial to understand that the iframe's origin will be set to null. This is particularly important when dealing with sandbox attributes and their implications on security and functionality.
By specifying allow-popups
in the sandbox attribute, any popup window opened from within the iframe inherits the sandbox restrictions of its parent. This means that unless the allow-popups-to-escape-sandbox
attribute is also included, the popup window's origin is similarly set to null
, aligning with the iframe's origin.
Consequently, when a popup is opened under these conditions and a message is sent from the iframe to the popup using postMessage
, both the sending and receiving ends have their origins set to null
. This situation leads to a scenario where e.origin == window.origin
evaluates to true (null == null
), because both the iframe and the popup share the same origin value of null
.
For more information read:
Bypassing SOP with Iframes - 1It's possible to check if the message came from the same window the script is listening in (specially interesting for Content Scripts from browser extensions to check if the message was sent from the same page):
You can force e.source
of a message to be null by creating an iframe that sends the postMessage and is immediately deleted.
For more information read:
Bypassing SOP with Iframes - 2In order to perform these attacks ideally you will be able to put the victim web page inside an iframe
. But some headers like X-Frame-Header
can prevent that behaviour.
In those scenarios you can still use a less stealthy attack. You can open a new tab to the vulnerable web application and communicate with it:
In the following page you can see how you could steal a sensitive postmessage data sent to a child iframe by blocking the main page before sending the data and abusing a XSS in the child to leak the data before it's received:
Blocking main page to steal postmessageIf you can iframe a webpage without X-Frame-Header that contains another iframe, you can change the location of that child iframe, so if it's receiving a postmessage sent using a wildcard, an attacker could change that iframe origin to a page controlled by him and steal the message:
Steal postmessage modifying iframe locationIn scenarios where the data sent through postMessage
is executed by JS, you can iframe the page and exploit the prototype pollution/XSS sending the exploit via postMessage
.
A couple of very good explained XSS though postMessage
can be found in https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Example of an exploit to abuse Prototype Pollution and then XSS through a postMessage
to an iframe
:
For more information:
Link to page about prototype pollution
Link to page about XSS
Link to page about client side prototype pollution to XSS
To practice: https://github.com/yavolo/eventlistener-xss-recon
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)