The WebSocket Protocol, standardized in 2011 with RFC 6455, enables full-duplex communication between clients and web servers over a single, persistent connection, resolving a longstanding limitation of HTTP that hindered bidirectional client to server communication. For example, if you’d like to receive real-time sports updates for a game, your web browser would need to send a request to the web server once every second checking if there were any changes to the score. With WebSockets, the server sends your browser the updates as they happen, removing the need for constant polling. This reduces bandwidth usage and delays experienced by the user for real-time events.  

The differences between the traditional HTTP connection and a WebSocket connection are illustrated below. Notice that after the handshake, the WebSocket session remains connected and is bidirectional, while in a traditional HTTP transaction the connection is terminated, requiring a new request. 

This blog will demonstrate how to exploit the handshake step of the WebSocket protocol, allowing a malicious webpage to hijack a WebSocket using the victim’s cookies. Each time I’ve encountered an application using WebSockets on a penetration test with meaningful functionality, this vulnerability was present. The impact has ranged from privilege escalation to remote code execution. For a more general overview of WebSocket hacking, reference our previous blog post — How to Hack WebSockets and Socket.io.

Understanding and Detecting WebSockets 

I’ll be using Burp Suite Academy’s free online lab so anyone can follow along. The lab occasionally timed out and needed to be refreshed, which caused a slight change in the subdomain name throughout the blog. 

First things first, you need to determine if the web application you are testing uses WebSockets. The best way to go about this is to set up Burp Suite to capture traffic and click around every page you see. Most of the time, only a small component of the site will use WebSockets, so you’ll have to search around. Next, open Burp Suite and click the Proxy -> WebSockets history tabs to view any captured WebSocket traffic. If nothing appears then, no WebSocket traffic was found. As shown below, the /chat endpoint appeared to send and receive data over WebSockets. 

WebSocket Communication from Live Chat Captured in Burp Suite 

Let me backtrack a bit and give some context to how the WebSocket connection was established in the first place. It all starts with good ole’ HTTP, as you can see in the image above. Browsing to the /chat endpoint returned an HTML document with the following reference to a JavaScript file. 

Once loaded, the JavaScript opened a new WebSocket connection and referenced the action attribute of the chat form to get the URL.

function openWebSocket() {
return new Promise(res => {
    if (webSocket) {
        res(webSocket);
        return;
    }
    let newWebSocket = new WebSocket(chatForm.getAttribute("action"));
});
}

The HTML snippet below shows the action attribute of the referenced chat form. The URL highlighted in red is used by the WebSocket code above. Please note that wss:// stands for WebSocket secure and tells a WebSocket client library to use TLS to connect to a WebSocket server. If you ever see a server send meaningful data over WebSockets without transport layer encryption, such as ws://, this would be a finding. 

action="wss://0aaf007d04e7a0c383151979009000dd.web-security-academy.net/chat">

Your message: