Tomcat 运行时动态添加删除filter

最近工作需要在写tomcat内存马,使用的方法便是动态插入filter,有个需求就是插入之后还需要能控制将其删除,于是有了下文tomcat 运行时动态添加删除filter

动态添加filter

运行时动态添加filter

动态删除filter

每次访问某个页面都会创建一次filter,实际filter的创建是在org.apache.catalina.core.StandardWrapperValve#invoke中的ApplicationFilterFactory.createFilterChain

下断点跟入调试跟入ApplicationFilterFactory.createFilterChain

从context提取了FilterMaps数组,并且遍历添加到filterChain,最终生效

所以动态删除的话只要从FilterMaps中删除就可

ps.后来测试发现也需要从FilterDefs中删除,否则用servletContext.getFilterRegistration判断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
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
public static void dynamicRemoveFilter(String name,javax.servlet.http.HttpServletRequest request){
javax.servlet.ServletContext servletContext=request.getServletContext();
if (servletContext.getFilterRegistration(name) != null) {

try {
//因为门面模式的使用,此处servletContext实际是ApplicationContextFacade,需要提取ApplicationContext
java.lang.reflect.Field contextField=servletContext.getClass().getDeclaredField("context");
contextField.setAccessible(true);
org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(servletContext);
//获取ApplicationContext中的StandardContext
contextField=applicationContext.getClass().getDeclaredField("context");
contextField.setAccessible(true);
org.apache.catalina.core.StandardContext standardContext= (org.apache.catalina.core.StandardContext) contextField.get(applicationContext);
//获取FilterMaps
java.lang.reflect.Method findFilterMapsMethod = standardContext.getClass().getMethod("findFilterMaps");
findFilterMapsMethod.setAccessible(true);
Object[] FilterMaps = (Object[]) findFilterMapsMethod.invoke(standardContext);
//获取指定filtermap
//兼容tomcat7,8
Class ccc = null;
try {
ccc = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
} catch (Throwable t){}
if (ccc == null) {
try {
ccc = Class.forName("org.apache.catalina.deploy.FilterMap");
} catch (Throwable t){}
}
Object filtermap = null;
for (int i = 0; i < FilterMaps.length; i++) {
Object o = FilterMaps[i];
java.lang.reflect.Method getFilterNameMethod = ccc.getMethod("getFilterName");
getFilterNameMethod.setAccessible(true);
if(getFilterNameMethod.invoke(FilterMaps[i]).equals(name)){
filtermap = FilterMaps[i];
}
}
//删除filtermap
java.lang.reflect.Method removeFilterMapMethod = standardContext.getClass().getMethod("removeFilterMap",ccc);
removeFilterMapMethod.invoke(standardContext,ccc.cast(filtermap));

//也要从FilterDefs中删除,否则用servletContext.getFilterRegistration判断时还是会认为filter存在
java.lang.reflect.Method findFilterDefMethod = standardContext.getClass().getMethod("findFilterDef",String.class);
Object filterDef = findFilterDefMethod.invoke(standardContext,name);
Class ddd = null;
try {
ddd = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
} catch (Throwable t){}
if (ddd == null) {
try {
ddd = Class.forName("org.apache.catalina.deploy.FilterDef");
} catch (Throwable t){}
}
java.lang.reflect.Method removeFilterDefMethod = standardContext.getClass().getMethod("removeFilterDef",ddd);
removeFilterDefMethod.invoke(standardContext,filterDef);
}catch (Exception e){
;
}
}
}