spring-messaging 远程代码执行漏洞分析
字数 1763 2025-08-03 10:57:11

Spring Messaging 远程代码执行漏洞分析教学文档

漏洞概述

Spring Messaging 组件中存在一个远程代码执行漏洞,攻击者可以通过构造恶意的 STOMP 消息触发 SpEL 表达式注入,从而在目标服务器上执行任意代码。

环境搭建

  1. 获取漏洞环境代码:

    https://github.com/spring-guides/gs-messaging-stomp-websocket/tree/6958af0b02bf05282673826b73cd7a85e84c12d3
    
  2. 使用 IntelliJ IDEA 导入项目:

    • 打开 pom.xml 文件
    • 配置运行环境:
      • 点击 "Edit Configurations"
      • 添加 Maven 配置
      • 在 "Command line" 输入:spring-boot:run

漏洞复现步骤

  1. 访问应用:http://127.0.0.1:8080/
  2. 点击 "Connect" 按钮建立 WebSocket 连接
  3. 使用抓包工具拦截 WebSocket 通信
  4. 当出现 "WebSockets message to" 消息时,修改内容为:
    ["SUBSCRIBE\nid:sub-0\ndestination:/topic/greetings\nselector:new java.lang.ProcessBuilder('calc.exe').start()  \n\n\u0000"]
    
  5. 返回页面,输入任意内容并点击 "Send"
  6. 观察计算器程序被弹出(证明代码执行成功)

漏洞原理分析

WebSocket 与 STOMP 协议

  1. WebSocket 是 HTML5 提出的实时通信协议
  2. STOMP (Simple Text Oriented Messaging Protocol) 是 WebSocket 的子协议,定义了消息传输格式
  3. 常用 STOMP 命令:
    • CONNECT/CONNECTED
    • SEND
    • SUBSCRIBE/UNSUBSCRIBE
    • BEGIN/COMMIT/ABORT
    • ACK/NACK
    • DISCONNECT

漏洞触发流程

  1. 订阅阶段 (SUBSCRIBE)

    • 攻击者发送恶意 SUBSCRIBE 消息,其中包含 selector 头部
    • 服务端调用 DefaultSubscriptionRegistry.addSubscriptionInternal 方法
    • 方法中通过 SimpMessageHeaderAccessor.getFirstNativeHeader 获取 selector
    • 使用 SpelExpressionParser.parseExpression 解析 selector 值(恶意 SpEL 表达式)
  2. 存储阶段

    • 解析后的表达式被存储在 DefaultSubscriptionRegistry
    • 与 sessionId 和 subscriptionId 关联
  3. 触发阶段 (SEND)

    • 当发送 SEND 消息时,调用 AbstractSubscriptionRegistry.filterSubscriptions
    • 方法遍历所有订阅,获取存储的表达式
    • 调用 expression.getValue 执行 SpEL 表达式
    • 恶意代码被执行

关键代码分析

  1. 表达式解析

    String selector = SimpMessageHeaderAccessor.getFirstNativeHeader(
        this.getSelectorHeaderName(), headers);
    if (selector != null) {
        expression = this.expressionParser.parseExpression(selector);
    }
    
  2. 表达式存储

    this.subscriptionRegistry.addSubscription(sessionId, subsId, destination, expression);
    
  3. 表达式执行

    if (Boolean.TRUE.equals(expression.getValue(context, Boolean.class))) {
        result.add(sessionId, subId);
    }
    

补丁分析

补丁链接:

https://github.com/spring-projects/spring-framework/commit/e0de9126ed8cf25cf141d3e66420da94e350708a#diff-ca84ec52e20ebb2a3732c6c15f37d37aL217

主要修改:

  • StandardEvaluationContext 替换为 SimpleEvaluationContext
  • SimpleEvaluationContext 限制:
    • 不支持 Java 类型引用
    • 不支持构造函数调用
    • 不支持 bean 引用

防御建议

  1. 升级 Spring Framework 到已修复版本
  2. 如果无法立即升级,可考虑:
    • 禁用 STOMP 的 selector 功能
    • 实现自定义的 SubscriptionRegistry 过滤恶意表达式
  3. 对 WebSocket 端点实施身份验证和授权

