影响范围:
3.0.0.RELEASE <= Spring Cloud Function <= 3.2.2
项目简介:
Spring Cloud Function 是一个具有以下高级目标的项目:
- 通过函数促进业务逻辑的实现,可以将函数设置为HTTP端点。
- 将业务逻辑的开发生命周期与任何特定的运行时目标分离,以便相同的代码可以作为 Web 端点、流处理器或任务运行。
- 支持跨无服务器提供商的统一编程模型,以及独立运行(本地或在 PaaS 中)的能力。
- 在无服务器提供程序上启用 Spring Boot 功能(自动配置、依赖注入、指标)
漏洞分析:
首先在项目中找到关键点,把项目从github导入IDEA,发现没有搭建成功,换成JDK17也不行,网上关于这个项目的资料寥寥无几,索性直接看源码找了,在下图中routingExpression
直接会被解析执行,并且context
也是StandardEvaluationContext
,接下来就是找这个参数了
在同一个文件中该函数就会被调用,一个是(String) message.getHeaders().get("spring.cloud.function.routing-expression")
,一个是functionProperties.getRoutingExpression()
,两个都不确定是否可控
先看functionProperties
,在构造函数中赋值
最终找到了functionRouter
,该函数添加了@Bean注解,Spring Cloud Function 项目中核心是推动基于函数的编程模型,而不是熟悉的 POJO 模型,满足一定条件并被@Bean注解后就可以将函数作为HTTP端点进行访问,发现代码中没有出现functionRouter
后,可能这里也作为了HTTP端点进行访问了,但是参数怎么在数据包中设置还得继续看文档。没有找到相关的内容,所以先跳过这个参数了,回到之前找另一个参数(String) message.getHeaders().get("spring.cloud.function.definition")
找message
的信息,在apply
函数中会进行调用,apply
函数经过查询文档之后发现应命名函数的结果,也就是在调用@Bean注解标记后的函数时会执行apply
查看官方文档,这里说明了RoutingFunction
注册在FunctionCatalog
中的名称下functionRouter
,也就是说访问functionRouter
时就会调用对应apply
,而apply
中正好调用了route
,这也与代码中的一致,因此可以通过functionRouter
成功执行到触发点,接下来还需要知道(String) message.getHeaders().get("spring.cloud.function.routing-expression")
,这个值如何控制
(String) message.getHeaders().get("spring.cloud.function.routing-expression")
仔细看这个方法,getHeaders
,很容易能想到请求包中也有header
,接下来就是到官方文档求证…
总结一下:
1、Spring Cloud Function 项目是基于函数的编程模型,而functionRouter
注册成为了HTTP端点
2、在functionRouter
函数中会调用RoutingFunction
,同时执行apply
方法
3、apply()
中会调用route
方法,在该方法中会判断请求内容是否为Message,如果有数据那么会将Hander中的spring.cloud.function.routing-expression
进行SpEL表达式进行解析
漏洞复现:
可以自己搭建也直接使用github上师傅的环境使用IDEA进行搭建,JDK版本为17
https://github.com/cckuailong/spring-cloud-function-SpEL-RCE
POST /functionRouter HTTP/1.1
host:127.0.0.1:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15
Connection: close
spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("open -a /System/Applications/Calculator.app")
Content-Length: 16
xxx
在复现中还发现一点没有分析到,可以在配置文件中配置默认路由,当访问不存在的路由时就会访问指定的该路由,当配置了以下内容时访问不存在的路有也会执行访问functionRouter
的内容
spring.cloud.function.definition:functionRouter
因此在配置之后访问不存在的路由就可以执行,堪称死亡配置…
补丁分析:
查看提交分支
https://github.com/spring-cloud/spring-cloud-function/commit/0e89ee27b2e76138c16bcba6f4bca906c4f3744f
设置SimpleEvaluationContext
来进行防御
总结:
这个漏洞的分析没有Spring Cloud Gateway那么顺利,因为这个项目的官方文档比较难懂,而且网上关于这个项目的使用也很少,可能是国内很少采用基于函数的编程方式吧。只能依靠官方文档和一些简单的教程去理解分析,由于没有调试,可能中间会缺少一些细节部分,分析有误的地方请大佬们及时指正~
参考内容:
- https://spring.io/projects/spring-cloud-function#overview
- https://docs.spring.io/spring-cloud-function/docs/3.1.7/reference/html/spring-cloud-function.html
- https://github.com/cckuailong/spring-cloud-function-SpEL-RCE
喜欢的大佬们可以添加我的公众号,我会在公众号里持续分享一些安全的内容,可以一起交流~