feat: support springmvc shell generate

This commit is contained in:
ReaJason
2024-12-22 16:29:02 +08:00
parent 91181ffc55
commit 77e5371fa8
50 changed files with 1546 additions and 181 deletions
+7 -1
View File
@@ -52,7 +52,13 @@ idea {
}
test {
dependsOn ":vul:vul-webapp:war", ":vul:vul-webapp-expression:war", ":vul:vul-webapp-jakarta:war"
dependsOn {
":vul:vul-webapp:war"
":vul:vul-webapp-expression:war"
":vul:vul-webapp-jakarta:war"
":vul:vul-springboot2:bootJar"
":vul:vul-springboot3:bootJar"
}
useJUnitPlatform()
finalizedBy jacocoTestReport
}
@@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.MountableFile;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
@@ -15,7 +16,8 @@ public class ContainerTool {
public static final MountableFile warJakartaFile = MountableFile.forHostPath(Paths.get("../vul/vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war").toAbsolutePath());
public static final MountableFile warExpressionFile = MountableFile.forHostPath(Paths.get("../vul/vul-webapp-expression/build/libs/vul-webapp-expression.war").toAbsolutePath());
public static final MountableFile warFile = MountableFile.forHostPath(Paths.get("../vul/vul-webapp/build/libs/vul-webapp.war").toAbsolutePath());
public static final Path springBoot2Dockerfile = Paths.get("../vul/vul-springboot2/Dockerfile").toAbsolutePath();
public static final Path springBoot3Dockerfile = Paths.get("../vul/vul-springboot3/Dockerfile").toAbsolutePath();
public static String getUrl(GenericContainer<?> container) {
String host = container.getHost();
@@ -1,6 +1,7 @@
package com.reajason.javaweb.integration;
import com.reajason.javaweb.GeneratorMain;
import com.reajason.javaweb.memshell.SpringMVCShell;
import com.reajason.javaweb.memshell.config.*;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.extern.slf4j.Slf4j;
@@ -15,7 +16,7 @@ public class ShellAssertionTool {
String shellUrl = url + "/test";
InjectorConfig injectorConfig = new InjectorConfig();
if (shellType.endsWith(Constants.SERVLET)) {
if (shellType.endsWith(Constants.SERVLET) || shellType.endsWith(SpringMVCShell.CONTROLLER_HANDLER)) {
String urlPattern = "/" + shellTool + shellType + packer.name();
shellUrl = url + urlPattern;
injectorConfig.setUrlPattern(urlPattern);
@@ -56,7 +57,7 @@ public class ShellAssertionTool {
String behinderPass = "pass";
String behinderHeaderValue = "Behinder" + shellType + packer.name();
BehinderConfig behinderConfig = BehinderConfig.builder().pass(behinderPass).headerName("User-Agent").headerValue(behinderHeaderValue).build();
log.info("generated {} godzilla with pass: {}, headerValue: {}", shellType, behinderPass, behinderHeaderValue);
log.info("generated {} behinder with pass: {}, headerValue: {}", shellType, behinderPass, behinderHeaderValue);
String behinderContent = GeneratorMain.generate(shellConfig, injectorConfig, behinderConfig, packer);
assertInjectIsOk(url, shellType, shellTool, behinderContent, packer);
BehinderShellTool.testIsOk(shellUrl, behinderConfig);
@@ -64,6 +65,7 @@ public class ShellAssertionTool {
}
public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer) {
System.out.println(content);
switch (packer) {
case JSP -> {
String uploadEntry = url + "/upload";
@@ -79,6 +81,7 @@ public class ShellAssertionTool {
case Freemarker -> VulTool.postData(url + "/freemarker", content);
case Velocity -> VulTool.postData(url + "/velocity", content);
case Deserialize -> VulTool.postData(url + "/java_deserialize", content);
case Base64 -> VulTool.postData(url + "/b64", content);
}
}
}
@@ -50,7 +50,7 @@ public class VulTool {
.url(uploadUrl).post(requestBody)
.build();
try (Response response = new OkHttpClient().newCall(request).execute()) {
// log.info(response.body().string());
System.out.println(response.body().string());
Assertions.assertNotEquals(404, response.code());
}
}
@@ -0,0 +1,84 @@
package com.reajason.javaweb.integration.springmvc;
import com.reajason.javaweb.memshell.SpringMVCShell;
import com.reajason.javaweb.memshell.config.Server;
import com.reajason.javaweb.memshell.config.ShellTool;
import com.reajason.javaweb.memshell.packer.Packer;
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.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.springBoot2Dockerfile;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
/**
* @author ReaJason
* @since 2024/12/22
*/
@Testcontainers
@Slf4j
public class SpringBoot2ContainerTest {
public static final String imageName = "springboot2";
@Container
public final static GenericContainer<?> container = new GenericContainer<>(new ImageFromDockerfile()
.withDockerfile(springBoot2Dockerfile))
.waitingFor(Wait.forHttp("/test"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() {
return Stream.of(
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Behinder, Packer.INSTANCE.ScriptEngine),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Behinder, Packer.INSTANCE.SpEL),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Behinder, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Godzilla, Packer.INSTANCE.SpEL),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Godzilla, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Command, Packer.INSTANCE.ScriptEngine),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Command, Packer.INSTANCE.SpEL),
arguments(imageName, SpringMVCShell.INTERCEPTOR, ShellTool.Command, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Behinder, Packer.INSTANCE.ScriptEngine),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Behinder, Packer.INSTANCE.SpEL),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Behinder, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.SpEL),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Command, Packer.INSTANCE.ScriptEngine),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Command, Packer.INSTANCE.SpEL),
arguments(imageName, SpringMVCShell.CONTROLLER_HANDLER, ShellTool.Command, Packer.INSTANCE.Base64)
);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
testShellInjectAssertOk(getUrl(container), Server.SpringMVC, shellType, shellTool, Opcodes.V1_6, packer);
}
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;
}
}
@@ -0,0 +1,72 @@
package com.reajason.javaweb.integration.springmvc;
import com.reajason.javaweb.memshell.SpringMVCShell;
import com.reajason.javaweb.memshell.config.Server;
import com.reajason.javaweb.memshell.config.ShellTool;
import com.reajason.javaweb.memshell.packer.Packer;
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.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.springBoot3Dockerfile;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
/**
* @author ReaJason
* @since 2024/12/22
*/
@Testcontainers
@Slf4j
public class SpringBoot3ContainerTest {
public static final String imageName = "springboot3";
@Container
public final static GenericContainer<?> container = new GenericContainer<>(new ImageFromDockerfile()
.withDockerfile(springBoot3Dockerfile))
.waitingFor(Wait.forHttp("/test"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() {
return Stream.of(
arguments(imageName, SpringMVCShell.JAKARTA_INTERCEPTOR, ShellTool.Behinder, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.JAKARTA_INTERCEPTOR, ShellTool.Godzilla, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.JAKARTA_INTERCEPTOR, ShellTool.Command, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.JAKARTA_CONTROLLER_HANDLER, ShellTool.Behinder, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.JAKARTA_CONTROLLER_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
arguments(imageName, SpringMVCShell.JAKARTA_CONTROLLER_HANDLER, ShellTool.Command, Packer.INSTANCE.Base64)
);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
testShellInjectAssertOk(getUrl(container), Server.SpringMVC, shellType, shellTool, Opcodes.V17, packer);
}
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;
}
}