扩展知识

  1. SpEL 表达式注入

    • Spring Expression Language (SpEL) 是 Spring 的表达式语言
    • 类似其他模板注入漏洞,当用户输入被直接解析时可能导致 RCE
  2. WebSocket 安全

    • 确保所有 WebSocket 端点都有适当的访问控制
    • 考虑对消息内容进行验证和过滤
  3. STOMP 协议安全

    • 限制可用的 STOMP 命令
    • 对订阅目标实施白名单控制

总结

该漏洞展示了即使在使用现代协议如 WebSocket 和 STOMP 时,如果不对用户输入进行严格验证,仍然可能导致严重的安全问题。开发者应当对所有用户提供的数据保持警惕,特别是在涉及表达式解析或代码执行的场景中。

Spring Messaging 远程代码执行漏洞分析教学文档 漏洞概述 Spring Messaging 组件中存在一个远程代码执行漏洞,攻击者可以通过构造恶意的 STOMP 消息触发 SpEL 表达式注入,从而在目标服务器上执行任意代码。 环境搭建 获取漏洞环境代码: 使用 IntelliJ IDEA 导入项目: 打开 pom.xml 文件 配置运行环境: 点击 "Edit Configurations" 添加 Maven 配置 在 "Command line" 输入: spring-boot:run 漏洞复现步骤 访问应用: http://127.0.0.1:8080/ 点击 "Connect" 按钮建立 WebSocket 连接 使用抓包工具拦截 WebSocket 通信 当出现 "WebSockets message to" 消息时,修改内容为: 返回页面,输入任意内容并点击 "Send" 观察计算器程序被弹出(证明代码执行成功) 漏洞原理分析 WebSocket 与 STOMP 协议 WebSocket 是 HTML5 提出的实时通信协议 STOMP (Simple Text Oriented Messaging Protocol) 是 WebSocket 的子协议,定义了消息传输格式 常用 STOMP 命令: CONNECT/CONNECTED SEND SUBSCRIBE/UNSUBSCRIBE BEGIN/COMMIT/ABORT ACK/NACK DISCONNECT 漏洞触发流程 订阅阶段 (SUBSCRIBE) : 攻击者发送恶意 SUBSCRIBE 消息,其中包含 selector 头部 服务端调用 DefaultSubscriptionRegistry.addSubscriptionInternal 方法 方法中通过 SimpMessageHeaderAccessor.getFirstNativeHeader 获取 selector 值 使用 SpelExpressionParser.parseExpression 解析 selector 值(恶意 SpEL 表达式) 存储阶段 : 解析后的表达式被存储在 DefaultSubscriptionRegistry 中 与 sessionId 和 subscriptionId 关联 触发阶段 (SEND) : 当发送 SEND 消息时,调用 AbstractSubscriptionRegistry.filterSubscriptions 方法遍历所有订阅,获取存储的表达式 调用 expression.getValue 执行 SpEL 表达式 恶意代码被执行 关键代码分析 表达式解析 : 表达式存储 : 表达式执行 : 补丁分析 补丁链接: 主要修改: 将 StandardEvaluationContext 替换为 SimpleEvaluationContext SimpleEvaluationContext 限制: 不支持 Java 类型引用 不支持构造函数调用 不支持 bean 引用 防御建议 升级 Spring Framework 到已修复版本 如果无法立即升级,可考虑: 禁用 STOMP 的 selector 功能 实现自定义的 SubscriptionRegistry 过滤恶意表达式 对 WebSocket 端点实施身份验证和授权 扩展知识 SpEL 表达式注入 : Spring Expression Language (SpEL) 是 Spring 的表达式语言 类似其他模板注入漏洞,当用户输入被直接解析时可能导致 RCE WebSocket 安全 : 确保所有 WebSocket 端点都有适当的访问控制 考虑对消息内容进行验证和过滤 STOMP 协议安全 : 限制可用的 STOMP 命令 对订阅目标实施白名单控制 总结 该漏洞展示了即使在使用现代协议如 WebSocket 和 STOMP 时,如果不对用户输入进行严格验证,仍然可能导致严重的安全问题。开发者应当对所有用户提供的数据保持警惕,特别是在涉及表达式解析或代码执行的场景中。