• SpringCloud Function SpEL注入漏洞分析(CVE-2022-22963)


    SpringCloud Function 介绍

    SpringCloud 是一套分布式系统的解决方案,常见的还有阿里巴巴的Dubbo,Fass(Function As A Service )的底层实现就是函数式编程,在视频转码、音视频转换、数据仓库ETL等与状态相关度低的领域运用的比较多。开发者无需关注服务器环境运维等问题上,专注于自身业务逻辑实现即可。

    SpringCloud Function 就是Spring提供的分布式函数式编程组件。

    image-20220401101253220

    漏洞环境搭建

    通过idea新建一个Spring项目,pom中引入spring-boot-starter-webspring-cloud-function-web,如下:

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>SpringCloudDemo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>SpringCloudDemo</name> <description>SpringCloudDemo</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>2021.0.1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-function-web</artifactId> <version>3.2.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>

    image-20220401144838412

    其中spring-cloud-function-web的依赖如上图,核心实现为spring-cloud-function-core包。

    先在main函数中新建两个方法(uppercase将字符串变为大写,reverse字符串反转):

    image-20220407095021125

    当在pom中引入spring-cloud-function-web后,函数会自动添加为HTTP端点。

    然后漏洞关键是在application.properties 或者yaml配置文件中新增一行:

    spring.cloud.function.definition=functionRouter

    这里的属性spring.cloud.function.definition 表示声明式函数组合,这个功能允许在提供属性时使用|(管道),;(过滤)分隔符以声明的方式提供组合指令。例如

    --spring.cloud.function.definition=uppercase|reverse

    举例:

    当配置该属性为uppercase时,访问根路径提交的参数会自动被uppercase函数接受转化为大写:

    image-20220407100743588

    image-20220407100648638

    反之若配置为reverse则默认路径函数功能为反转字符串:

    image-20220407100849083

    image-20220407100912828

    通俗来讲这个属性就是一个默认路由, 可以手动指定相关函数,也可以使用functionRouter ,指定的方式可以是配置文件、环境变量或者启动参数等

    functionRouter

    如果设置为functionRouter则默认路由绑定的具体函数交由用户进行控制,在 Spring Cloud Function Web里面,可以通过设置http头的方式来控制,使用spring.cloud.function.definitionspring.cloud.function.routing-expression 都可以,区别是后者允许使用Spring表达式语言(SpEL)

    举例:

    image-20220407101221032

    image-20220407101243914

    image-20220407101308586

    image-20220407101414750

    因为spring.cloud.function.routing-expression 允许使用SpEL表达式,所以就可能存在SpEL注入

    SpEL注入

    这里简单介绍下SpEL,Spring Expression Language 是Spring提供的具有方法调用和基本的字符串模版功能的套件。类似OGNL、MVEL、JBoss EL。

    SpEL可以字符串之间进行嵌套也可以单独使用,嵌套时使用#{}(实现ParserContext接口)。

    举例:

    image-20220407104131771

    但因为Spel支持方法调用,所以如果使用的是StandardEvaluationContext 进行解析(默认),则可能会被滥用,如使用new ProcessBuilder('/System/Applications/Calculator.app/Contents/MacOS/Calculator').start()可触发命令执行:

    image-20220407104613567

    漏洞复现

    既然SpringCloud Function 中的functionRouter支持SpEL那是不是存在SpEL注入呢,我们在HTTP头中插入上面调起计算器的SpEL表达式

    Payload: spring.cloud.function.routing-expression: new ProcessBuilder('/System/Applications/Calculator.app/Contents/MacOS/Calculator').start()

    非常简单粗暴,漏洞复现成功:

    image-20220407105317920

    原理分析

    在命令执行出下断点,看下程序执行流程。

    SpringCloud Function之所以能自动将函数建立http端点,是因为在包mvc.FunctionController中使用/** 监听了get/post类型的所有端点。

    1. 当一个请求进入时,程序首先基于Springboot的自动配置,将配置文件注入到functionProperties,随后将以“WebRequestConstants.handler”为key,function为值添加到request数组里面。

    image-20220407164023103

    image-20220407164200379

    1. 请求正式进入Controller节点,Controller首先会将请求使用wrapper进行包装,wrapper就是将request转成FunctionInvocationWrapper 格式。

    image-20220407164733082

    1. 随后进入processRequest 对request进行处理,执行function的apply方法,跳转到doApply()时会对function进行判断,判断是不是functionRouter方法,根据咱们的配置文件此时的function为RoutingFunction.FUNCTION_NAMEfunctionRouter所以会,一路跳转到RoutingFunction.route

    image-20220407170619009

    image-20220407170151488

    image-20220407170208535

    1. 随后进入else if 分支, http头spring.cloud.function.routing-expression 不为空,则传入其值到functionFromExpression方法。
      image-20220407170804259

    2. 使用标准的StandardEvaluationContext 对header的值进行SpEL表达式解析:

    image-20220407171027665

    image-20220407171053490

    后续就不用再跟下去了,至此可以发现,只要通过环境变量、配置文件或者参数等方式配置为spring.cloud.function.definition=functionRouter 即可触发SpEL注入。

    补丁分析

    SpringCloud官方已经修复了此问题(https://github.com/spring-cloud/spring-cloud-function/commit/0e89ee27b2e76138c16bcba6f4bca906c4f3744f)

    和其他SpEL注入修复方式一样,使用了SimpleEvaluationContext替换StandardEvaluationContext,那这个漏洞基本就算修复完成了。但因为这个commit还没有纳入版本,所以目前springcloud Function3.0以上版本仍然暴露在风险之中。

    image-20220407171533592

    引用

    公众号

    欢迎大家关注我的公众号,这里有干货满满的硬核安全知识,和我一起学起来吧!


    __EOF__

    本文作者9eek
    本文链接https://www.cnblogs.com/9eek/p/16113603.html
    关于博主:评论和私信会在第一时间回复。或者直接私信我。
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
  • 相关阅读:
    图像识别(九)| 彻底搞懂SoftMax分类的底层逻辑
    根据Power switch建模发散开来的内部结构
    css打造漫天飞舞的蝴蝶
    mac废纸篓的如何还原?
    如何将带GPS的网络化的软件定义无线电接收机应用于分布式和移动频谱监测?(二)
    CICD 持续集成与持续交付——git
    Linux:文本搜索命令grep
    【理解线性代数】(四)从向量组点乘到矩阵相乘
    程序员的护城河
    如何利用 promise 影响代码的执行顺序?
  • 原文地址:https://www.cnblogs.com/9eek/p/16113603.html