Tomcat FIlter和Servlet内存马的扫描和查杀脚本

​ 之前发过两种内存马的原理,其实也都是利用反射进行动态注册,那么针对查杀也有一些方法,我这边是随便直接写了个jsp脚本,内部采用反编译技术并且结合了一些敏感的内存马特点进行相关恶意内存检测,这里我只是检测了getRuntime,exec( ,ProcessBuilder,ProcessImpl,shell等敏感的代码区域;还有一些文件落地情况,和classloader的情况等等;实际情况根据需要来,可以自己后期加上一些新的污点;

​ 需要利用的时候直接上传就可自动扫描,然后可以调用接口进行kill掉内存马;不多解释,相信理解两种内存马原理的师傅们应该都懂,不懂的话可以去追溯一波Tomcat源码;或者看我后面一篇文章;

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<%@ 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="java.util.HashMap" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="org.apache.catalina.startup.ContextConfig" %>
<%@ page import="org.xml.sax.InputSource" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.WebXml" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.WebXmlParser" %>
<%@ page import="java.util.Set" %>
<%@ page import="java.util.HashSet" %>
<%@ page import="org.apache.catalina.Container" %>
<%@ page import="org.apache.catalina.core.StandardWrapper" %>
<%@ page import="java.net.URL" %>
<%@ page import="com.sun.org.apache.bcel.internal.Repository" %>
<%@ page import="com.sun.org.apache.bcel.internal.classfile.JavaClass" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Scanner</title>
</head>
<body>
<%!
private boolean isshell;
%>
<%
String paths = request.getRequestURI();
request.setCharacterEncoding("GBK");
ServletContext servletContext = request.getServletContext();
Field context = servletContext.getClass().getDeclaredField("context");
context.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) context.get(servletContext);
Field standardcontext = applicationContext.getClass().getDeclaredField("context");
standardcontext.setAccessible(true);
StandardContext standardContext = (StandardContext) standardcontext.get(applicationContext);
FilterMap[] filterMaps = standardContext.findFilterMaps();
FilterDef[] filterDefs = standardContext.findFilterDefs();
PrintWriter printWriter = response.getWriter();
String remove = request.getParameter("removefilter");
if(remove!=null){
for(FilterDef filterDef:filterDefs){
if(filterDef.getFilterName().equals(remove)){
standardContext.removeFilterDef(filterDef);
}
}
for(FilterMap filterMap :filterMaps){
if(filterMap.getFilterName().equals(remove)){
standardContext.removeFilterMap(filterMap);
}
}
}
else {
HashMap hashMap = new HashMap();
printWriter.println("<h1>s1mple-Scanner</h1>");
Class contextConfigclass = ContextConfig.class;
Constructor constructor = contextConfigclass.getDeclaredConstructor();
ContextConfig contextConfig = (ContextConfig) constructor.newInstance();
Field contexts = contextConfigclass.getDeclaredField("context");
contexts.setAccessible(true);
contexts.set(contextConfig, standardContext);
Method getContextWebXmlSource = contextConfigclass.getDeclaredMethod("getContextWebXmlSource", (Class[]) null);
getContextWebXmlSource.setAccessible(true);
InputSource source = (InputSource) getContextWebXmlSource.invoke(contextConfig, (Object[]) null);
WebXmlParser webXmlParser = new WebXmlParser(standardContext.getXmlNamespaceAware(), standardContext.getXmlValidation(), standardContext.getXmlBlockExternal());
WebXml webXml = new WebXml();
Set<WebXml> defaults = new HashSet();
Method getDefaultWebXmlFragment = contextConfigclass.getDeclaredMethod("getDefaultWebXmlFragment", WebXmlParser.class);
getDefaultWebXmlFragment.setAccessible(true);
defaults.add((WebXml) getDefaultWebXmlFragment.invoke(contextConfig, webXmlParser));
boolean bol = webXmlParser.parseWebXml(source, webXml, false);
HashMap<String, FilterDef> Filter = (HashMap<String, FilterDef>) webXml.getFilters();
Set<String> real_filter = Filter.keySet();
for (FilterDef filterDef:filterDefs) {
String filtername = filterDef.getFilterName();
for (String real_Filter : real_filter) {
if (!filtername.equals(real_Filter) && !filtername.equals("Tomcat WebSocket (JSR356) Filter")) {
this.isshell = true;
}
}
if (this.isshell == true) {
String filterclass = filterDef.getFilterClass();
String path = filterclass.replace(".","/")+".class";
File file = new File(path);
if(!file.exists()) {
hashMap.put(filtername, "shell");
this.isshell = false;
}
}
}
printWriter.println("<h2>Filter---Result</h2>");
printWriter.println("shell--->");
printWriter.println(hashMap);
printWriter.println("<br>");
for(Object key: hashMap.keySet()){
printWriter.println(key);
printWriter.println("<a href = "+paths+"?removefilter="+key+">delete</a>");
printWriter.println("<br>");
}
}
Container[] Childrens = (Container[]) standardContext.findChildren();
printWriter.println("<h2>Servlet---Result</h2>");
HashMap hashMap1 = new HashMap();
for(Container wrapper : Childrens) {
String url_some = request.getParameter("removeServlet");
if (url_some != null) {
if(wrapper.getName().equals(url_some)) {
standardContext.removeChild(wrapper);
}
} else {
StandardWrapper standardWrapper = (StandardWrapper) wrapper;
Servlet servlet = standardWrapper.getServlet();
String servletname = standardWrapper.getServletName();
if (servlet != null) {
String servletclass = standardWrapper.getServletClass();
Class servletClass = servlet.getClass();
String servletpath = (servletclass.replace(".", "/") + ".class");
URL url = servlet.getClass().getClassLoader().getResource(servletpath);
Class classLoader = servletClass.getClassLoader().getClass();
String clastr = "org.apache.catalina.loader.WebappClassLoaderBase";
Class webappClassLoader = Class.forName(clastr);
//反编译内存中的class文件进行判断
JavaClass javaclass = Repository.lookupClass(servletClass);
File file = new File("/tmp/s1mple");
javaclass.dump(file);
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String content = bufferedReader.readLine();
String filecontent = null;
while (content != null) {
filecontent = filecontent + content;
content = bufferedReader.readLine();
}
if (filecontent.contains("getRuntime") || filecontent.contains("exec(") || filecontent.contains("ProcessBuilder") || filecontent.contains("ProcessImpl") || filecontent.contains("shell")) {
if (!webappClassLoader.isAssignableFrom(classLoader)) {
hashMap1.put(servletname, "isShell");

} else {
hashMap1.put(servletname, "maybeShell");
}
continue;
}
else{
String strclassloader = String.valueOf(classLoader);
if (strclassloader.contains("TemplatesImpl")) {
hashMap1.put(servletname, "very--maybeShell");
}
}
} else {
continue;
}
}
}
printWriter.println("shell--->");
printWriter.println(hashMap1);
printWriter.println("<br>");
for(Object key: hashMap1.keySet()){
printWriter.println(key);
printWriter.println("<a href = "+paths+"?removeServlet="+key+">delete</a>");
printWriter.println("<br>");

}
%>
</body>
</html>

效果如下图:默认启始页面:

LIXO9U.png

注入两个filter内存马和一个servlet内存马之后的扫描结果:

LIXX3F.png

直接点击后面delete直接删除:

LIXjc4.png