Spring Messaging 远程代码执行漏洞分析(CVE-2018-1270)

本文探讨了Spring Framework 5.0至5.0.4版本的远程命令执行漏洞(CVE-2018-1270),涉及WebSocket、SockJS和STOMP协议。通过实例展示了如何利用STOMP的selector漏洞进行攻击,并提供了修复方法和相关技术背景知识。

Spring Messaging 远程命令执行漏洞(CVE-2018-1270)

漏洞公告:

https://tanzu.vmware.com/security/cve-2018-1270

影响版本:

  • Spring Framework 5.0 to 5.0.4
  • Spring Framework 4.3 to 4.3.15
  • Older unsupported versions are also affected

环境搭建:

https://github.com/spring-guides/gs-messaging-stomp-websocket
 
执行git checkout 2.0.0.RELEASE切换版本,该版本使用了存在漏洞的spring-messaging:5.0.4

相关知识

在分析这个漏洞之前,这里简单介绍相关的一些概念。详细内容请阅读文末罗列的参考资料。

WebSocket、SockJS和STOMP

WebSocket:是 HTML5 新增加特性之一,目的是浏览器与服务端建立全双工的通信方式,解决 http 请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天、股票交易、游戏等对对实时性要求较高的行业领域。

HTTP与WebSocket都是基于TCP(传输控制协议)的,WebSocket可以看做是对http协议的一个补充,它复用HTTP/HTTPS的端口。

WebSocket协议提供了通过一个套接字实现全双工通信的功能。除了其他的功能之外,它能够实现Web浏览器和服务器之间的异步通信。全双工意味着服务器可以发送消息给浏览器,浏览器也可以发送消息给服务器。

SockJS:SockJS是一个JavaScript库,为了应对许多浏览器不支持WebSocket协议的问题,设计了备选SockJS。SockJS 是 WebSocket 技术的一种模拟。SockJS会尽可能对应 WebSocket API,但如果WebSocket 技术不可用的话,会自动降为轮询的方式。

WebSocket是一个相对比较新的规范,在Web浏览器和应用服务器上没有得到一致的支持。所以我们需要一种WebSocket的备选方案,而这恰恰是SockJS所擅长的。

SockJS是WebSocket技术的一种模拟,在表面上,它尽可能对应WebSocket API,但是在底层非常智能。如果WebSocket技术不可用的话,就会选择另外的通信方式。

SockJS会优先选择WebSocket进行连接,但是当服务器或客户端不支持WebSocket时,会自动在 XHR流、XDR流、iFrame事件源、iFrame HTML文件、XHR轮询、XDR轮询、iFrame XHR轮询、JSONP轮询 这几个方案中择优进行连接。

STOMP: 即 Simple Text Oriented Message Protocol——面向消息的简单文本协议。SockJS 为 WebSocket 提供了 备选方案。但无论哪种场景,对于实际应用来说,这种通信形式层级过低。STOMP协议,为浏览器 和 服务器之间的通信增加适当的消息语义。

三者的关系

简而言之,WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是底层协议,而 STOMP 是基于 WebSocket(SockJS)的上层协议。

STOMP和WebSocket(SockJS)的关系,类似于HTTP和TCP。

(1)HTTP协议解决了 Web 浏览器发起请求以及 web 服务器响应请求的细节,假设 HTTP 协议 并不存在,只能使用 TCP 套接字来编写 web 应用,那将是一件非常痛苦的事情。

(2)直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;

(3)同HTTP在TCP 套接字上添加请求-响应模型层一样,STOMP在WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;

WebSocket、SockJS、STOMP三者,从前往后,层级依次上升,就像洋葱,WebSocket在里面,SockJS其次,STOMP在最外面。如果我们使用建立在SockJS协议上的STOMP服务,而SockJS又选择WebSocket作为底层的通信协议。在通信过程中,STOMP帧会被组装成SockJS的帧;SockJS的帧会被组装成WebSocket的帧;再深一点,WebSocket的帧会被组装成TCP的帧;TCP的帧被组装成IP层的帧,然后传输;到远端后执行相反操作。

从分类上说,WebSocket和SockJS都只是通用的数据传输协议;而STOMP是一种消息协议,抽象层级更高。

STOMP的消息结构和示例

STOMP是一种基于帧的协议,其帧基于HTTP建模。STOMP消息帧结构如下:

COMMAND
header1:value1
header2:value2

Body^@

^@表示字符串结束符\x00

客户端可以使用SENDSUBSCRIBE命令发送订阅带有destination请求头的消息,destination描述了消息的内容以及应该接收该消息的人。

在使用Spring的STOMP支持时,Spring WebSocket应用程序充当客户端的STOMP代理。消息被路由到@Controller类的消息处理方法或一个简单的内存中代理,该代理跟踪订阅并将消息广播给订阅用户。你也可以配置Spring使用专用的STOMP代理(例如RabbitMQ, ActiveMQ等)来实际广播消息。在这种情况下,Spring维护与代理的TCP连接,将消息转发给代理,并将消息从代理向下传递到连接的WebSocket客户端。

示例1:客户端订阅股票报价

SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*

^@

示例2:客户端发送交易请求

SEND
destination:/queue/trade
content-type:application/json
content-length:44

