feat: support servletNameFilter for TomcatFilterProbe

This commit is contained in:
ReaJason
2026-01-12 02:12:34 +08:00
parent 86738e308d
commit 9d5c5a1ddf
35 changed files with 348 additions and 212 deletions
@@ -0,0 +1,52 @@
package com.reajason.javaweb.probe.payload;
import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.Server;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.probe.payload.filter.*;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.codec.binary.Base64;
/**
* @author ReaJason
* @since 2026/1/11
*/
public class FilterProbeFactory {
public static String getBase64ByServer(String server) {
try (DynamicType.Unloaded<?> unloaded = new ByteBuddy()
.redefine(getFilterClass(server))
.visit(TargetJreVersionVisitorWrapper.DEFAULT)
.name(CommonUtil.generateClassName()).make()) {
return Base64.encodeBase64String(unloaded.getBytes());
}
}
private static Class<?> getFilterClass(String server) {
switch (server) {
case Server.Tomcat:
case Server.JBoss:
case Server.BES:
case Server.TongWeb:
return TomcatFilterProbe.class;
case Server.Jetty:
return JettyFilterProbe.class;
case Server.Apusic:
return ApusicFilterProbe.class;
case Server.GlassFish:
case Server.InforSuite:
return GlassFishFilterProbe.class;
case Server.WebSphere:
return WebSphereFilterProbe.class;
case Server.WebLogic:
return WebLogicFilterProbe.class;
case Server.Undertow:
return UndertowFilterProbe.class;
default:
throw new GenerationException("filterProbe not supported for server: " + server);
}
}
}
@@ -13,77 +13,83 @@ public class TomcatFilterProbe {
@Override @Override
public String toString() { public String toString() {
String msg = ""; StringBuilder msg = new StringBuilder();
Map<String, List<Map<String, String>>> allFiltersData = new LinkedHashMap<String, List<Map<String, String>>>(); Map<String, List<Map<String, String>>> allFiltersData = new LinkedHashMap<String, List<Map<String, String>>>();
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg.append("context error: ").append(getErrorMessage(throwable));
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null || contexts.isEmpty()) {
msg += "context not found\n"; msg.append("context not found\n");
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
String contextRoot = getContextRoot(context); String contextRoot = getContextRoot(context);
List<Map<String, String>> filters = collectFiltersData(context); try {
allFiltersData.put(contextRoot, filters); List<Map<String, String>> filters = collectFiltersData(context);
allFiltersData.put(contextRoot, filters);
} catch (Throwable e) {
msg.append(contextRoot).append(" failed ").append(getErrorMessage(e)).append("\n");
}
} }
msg += formatFiltersData(allFiltersData); msg.append(formatFiltersData(allFiltersData));
} }
return msg; return msg.toString();
} }
private List<Map<String, String>> collectFiltersData(Object context) { @SuppressWarnings("unchecked")
private List<Map<String, String>> collectFiltersData(Object context) throws Exception {
Map<String, Map<String, Object>> aggregatedData = new LinkedHashMap<>(); Map<String, Map<String, Object>> aggregatedData = new LinkedHashMap<>();
try { Object[] filterMaps = (Object[]) invokeMethod(context, "findFilterMaps");
Object[] filterMaps = (Object[]) invokeMethod(context, "findFilterMaps"); if (filterMaps == null || filterMaps.length == 0) return Collections.emptyList();
if (filterMaps == null || filterMaps.length == 0) return Collections.emptyList();
Object[] filterDefs = (Object[]) invokeMethod(context, "findFilterDefs"); Object[] filterDefs = (Object[]) invokeMethod(context, "findFilterDefs");
for (Object fm : filterMaps) { for (Object fm : filterMaps) {
String name = (String) invokeMethod(fm, "getFilterName"); String name = (String) invokeMethod(fm, "getFilterName");
if (name == null) continue; if (name == null) continue;
if (!aggregatedData.containsKey(name)) { if (!aggregatedData.containsKey(name)) {
String filterClass = "N/A"; String filterClass = "N/A";
if (filterDefs != null) { if (filterDefs != null) {
for (Object def : filterDefs) { Object filterDef = invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{name});
if (!name.equals(invokeMethod(def, "getFilterName"))) continue; filterClass = (String) invokeMethod(filterDef, "getFilterClass");
String cls = (String) invokeMethod(def, "getFilterClass"); if (filterClass == null) {
if (cls == null) { Object filterConfig = invokeMethod(context, "findFilterConfig", new Class[]{String.class}, new Object[]{name});
Object config = invokeMethod(context, "findFilterConfig", new Class[]{String.class}, new Object[]{name}); Object filter = invokeMethod(filterConfig, "getFilter");
Object filter = config != null ? invokeMethod(config, "getFilter") : null; if (filter != null) filterClass = filter.getClass().getName();
if (filter != null) cls = filter.getClass().getName();
}
if (cls != null) filterClass = cls;
break;
}
}
Map<String, Object> info = new HashMap<>();
info.put("filterName", name);
info.put("filterClass", filterClass);
info.put("urlPatterns", new LinkedHashSet<String>());
info.put("servletNames", new LinkedHashSet<String>());
aggregatedData.put(name, info);
}
Map<String, Object> 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<String>) info.get("urlPatterns")).addAll(Arrays.asList(urls)); Map<String, Object> info = new HashMap<>();
info.put("filterName", name);
info.put("filterClass", filterClass);
info.put("urlPatterns", new LinkedHashSet<String>());
info.put("servletNames", new LinkedHashSet<String>());
aggregatedData.put(name, info);
} }
} catch (Exception ignored) {} Map<String, Object> info = aggregatedData.get(name);
String[] urls = null;
try {
urls = (String[]) invokeMethod(fm, "getURLPatterns");
} catch (Exception e) {
Object urlPattern = invokeMethod(fm, "getURLPattern");
if (urlPattern instanceof String) {
urls = new String[]{(String) urlPattern};
}
}
if (urls != null) ((Set<String>) info.get("urlPatterns")).addAll(Arrays.asList(urls));
String[] servletNames = null;
try {
servletNames = (String[]) invokeMethod(fm, "getServletNames");
} catch (Exception e) {
Object servletName = invokeMethod(fm, "getServletName");
if (servletName instanceof String) {
servletNames = new String[]{(String) servletName};
}
}
if (servletNames != null) ((Set<String>) info.get("servletNames")).addAll(Arrays.asList(servletNames));
}
List<Map<String, String>> result = new ArrayList<>(); List<Map<String, String>> result = new ArrayList<>();
for (Map<String, Object> entry : aggregatedData.values()) { for (Map<String, Object> entry : aggregatedData.values()) {
Map<String, String> finalInfo = new HashMap<>(); Map<String, String> finalInfo = new HashMap<>();
@@ -91,6 +97,8 @@ public class TomcatFilterProbe {
finalInfo.put("filterClass", (String) entry.get("filterClass")); finalInfo.put("filterClass", (String) entry.get("filterClass"));
Set<?> urls = (Set<?>) entry.get("urlPatterns"); Set<?> urls = (Set<?>) entry.get("urlPatterns");
finalInfo.put("urlPatterns", urls.isEmpty() ? "" : urls.toString()); finalInfo.put("urlPatterns", urls.isEmpty() ? "" : urls.toString());
Set<?> servletNames = (Set<?>) entry.get("servletNames");
finalInfo.put("servletNames", servletNames.isEmpty() ? "" : servletNames.toString());
result.add(finalInfo); result.add(finalInfo);
} }
return result; return result;
@@ -113,6 +121,7 @@ public class TomcatFilterProbe {
appendIfPresent(output, "", info.get("filterName"), ""); appendIfPresent(output, "", info.get("filterName"), "");
appendIfPresent(output, " -> ", info.get("filterClass"), ""); appendIfPresent(output, " -> ", info.get("filterClass"), "");
appendIfPresent(output, " -> URL:", info.get("urlPatterns"), ""); appendIfPresent(output, " -> URL:", info.get("urlPatterns"), "");
appendIfPresent(output, " -> Servlet:", info.get("servletNames"), "");
output.append("\n"); output.append("\n");
} }
} }
@@ -96,8 +96,9 @@ public class CommonUtil {
return className.substring(0, className.lastIndexOf(".")); return className.substring(0, className.lastIndexOf("."));
} }
public static String generateShellClassName() { public static String generateClassName() {
return getRandomPackageName() + ".ErrorHandler"; String randomString = getRandomString(5);
return getRandomPackageName() + ".Error" + randomString.substring(0, 1).toUpperCase() + randomString.substring(1).toLowerCase() + "Handler";
} }
public static String generateInjectorClassName() { public static String generateInjectorClassName() {
@@ -30,8 +30,8 @@ class CustomShellGeneratorTest {
void testListener() { void testListener() {
byte[] bytes = new ByteBuddy() byte[] bytes = new ByteBuddy()
.redefine(CommandListener.class) .redefine(CommandListener.class)
.name(CommonUtil.generateShellClassName()).make().getBytes(); .name(CommonUtil.generateClassName()).make().getBytes();
String className = CommonUtil.generateShellClassName(); String className = CommonUtil.generateClassName();
ShellConfig shellConfig = ShellConfig.builder() ShellConfig shellConfig = ShellConfig.builder()
.server(Server.Tomcat) .server(Server.Tomcat)
.shellType(ShellType.LISTENER) .shellType(ShellType.LISTENER)
@@ -52,8 +52,8 @@ class CustomShellGeneratorTest {
void testFilter() { void testFilter() {
byte[] bytes = new ByteBuddy() byte[] bytes = new ByteBuddy()
.subclass(Object.class) .subclass(Object.class)
.name(CommonUtil.generateShellClassName()).make().getBytes(); .name(CommonUtil.generateClassName()).make().getBytes();
String className = CommonUtil.generateShellClassName(); String className = CommonUtil.generateClassName();
ShellConfig shellConfig = ShellConfig.builder() ShellConfig shellConfig = ShellConfig.builder()
.shellType(ShellType.FILTER) .shellType(ShellType.FILTER)
.build(); .build();
@@ -72,8 +72,8 @@ class CustomShellGeneratorTest {
void testValue() { void testValue() {
byte[] bytes = new ByteBuddy() byte[] bytes = new ByteBuddy()
.redefine(GodzillaValve.class) .redefine(GodzillaValve.class)
.name(CommonUtil.generateShellClassName()).make().getBytes(); .name(CommonUtil.generateClassName()).make().getBytes();
String className = CommonUtil.generateShellClassName(); String className = CommonUtil.generateClassName();
ShellConfig shellConfig = ShellConfig.builder() ShellConfig shellConfig = ShellConfig.builder()
.server(Server.BES) .server(Server.BES)
.shellType(ShellType.VALVE) .shellType(ShellType.VALVE)
@@ -33,7 +33,7 @@ class GodzillaGeneratorTest {
.build(); .build();
GodzillaConfig godzillaConfig = GodzillaConfig.builder() GodzillaConfig godzillaConfig = GodzillaConfig.builder()
.shellClass(GodzillaServlet.class) .shellClass(GodzillaServlet.class)
.shellClassName(CommonUtil.generateShellClassName()) .shellClassName(CommonUtil.generateClassName())
.pass("pass") .pass("pass")
.key("key") .key("key")
.headerName("User-Agent") .headerName("User-Agent")
@@ -40,8 +40,7 @@ import java.util.Random;
import static com.reajason.javaweb.memshell.ShellTool.*; import static com.reajason.javaweb.memshell.ShellTool.*;
import static com.reajason.javaweb.utils.CommonUtil.INJECTOR_CLASS_NAMES; import static com.reajason.javaweb.utils.CommonUtil.INJECTOR_CLASS_NAMES;
import static com.reajason.javaweb.utils.CommonUtil.getRandomString; import static com.reajason.javaweb.utils.CommonUtil.getRandomString;
import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -53,13 +52,13 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@Slf4j @Slf4j
public class ShellAssertion { public class ShellAssertion {
public static void shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer) { public static MemShellResult shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer) {
shellInjectIsOk(url, server, shellType, shellTool, targetJdkVersion, packer, null); return shellInjectIsOk(url, server, shellType, shellTool, targetJdkVersion, packer, null);
} }
@SneakyThrows @SneakyThrows
public static void shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer<?> container) { public static MemShellResult shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer<?> container) {
shellInjectIsOk(url, server, shellType, shellTool, targetJdkVersion, packer, container, null); return shellInjectIsOk(url, server, shellType, shellTool, targetJdkVersion, packer, container, null);
} }
@SneakyThrows @SneakyThrows
@@ -85,12 +84,12 @@ public class ShellAssertion {
} }
@SneakyThrows @SneakyThrows
public static void shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) { public static MemShellResult shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
shellInjectIsOk(url, server, null, shellType, shellTool, targetJdkVersion, packer, appContainer, pythonContainer); return shellInjectIsOk(url, server, null, shellType, shellTool, targetJdkVersion, packer, appContainer, pythonContainer);
} }
@SneakyThrows @SneakyThrows
public static void shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool, public static MemShellResult shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool,
int targetJdkVersion, Packers packer, int targetJdkVersion, Packers packer,
GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) { GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
Pair<String, String> urls = getUrls(url, shellType, shellTool, packer); Pair<String, String> urls = getUrls(url, shellType, shellTool, packer);
@@ -104,6 +103,8 @@ public class ShellAssertion {
packerResultAndInject(generateResult, url, shellTool, shellType, packer, appContainer); packerResultAndInject(generateResult, url, shellTool, shellType, packer, appContainer);
assertShellIsOk(generateResult, shellUrl, shellTool, shellType, appContainer, pythonContainer); assertShellIsOk(generateResult, shellUrl, shellTool, shellType, appContainer, pythonContainer);
return generateResult;
} }
@SneakyThrows @SneakyThrows
@@ -492,4 +493,11 @@ public class ShellAssertion {
public static void testProbeInject(String url, String server, String shellType, int targetJdkVersion) { public static void testProbeInject(String url, String server, String shellType, int targetJdkVersion) {
testProbeInject(url, server, null, shellType, targetJdkVersion); testProbeInject(url, server, null, shellType, targetJdkVersion);
} }
public static void assertFilterProbeIsRight(String filterInfos) {
assertThat(filterInfos, allOf(
containsString("urlMappingTestFilter -> UrlMappingTestFilter -> URL:[/b64, /test]"),
containsString("servletNameTestFilter -> ServletNameTestFilter -> Servlet:[b64, biginteger]")
));
}
} }
@@ -18,7 +18,7 @@ public class DetectionTool {
public static String getBase64Class(Class<?> clazz) { public static String getBase64Class(Class<?> clazz) {
return Base64.encodeBase64String(new ByteBuddy() return Base64.encodeBase64String(new ByteBuddy()
.redefine(clazz) .redefine(clazz)
.name(CommonUtil.generateShellClassName()) .name(CommonUtil.generateClassName())
.visit(TargetJreVersionVisitorWrapper.DEFAULT) .visit(TargetJreVersionVisitorWrapper.DEFAULT)
.make().getBytes()); .make().getBytes());
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -83,20 +86,17 @@ public class Jboss423ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.JBoss));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.JBoss)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -81,20 +84,17 @@ public class Jboss510ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.JBoss));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.JBoss)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -81,20 +84,17 @@ public class Jboss610ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.JBoss));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.JBoss)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -81,20 +84,17 @@ public class Jboss711ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.JBoss));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.JBoss)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,12 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
@@ -25,8 +27,6 @@ import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.getUrl;
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; 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; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
@@ -95,20 +95,18 @@ public class Tomcat10ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V11, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V11, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
log.info(data);
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -82,20 +85,18 @@ public class Tomcat11ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.JAKARTA_FILTER, ShellTool.Command, org.objectweb.asm.Opcodes.V11, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
log.info(data);
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,12 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
@@ -24,8 +26,6 @@ import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.getUrl;
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; 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; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
@@ -83,20 +83,18 @@ public class Tomcat11JRE21ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.JAKARTA_FILTER, ShellTool.Command, org.objectweb.asm.Opcodes.V21, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V21, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
log.info(data);
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -26,7 +29,8 @@ import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.getUrl;
import static com.reajason.javaweb.integration.ContainerTool.warFile; import static com.reajason.javaweb.integration.ContainerTool.warFile;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk; import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -45,8 +49,8 @@ public class Tomcat5ContainerTest {
.withExposedPorts(8080); .withExposedPorts(8080);
@AfterAll @AfterAll
public static void stopContainer() { public static void tearDown() {
System.out.println(container.getLogs()); log.info(container.getLogs());
} }
// 存在首次请求,Tomcat 无法通过 req.getParameter 拿到参数的情况,因此需要重试 // 存在首次请求,Tomcat 无法通过 req.getParameter 拿到参数的情况,因此需要重试
@@ -96,20 +100,17 @@ public class Tomcat5ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -88,20 +91,17 @@ public class Tomcat6ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -90,20 +93,17 @@ public class Tomcat7ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -92,20 +95,17 @@ public class Tomcat8ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -2,11 +2,14 @@ package com.reajason.javaweb.integration.probe.tomcat;
import com.reajason.javaweb.Server; import com.reajason.javaweb.Server;
import com.reajason.javaweb.integration.ProbeAssertion; import com.reajason.javaweb.integration.ProbeAssertion;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.integration.VulTool; import com.reajason.javaweb.integration.VulTool;
import com.reajason.javaweb.integration.probe.DetectionTool; import com.reajason.javaweb.integration.probe.DetectionTool;
import com.reajason.javaweb.memshell.MemShellResult;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -82,20 +85,17 @@ public class Tomcat9ContainerTest {
@Test @Test
void testFilterProbe() { void testFilterProbe() {
String url = getUrl(container); String url = getUrl(container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
System.out.println(data); ShellAssertion.assertFilterProbeIsRight(data);
assertThat(data, anyOf(
containsString("Context: ")
));
} }
@Test @Test
void testFilterFirstInject() { void testFilterFirstInject() {
String url = getUrl(container); String url = getUrl(container);
shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container); MemShellResult memShellResult = shellInjectIsOk(url, Server.Tomcat, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe()); String data = VulTool.post(url + "/b64", DetectionTool.getTomcatFilterProbe());
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app"); List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
String filterName = ProbeAssertion.extractFilterName(filter.get(0)); String filterName = ProbeAssertion.extractFilterName(filter.get(0));
assertThat(filterName, anyOf(startsWith(CommonUtil.getWebPackageNameForServer(Server.Tomcat)))); assertEquals(filterName, memShellResult.getShellClassName());
} }
} }
@@ -7,7 +7,7 @@ import java.io.IOException;
* @since 2025/08/25 * @since 2025/08/25
*/ */
@WebServlet("/biginteger") @WebServlet("/biginteger")
public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet { public class BigIntegerClassLoaderServlet extends ClassLoader implements Servlet {
@Override @Override
public void init(ServletConfig config) throws ServletException { public void init(ServletConfig config) throws ServletException {
@@ -1,5 +1,3 @@
package jakarta;
import jakarta.servlet.*; import jakarta.servlet.*;
import java.io.IOException; import java.io.IOException;
@@ -1,5 +1,3 @@
package jakarta;
import jakarta.servlet.*; import jakarta.servlet.*;
import java.io.IOException; import java.io.IOException;
@@ -8,12 +6,12 @@ import java.io.IOException;
* @author Wans * @author Wans
* @since 2025/08/25 * @since 2025/08/25
*/ */
public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet { public class BigIntegerClassLoaderServlet extends ClassLoader implements Servlet {
public BigIntegerClassLaoderServlet() { public BigIntegerClassLoaderServlet() {
} }
protected BigIntegerClassLaoderServlet(ClassLoader parent) { protected BigIntegerClassLoaderServlet(ClassLoader parent) {
super(parent); super(parent);
} }
@@ -32,7 +30,7 @@ public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet
String data = req.getParameter("data"); String data = req.getParameter("data");
try { try {
byte[] bytes = decodeBigInteger(data); byte[] bytes = decodeBigInteger(data);
new BigIntegerClassLaoderServlet(Thread.currentThread().getContextClassLoader()).defineClass(null, bytes, 0, bytes.length).newInstance(); new BigIntegerClassLoaderServlet(Thread.currentThread().getContextClassLoader()).defineClass(null, bytes, 0, bytes.length).newInstance();
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -1,7 +1,4 @@
package jakarta;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@@ -1,5 +1,3 @@
package jakarta;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@@ -0,0 +1,24 @@
import jakarta.servlet.*;
import java.io.IOException;
/**
* @author ReaJason
* @since 2026/1/11
*/
public class ServletNameTestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
@@ -1,5 +1,3 @@
package jakarta;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@@ -1,5 +1,3 @@
package jakarta;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@@ -1,5 +1,3 @@
package jakarta;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@@ -1,8 +1,5 @@
package jakarta;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@@ -1,15 +1,22 @@
package jakarta;
import jakarta.servlet.*; import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException; import java.io.IOException;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/2/23 * @since 2025/1/3
*/ */
public class EmptyFilter implements Filter { public class UrlMappingTestFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response); chain.doFilter(request, response);
@@ -11,7 +11,7 @@
</welcome-file-list> </welcome-file-list>
<servlet> <servlet>
<servlet-name>test</servlet-name> <servlet-name>test</servlet-name>
<servlet-class>jakarta.TestServlet</servlet-class> <servlet-class>TestServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>test</servlet-name> <servlet-name>test</servlet-name>
@@ -20,7 +20,7 @@
<servlet> <servlet>
<servlet-name>upload</servlet-name> <servlet-name>upload</servlet-name>
<servlet-class>jakarta.UploadServlet</servlet-class> <servlet-class>UploadServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>upload</servlet-name> <servlet-name>upload</servlet-name>
@@ -29,7 +29,7 @@
<servlet> <servlet>
<servlet-name>java-deserialize</servlet-name> <servlet-name>java-deserialize</servlet-name>
<servlet-class>jakarta.JavaReadObjServlet</servlet-class> <servlet-class>JavaReadObjServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>java-deserialize</servlet-name> <servlet-name>java-deserialize</servlet-name>
@@ -38,7 +38,7 @@
<servlet> <servlet>
<servlet-name>b64</servlet-name> <servlet-name>b64</servlet-name>
<servlet-class>jakarta.Base64ClassLoaderServlet</servlet-class> <servlet-class>Base64ClassLoaderServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>b64</servlet-name> <servlet-name>b64</servlet-name>
@@ -47,7 +47,7 @@
<servlet> <servlet>
<servlet-name>biginteger</servlet-name> <servlet-name>biginteger</servlet-name>
<servlet-class>jakarta.BigIntegerClassLaoderServlet</servlet-class> <servlet-class>BigIntegerClassLoaderServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>biginteger</servlet-name> <servlet-name>biginteger</servlet-name>
@@ -56,7 +56,7 @@
<servlet> <servlet>
<servlet-name>js</servlet-name> <servlet-name>js</servlet-name>
<servlet-class>jakarta.ScriptEngineServlet</servlet-class> <servlet-class>ScriptEngineServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>js</servlet-name> <servlet-name>js</servlet-name>
@@ -65,7 +65,7 @@
<servlet> <servlet>
<servlet-name>reader</servlet-name> <servlet-name>reader</servlet-name>
<servlet-class>jakarta.TestReaderServlet</servlet-class> <servlet-class>TestReaderServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>reader</servlet-name> <servlet-name>reader</servlet-name>
@@ -74,7 +74,7 @@
<servlet> <servlet>
<servlet-name>inputStream</servlet-name> <servlet-name>inputStream</servlet-name>
<servlet-class>jakarta.TestInputStreamServlet</servlet-class> <servlet-class>TestInputStreamServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>inputStream</servlet-name> <servlet-name>inputStream</servlet-name>
@@ -82,11 +82,27 @@
</servlet-mapping> </servlet-mapping>
<filter> <filter>
<filter-name>empty</filter-name> <filter-name>urlMappingTestFilter</filter-name>
<filter-class>jakarta.EmptyFilter</filter-class> <filter-class>UrlMappingTestFilter</filter-class>
</filter>
<filter>
<filter-name>servletNameTestFilter</filter-name>
<filter-class>ServletNameTestFilter</filter-class>
</filter> </filter>
<filter-mapping> <filter-mapping>
<filter-name>empty</filter-name> <filter-name>urlMappingTestFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/b64</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>urlMappingTestFilter</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>servletNameTestFilter</filter-name>
<servlet-name>b64</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>servletNameTestFilter</filter-name>
<servlet-name>biginteger</servlet-name>
</filter-mapping> </filter-mapping>
</web-app> </web-app>
@@ -5,12 +5,12 @@ import java.io.IOException;
* @author Wans * @author Wans
* @since 2025/08/25 * @since 2025/08/25
*/ */
public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet { public class BigIntegerClassLoaderServlet extends ClassLoader implements Servlet {
public BigIntegerClassLaoderServlet() { public BigIntegerClassLoaderServlet() {
} }
protected BigIntegerClassLaoderServlet(ClassLoader parent) { protected BigIntegerClassLoaderServlet(ClassLoader parent) {
super(parent); super(parent);
} }
@@ -29,7 +29,7 @@ public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet
String data = req.getParameter("data"); String data = req.getParameter("data");
try { try {
byte[] bytes = decodeBigInteger(data); byte[] bytes = decodeBigInteger(data);
new BigIntegerClassLaoderServlet(Thread.currentThread().getContextClassLoader()).defineClass(null, bytes, 0, bytes.length).newInstance(); new BigIntegerClassLoaderServlet(Thread.currentThread().getContextClassLoader()).defineClass(null, bytes, 0, bytes.length).newInstance();
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -0,0 +1,23 @@
import javax.servlet.*;
import java.io.IOException;
/**
* @author ReaJason
* @since 2026/1/11
*/
public class ServletNameTestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
@@ -5,7 +5,7 @@ import java.io.IOException;
* @author ReaJason * @author ReaJason
* @since 2025/1/3 * @since 2025/1/3
*/ */
public class EmptyFilter implements Filter { public class UrlMappingTestFilter implements Filter {
@Override @Override
public void destroy() { public void destroy() {
+21 -5
View File
@@ -53,7 +53,7 @@
<servlet> <servlet>
<servlet-name>biginteger</servlet-name> <servlet-name>biginteger</servlet-name>
<servlet-class>BigIntegerClassLaoderServlet</servlet-class> <servlet-class>BigIntegerClassLoaderServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>biginteger</servlet-name> <servlet-name>biginteger</servlet-name>
@@ -79,11 +79,27 @@
</servlet-mapping> </servlet-mapping>
<filter> <filter>
<filter-name>godzilla</filter-name> <filter-name>urlMappingTestFilter</filter-name>
<filter-class>EmptyFilter</filter-class> <filter-class>UrlMappingTestFilter</filter-class>
</filter>
<filter>
<filter-name>servletNameTestFilter</filter-name>
<filter-class>ServletNameTestFilter</filter-class>
</filter> </filter>
<filter-mapping> <filter-mapping>
<filter-name>godzilla</filter-name> <filter-name>urlMappingTestFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/b64</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>urlMappingTestFilter</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>servletNameTestFilter</filter-name>
<servlet-name>b64</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>servletNameTestFilter</filter-name>
<servlet-name>biginteger</servlet-name>
</filter-mapping> </filter-mapping>
</web-app> </web-app>