postMessage(): common issues and how you can mitigate them?

Websocket-common-vulnerabilities
Websocket: common vulnerabilities plaguing it and managing them.
December 17, 2021
mobile-app-pen-testing
Webinar – Mobile app pen testing: Understanding android apps and how to secure them
January 21, 2022

December 22, 2021

Introduction to postMessage

The window.postMessage() method, provided by the Window interface in web browsers, serves as a pivotal tool for enabling secure cross-origin communication between distinct browsing contexts. This method is instrumental in facilitating interaction between different window objects, such as iframes or popup windows, even when they originate from the same base, but diverge in domains, ports, or protocols.

Why is postMessage used?

Typically, scripts on different pages can access each other only if the pages from which they originate share the same protocol, port number, and host (also known as “same-origin policy”). Window.postMessage() provides a controlled mechanism to bypass this restriction.

Generally speaking, a window can get a reference to another (for example, via targetWindow = window.opener) and then send a MessageEvent on it with targetWindow.postMessage (). The reception window is free to handle this event as needed. The arguments passed to window.postMessage (i.e., the “message”) are exposed to the receiving window through the event object..

Syntax

The two required components are:

  1. window.postMessage() — to send the message
  2. window.addEventListener(“message”,callback) — to receive and process the message

The syntax for the Window: postMessage() method:

targetWindow.postMessage(message, targetOrigin, [transfer]);

There is an optional third parameter, [transfer], that we will not be using. You may want to read more about the MDN.

  • targetWindow’ is an identifier of the window to which you want to send the message.
  • The ‘message’ can have multiple complex objects. However, the functions cannot be sent as part of the message, as the message is serialized using the structured cloning algorithm. The structured cloning algorithm does not support functions. However, this means that you can safely pass a wide variety of data objects.
  • targetOrigin’ is a very important piece. It is the URI of the recipient’s page. At post-message time, if targetOrigin matches the hostname of the targetWindow page, it will not be sent. It is possible to use “*” as the destination source, but only for simple tests.
  • In this complete form, ‘transfer’ is an optional parameter for passing transferable objects. It allows you to send objects with postMessage that are transferred instead of cloned.

Example

We will create two web pages called Page1.html and Page2.html. Page2.html will be a popup window.

Create the following files

Page1.html (note the sendMessage function)

<!DOCTYPE html>

<html>

<head>

    <title></title>

 <meta charset=”utf-8″ />

<script>var childwin;

const childname = “popup”;

function openChild() {childwin = window.open(‘Page2.html’, childname, ‘height=300px, width=500px’);

}

function sendMessage(){

    let msg={pName : “alice”, pAge: “23”};

    // In production, DO NOT use ‘*’, use toe target domain

    childwin.postMessage(msg,’*’)// childwin is the targetWindow

    childwin.focus();

}</script>

</head>

<body>

    <form>

        <fieldset>

            <input type=’button’ id=’btnopen’ value=’Open child’ onclick=’openChild();’ />

            <input type=’button’ id=’btnSendMsg’ value=’Send Message’ onclick=’sendMessage();’ />

        </fieldset>

    </form>

</body>

</html>

Page2.html (note callback function in addEventListener)

<!DOCTYPE html>

<html>

