漏洞简介
Spring 框架中通过spring-messaging 模块来实现 STOMP (Simple Text-Orientated Messaging Protocol),STOMP是一种封装 WebSocket的简单消息协议。攻击者可以通过建立WebSocket连接并发送一条消息造成远程代码执行, spring-messaging和spring-websocket模块都能提供WebSocket支持的STOMP,一旦有了这些依赖项,就可以通过WebSocket使用SockJS Fallback公开STOMP端点。
具体的说,在Spring Messaging 中,其允许客户端订阅消息,并使用selector 过滤消息,其中 selector 使用SpEL 表达式编写,并使用StandardEvaluationContext解析,从而导致SpEL表达式注入漏洞。
推荐一篇文章 以理解 STOMP :Spring消息之STOMP - JMCui - 博客园 (cnblogs.com)
引用p神的描述:
spring-messaging是基于sockjs(可以理解为一个通信协议),而sockjs适配多种浏览器:现代浏览器中使用websocket通信,老式浏览器中使用ajax通信。 连接后端服务器的流程,可以理解为:
1. 用STOMP协议将数据组合成一个文本流
2. 用sockjs协议发送文本流,sockjs会选择一个合适的通道:websocket或xhr(http),与后端通信
正是由于第2条的存在,我们才可以使用http来复现该漏洞,称之为“降维打击”
如同提及 Struts2 RCE 类漏洞都要提及OGNL 表达式语言
而 Spring 的RCE 类漏洞 往往和SpEL 表达式有关
环境搭建:
git clone https://github.com/spring-guides/gs-messaging-stomp-websocket
回退到 漏洞版本
cd gs-messaging-stomp-websocket
git checkout 6958af0b02bf05282673826b73cd7a85e84c12d3
然后导入到IDEA,进行MAVEN加载
运行成功:
漏洞复现:
方式一:
通过开发者工具F12 修改其中的 app.js 里面的 connect函数
如何修改,直接定义一个header,里面写入json格式的“selector”,值为SpEL表达式,内容是弹计算器;最后在加入该header
var header = {"selector":"T(java.lang.Runtime).getRuntime().exec('calc.exe')"};
最后记得保存一下该app.js
这个时候,依次点击Connect,输入任意字符串,单击Send
利用完成了,但是感觉不是RCE,就像是修改本地文件一样。
但是如果你去Console 看一眼,你会发现整个通讯过程很多是js 完成的,不是app.js发起,就是调用 stomp.min.js 来发起
方式二:
从前面提到
STOMP是将数据组合成文本流,spring