{"action":"BUY","ticker":"MMM","shares",44}^@

示例3:服务器发送股票报价给订阅客户端

MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM

{"ticker":"MMM","price":129.45}^@

服务器不能发送未经请求的消息。来自服务器的所有消息都必须响应特定的客户端订阅,且服务器消息的subscription-id请求头必须与客户端订阅的id请求头匹配。

Spring Messaging

Spring Messaging是Spring框架中的一个模块,该模块为Spring框架提供消息支持,其上层协议是STOMP,底层通信基于SockJS。

一旦公开了STOMP端点,Spring应用程序就成为已连接的客户端的STOMP代理(STOMP broker)。

下图显示了基于Spring的消息订阅程序,且使用内置的消息代理(SimpleBrokerMessageHandler)时的消息传递流程:
在这里插入图片描述
上图中,有3个消息通道(Channel):

  • clientInboundChannel:用于传递来自WebSocket客户端发来的消息。
  • clientOutboundChannel:用于向WebSocket客户端发送服务端消息。
  • brokerChannel:用于从服务器端、应用程序代码中向消息代理(message broker)发送消息。

下面结合本次漏洞复现的示例代码理一下工作流程。

前端:app.js

var stompClient = null;

function setConnected(connected) {
   
   
    $("#connect").prop("disabled", connected);
    $("#disconnect").prop(
### 漏洞概述 CVE-2018-1270Spring Framework 中 **spring-messaging** 组件存在的一个远程代码执行(RCE)漏洞。该漏洞源于在处理 STOMP(Simple Text-Oriented Messaging Protocol)消息时,Spring Messaging 对用户输入的 SpEL(Spring Expression Language)表达式未进行充分的安全校验,导致攻击者可以通过构造恶意的 STOMP 消息来执行任意代码 [^2]。 此漏洞主要影响使用了 SpringWebSocket、SockJS 和 STOMP 功能的应用程序,尤其是在未启用适当安全控制的情况下。 ### 受影响版本 受 CVE-2018-1270 影响的 Spring Framework 版本包括: - 4.3.x 至 4.3.24 - 5.0.x 至 5.0.13 ### 漏洞原理 Spring Messaging 提供了对 STOMP 协议的支持,允许客户端通过 WebSocket 或 SockJS 建立连接并发送消息。在某些配置下,Spring 允许在消息头中使用 SpEL 表达式来动态解析值。例如,可以使用类似 `${systemProperties['user.name']}` 的表达式来获取系统属性。 攻击者通过构造包含恶意 SpEL 表达式的 STOMP 消息,并发送到存在漏洞的服务端,从而触发远程代码执行 [^3]。典型的攻击流程如下: 1. 攻击者建立 WebSocket 或 SockJS 连接。 2. 发送构造好的带有恶意 SpEL 的 STOMP 消息。 3. Spring 在处理消息时解析并执行 SpEL 表达式。 4. 恶意代码被执行,导致 RCE。 ### 利用示例 以下是一个简化的 PoC 示例,展示如何构造一个恶意的 STOMP 消息来执行命令: ```stomp CONNECT accept-version:1.1,1.0 heart-beat:10000,10000 ^@ SUBSCRIBE id:sub-0 destination:/topic/greetings headers:"T(java.lang.Runtime).getRuntime().exec('calc')" ^@ ``` 在这个例子中,`headers` 字段包含了一个 SpEL 表达式,尝试调用 `Runtime.exec()` 来执行系统命令(如打开计算器)。如果服务端未正确过滤或限制 SpEL 表达式的使用,将导致任意命令执行 [^4]。 ### 修复方法 为防止 CVE-2018-1270 漏洞的影响,建议采取以下措施: #### 1. 升级 Spring Framework 版本 官方已在以下版本中修复了该漏洞- Spring Framework 4.3.24+ - Spring Framework 5.0.13+ 升级到上述版本之一即可获得修复补丁。 #### 2. 配置 SpEL 表达式白名单 即使无法立即升级,也可以通过限制 SpEL 表达式的使用范围来缓解风险。可以在应用中禁用或限制 SpEL 的自动求值行为。例如,在配置类中设置 `SpelExpressionParser` 的安全策略: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").withSockJS(); } @Bean public SpelExpressionParser spelExpressionParser() { return new SpelExpressionParser(new SpelParserConfiguration(false, false)); } } ``` #### 3. 启用 Spring Security 权限控制 如果应用启用了 Spring Security,则可以增加攻击者的利用难度。通过配置认证和授权机制,确保只有经过身份验证的用户才能访问 WebSocket 端点 [^2]。 例如,添加如下安全配置: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/ws/**").authenticated() .and() .httpBasic(); } } ``` #### 4. 使用 WAF 或 IDS/IPS 规则 部署 Web 应用防火墙(WAF)或入侵检测系统(IDS)可以帮助识别和拦截包含可疑 SpEL 表达式的请求流量,从而提供额外的防护层。 --- ### 总结 CVE-2018-1270 是由于 Spring Messaging 对 SpEL 表达式的处理不当而导致的远程代码执行漏洞。攻击者可通过构造恶意的 STOMP 消息实现任意命令执行。建议尽快升级到修复版本,并结合安全配置和外部防护手段以全面缓解风险。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值