<head>

    <title></title>

    <meta charset=”utf-8″ />

    <script>// Allow window to listen for a postMessage

    window.addEventListener(“message”, (event)=>{// Normally you would check event.origin

        // To verify the targetOrigin matches

        // this window’s domain

        let txt=document.querySelector(‘#txtMsg’);

        // event.data contains the message sent

        txt.value=`Name is ${event.data.pName} Age is  ${event.data.pAge}` ;

    });function closeMe() {

        try {window.close();

        } catch (e) { console.log(e) }

        try {self.close();

        } catch (e) { console.log(e) }}

    </script>

</head>

<body>

    <form>

        <h1>Recipient of postMessage</h1>

            <fieldset>

                <input type=’text’ id=’txtMsg’ />

                <input type=’button’ id=’btnCloseMe’ value=’Close me’ onclick=’closeMe();’ />

            </fieldset>

    </form>

</body>

</html>

Test Run

Open Page1.html and click the “Open child” button. This opens the pop-up.

Popup-targetWindow

Click the “Send Message” button. The message is received by the pop-up window.

Result of childwin.postMessage()

postMessage() Vulnerability

postMessage() must be implemented correctly; otherwise, it may lead to security vulnerabilities such as Cross-Site Scripting (XSS), exposure of sensitive data, information theft, and others.

Detecting these vulnerabilities is not very simple. It requires knowledge and understanding of JavaScript to read the JavaScript of the target application to identify possible points of attack. It is necessary to trace the flow of execution to perform a successful attack.

Identifying the use of PostMessage():

To exploit postMessage () vulnerabilities, you first need to know whether the target application is using web messaging or not. If the target application uses web messaging, it is essential to identify the different listeners. There are several methods to do this, including:

  1. Keyword Search – Use the developer tool’s global search option to search for specific keywords such as postMessage (), addEventListener (“message, .on (” message “in javascript files.
  2. Using the MessPostage browser extension: Using the MessPostage extension is an easy way to detect every time an application uses the postMessage () APIs. This also shows what messages were sent and where event listeners were added:
  3. Usage of developer tools: The “Global listener” function present in the “Sources” panel of the developer tools can be used to identify the use of postMessage(). After opening Global Listener, click on “messages” to view the message handlers.
  4. Use of Posta: Posta is a tool to investigate messaging and communication between documents. It allows you to track, explore, and exploit postMessage vulnerabilities and includes features like replaying messages sent between windows within any attached browser.
  5. Using PMHook: PMHook is a client-side JavaScript library designed to be used with TamperMonkey in the Chrome web browser. Executed immediately on page load, PMHook wraps the EventTarget.addEventListener method and logs any subsequent message events as they are added. The event handler functions themselves are also packaged to record the messages received by each handler.

Dom Based XSS using Insecure postMessage():

HTML5 postMessage introduces a new source of corruption in the form of the message payload (Event.data). A DOM-based Cross-Site Scripting (XSS) vulnerability occurs when the payload of a message event is handled insecurely. The following table lists some of the more common functions and attributes that can lead to an XSS vulnerability.

FunctionDescription
document.write({taint})
document.writeln({taint})
The document.write function writes the string passed to the page, including any embedded script code. To exploit this function, the attacker simply embeds the script code within the tainted input.
element.innerHTML={taint}
element.outerHTML={taint}
Similar to document.write, setting the innerHTML or externalHTML attributes with a tainted value can be exploited by embedding malicious script code within the assigned value.
location={taint}
location.href={taint}
window.open({taint})
location.replace({taint})
Changing the location of the page could be exploited to perform an XSS attack by passing a JavaScript: or Data: protocol handler such as the value. For instance,
location = “JavaScript:alert(‘xss’)”

location = “data:text/html,
<script>alert(document.cookie)</script>”
$({taint})Markup that is passed directly to a jQuery selector is evaluated immediately, and any embedded JavaScript event handlers are executed. For instance; $(“<svg onload=’alert(123)’>”)// Executes
alert(123)
eval({taint})The data passed to the eval () function is evaluated as JavaScript, therefore if the attacker can control the data passed to this function, it is possible to perform XSS.
ScriptElement.src
ScriptElement.text
ScriptElement.textContent
ScriptElement.innerText
Setting the “src” attribute of a script element allows a script to be loaded from an attacking controller server. Setting the text, textContent or innerText allows the content of the script will be modified.
Href,srcattribute of
various elements.
Many elements that support an “href” or “src” attribute can be exploited to perform an XSS attack by setting a JavaScript: or Data: URI. Some examples include; TEXT, EMBED, OBJECT, A, and IFRAME, however, this is not an exhaustive list and new elements are introduced over time.

Impact of postMessage() Exploitation

  1. Insecure implementation of postMessage () can lead to multiple attack scenarios, and one of the widely exploited scenarios is cross-site scripting based on postMessage (), as discussed in one of the previous sections.
  2. Exposure of sensitive data or disclosure of the information is another impact of postMessage () related issues. This information can sometimes include information related to PII, confidential tokens, or credentials such as API keys.
  3. Further, if regex is implemented weakly, it can become an entrance for attackers to exploit it, which would have been blockers if regex had been implemented properly. And they would act as blockers because of certain domain/host-based protection. 

Remediations

  1. If the application does not require communication, such as receiving messages from other websites, it is recommended not to use event listeners for message events unnecessarily.
  2. Do not use a wildcard destination source (*), instead use the expected destination source with postMessage (). It will protect against the attack that tries to use a malicious website to steal confidential information.
  3. Always verify the identity of the sender using the origin.

Conclusion

Use postMessage for multi-threaded applications, and it allows to securely communicating between threads via their created windows. postMessage( ) sends data locally between the Window objects without generating an HTTP request. It is used for DOM-based communication.

Reference

https://www.yeswehack.com/learn-bug-bounty/introduction-postmessage-vulnerabilities

Discover more from SecureLayer7 - Offensive Security, API Scanner & Attack Surface Management

Subscribe now to keep reading and get access to the full archive.

Continue reading

Enable Notifications OK No thanks