Skip to content

Commit 3de0700

Browse files
committed
feat: support servletNameFilter for UndertowFilterProbe
1 parent 1166036 commit 3de0700

9 files changed

Lines changed: 144 additions & 88 deletions

File tree

generator/src/main/java/com/reajason/javaweb/probe/payload/filter/UndertowFilterProbe.java

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,82 @@ public class UndertowFilterProbe {
1313

1414
@Override
1515
public String toString() {
16-
String msg = "";
16+
StringBuilder msg = new StringBuilder();
1717
Map<String, List<Map<String, String>>> allFiltersData = new LinkedHashMap<String, List<Map<String, String>>>();
1818
Set<Object> contexts = null;
1919
try {
2020
contexts = getContext();
2121
} catch (Throwable throwable) {
22-
msg += "context error: " + getErrorMessage(throwable);
22+
msg.append("context error: ").append(getErrorMessage(throwable));
2323
}
2424
if (contexts == null || contexts.isEmpty()) {
25-
msg += "context not found\n";
25+
msg.append("context not found\n");
2626
} else {
2727
for (Object context : contexts) {
2828
String contextRoot = getContextRoot(context);
29-
List<Map<String, String>> filters = collectFiltersData(context);
30-
allFiltersData.put(contextRoot, filters);
29+
try {
30+
List<Map<String, String>> filters = collectFiltersData(context);
31+
allFiltersData.put(contextRoot, filters);
32+
} catch (Throwable e) {
33+
msg.append(contextRoot).append(" failed ").append(getErrorMessage(e)).append("\n");
34+
}
3135
}
32-
msg += formatFiltersData(allFiltersData);
36+
msg.append(formatFiltersData(allFiltersData));
3337
}
34-
return msg;
38+
return msg.toString();
3539
}
3640

37-
private List<Map<String, String>> collectFiltersData(Object context) {
38-
List<Map<String, String>> result = new ArrayList<>();
39-
try {
40-
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
41-
if (deploymentInfo == null) return Collections.emptyList();
42-
43-
Map<String, Object> filters = (Map<String, Object>) getFieldValue(deploymentInfo, "filters");
44-
45-
if (filters == null || filters.isEmpty()) return Collections.emptyList();
46-
47-
List<Object> filterUrlMappings = (List<Object>) getFieldValue(deploymentInfo, "filterUrlMappings");
48-
// List<Object> filterServletNameMappings = (List<Object>) getFieldValue(deploymentInfo, "filterServletNameMappings");
49-
50-
for (Object filterUrlMapping : filterUrlMappings) {
51-
Map<String, String> info = new HashMap<>();
52-
String filterName = (String) getFieldValue(filterUrlMapping, "filterName");
53-
String urlPattern = (String) getFieldValue(filterUrlMapping, "mapping");
54-
Class<?> filterClass = (Class<?>) getFieldValue(filters.get(filterName), "filterClass");
41+
@SuppressWarnings("unchecked")
42+
private List<Map<String, String>> collectFiltersData(Object context) throws Exception {
43+
Map<String, Map<String, Object>> aggregatedData = new LinkedHashMap<>();
44+
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
45+
Map<String, Object> filters = (Map<String, Object>) getFieldValue(deploymentInfo, "filters");
46+
List<Object> filterUrlMappings = (List<Object>) getFieldValue(deploymentInfo, "filterUrlMappings");
47+
List<Object> filterServletNameMappings = (List<Object>) getFieldValue(deploymentInfo, "filterServletNameMappings");
48+
for (Object filterUrlMapping : filterUrlMappings) {
49+
String filterName = (String) getFieldValue(filterUrlMapping, "filterName");
50+
Class<?> filterClass = (Class<?>) getFieldValue(filters.get(filterName), "filterClass");
51+
if (aggregatedData.get(filterName) == null) {
52+
Map<String, Object> info = new HashMap<>();
5553
info.put("filterName", filterName);
56-
info.put("urlPatterns", urlPattern);
5754
info.put("filterClass", filterClass.getName());
58-
result.add(info);
55+
info.put("urlPatterns", new LinkedHashSet<String>());
56+
info.put("servletNames", new LinkedHashSet<String>());
57+
aggregatedData.put(filterName, info);
5958
}
60-
} catch (Exception ignored) {
59+
Map<String, Object> info = aggregatedData.get(filterName);
60+
String urlPattern = (String) getFieldValue(filterUrlMapping, "mapping");
61+
if (urlPattern != null) {
62+
((Set<String>) info.get("urlPatterns")).add(urlPattern);
63+
}
64+
}
65+
for (Object filterServletNameMapping : filterServletNameMappings) {
66+
String filterName = (String) getFieldValue(filterServletNameMapping, "filterName");
67+
Class<?> filterClass = (Class<?>) getFieldValue(filters.get(filterName), "filterClass");
68+
if (aggregatedData.get(filterName) == null) {
69+
Map<String, Object> info = new HashMap<>();
70+
info.put("filterName", filterName);
71+
info.put("filterClass", filterClass.getName());
72+
info.put("urlPatterns", new LinkedHashSet<String>());
73+
info.put("servletNames", new LinkedHashSet<String>());
74+
aggregatedData.put(filterName, info);
75+
}
76+
Map<String, Object> info = aggregatedData.get(filterName);
77+
String servletNames = (String) getFieldValue(filterServletNameMapping, "mapping");
78+
if (servletNames != null) {
79+
((Set<String>) info.get("servletNames")).add(servletNames);
80+
}
81+
}
82+
List<Map<String, String>> result = new ArrayList<>();
83+
for (Map<String, Object> entry : aggregatedData.values()) {
84+
Map<String, String> finalInfo = new HashMap<>();
85+
finalInfo.put("filterName", (String) entry.get("filterName"));
86+
finalInfo.put("filterClass", (String) entry.get("filterClass"));
87+
Set<?> urls = (Set<?>) entry.get("urlPatterns");
88+
finalInfo.put("urlPatterns", urls.isEmpty() ? "" : urls.toString());
89+
Set<?> servletNames = (Set<?>) entry.get("servletNames");
90+
finalInfo.put("servletNames", servletNames.isEmpty() ? "" : servletNames.toString());
91+
result.add(finalInfo);
6192
}
6293
return result;
6394
}
@@ -77,7 +108,8 @@ private String formatFiltersData(Map<String, List<Map<String, String>>> allFilte
77108
for (Map<String, String> info : filters) {
78109
appendIfPresent(output, "", info.get("filterName"), "");
79110
appendIfPresent(output, " -> ", info.get("filterClass"), "");
80-
appendIfPresent(output, " -> URL:[", info.get("urlPatterns"), "]");
111+
appendIfPresent(output, " -> URL:", info.get("urlPatterns"), "");
112+
appendIfPresent(output, " -> Servlet:", info.get("servletNames"), "");
81113
output.append("\n");
82114
}
83115
}

integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap6ContainerTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22

33
import com.reajason.javaweb.Server;
44
import com.reajason.javaweb.integration.ProbeAssertion;
5+
import com.reajason.javaweb.integration.ShellAssertion;
56
import com.reajason.javaweb.integration.VulTool;
67
import com.reajason.javaweb.integration.probe.DetectionTool;
8+
import com.reajason.javaweb.memshell.MemShellResult;
9+
import com.reajason.javaweb.memshell.ShellTool;
10+
import com.reajason.javaweb.memshell.ShellType;
11+
import com.reajason.javaweb.packer.Packers;
12+
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
713
import lombok.SneakyThrows;
814
import lombok.extern.slf4j.Slf4j;
915
import org.junit.jupiter.api.Test;
@@ -15,9 +21,11 @@
1521

1622
import java.nio.file.Files;
1723
import java.nio.file.Paths;
24+
import java.util.List;
1825

1926
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
2027
import static com.reajason.javaweb.integration.ContainerTool.warFile;
28+
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
2129
import static org.junit.jupiter.api.Assertions.assertEquals;
2230

2331
/**
@@ -69,4 +77,21 @@ void testBytecodeReqParamResponseBody() {
6977
String url = getUrl(container);
7078
ProbeAssertion.responseBytecodeIsOk(url, Server.JBoss, Opcodes.V1_6);
7179
}
80+
81+
@Test
82+
void testFilterProbe() {
83+
String url = getUrl(container);
84+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.JBoss));
85+
ShellAssertion.assertFilterProbeIsRight(data);
86+
}
87+
88+
@Test
89+
void testFilterFirstInject() {
90+
String url = getUrl(container);
91+
MemShellResult memShellResult = shellInjectIsOk(url, Server.JBoss, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
92+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Tomcat));
93+
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
94+
String filterName = ProbeAssertion.extractFilterName(filter.get(0));
95+
assertEquals(filterName, memShellResult.getShellClassName());
96+
}
7297
}

integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap7ContainerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.reajason.javaweb.Server;
44
import com.reajason.javaweb.integration.ProbeAssertion;
5+
import com.reajason.javaweb.integration.ShellAssertion;
56
import com.reajason.javaweb.integration.VulTool;
67
import com.reajason.javaweb.integration.probe.DetectionTool;
8+
import com.reajason.javaweb.memshell.MemShellResult;
79
import com.reajason.javaweb.memshell.ShellTool;
810
import com.reajason.javaweb.memshell.ShellType;
911
import com.reajason.javaweb.packer.Packers;
12+
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
1013
import lombok.SneakyThrows;
1114
import lombok.extern.slf4j.Slf4j;
1215
import org.junit.jupiter.api.AfterAll;
@@ -87,20 +90,17 @@ void testBytecodeReqParamResponseBody() {
8790
@Test
8891
void testFilterProbe() {
8992
String url = getUrl(container);
90-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
91-
System.out.println(data);
92-
assertThat(data, anyOf(
93-
containsString("Context: ")
94-
));
93+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
94+
ShellAssertion.assertFilterProbeIsRight(data);
9595
}
9696

9797
@Test
9898
void testFilterFirstInject() {
9999
String url = getUrl(container);
100-
shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
101-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
100+
MemShellResult memShellResult = shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
101+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
102102
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
103103
String filterName = ProbeAssertion.extractFilterName(filter.get(0));
104-
assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers")));
104+
assertEquals(filterName, memShellResult.getShellClassName());
105105
}
106106
}

integration-test/src/test/java/com/reajason/javaweb/integration/probe/jbosseap/JbossEap81ContainerTest.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.reajason.javaweb.Server;
44
import com.reajason.javaweb.integration.ProbeAssertion;
5+
import com.reajason.javaweb.integration.ShellAssertion;
56
import com.reajason.javaweb.integration.VulTool;
67
import com.reajason.javaweb.integration.probe.DetectionTool;
8+
import com.reajason.javaweb.memshell.MemShellResult;
79
import com.reajason.javaweb.memshell.ShellTool;
810
import com.reajason.javaweb.memshell.ShellType;
911
import com.reajason.javaweb.packer.Packers;
12+
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
1013
import lombok.SneakyThrows;
1114
import lombok.extern.slf4j.Slf4j;
1215
import org.junit.jupiter.api.Test;
@@ -20,10 +23,9 @@
2023
import java.nio.file.Paths;
2124
import java.util.List;
2225

23-
import static com.reajason.javaweb.integration.ContainerTool.*;
26+
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
27+
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
2428
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
25-
import static org.hamcrest.MatcherAssert.assertThat;
26-
import static org.hamcrest.Matchers.*;
2729
import static org.junit.jupiter.api.Assertions.assertEquals;
2830

2931
/**
@@ -80,20 +82,17 @@ void testBytecodeReqParamResponseBody() {
8082
@Test
8183
void testFilterProbe() {
8284
String url = getUrl(container);
83-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
84-
System.out.println(data);
85-
assertThat(data, anyOf(
86-
containsString("Context: ")
87-
));
85+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
86+
ShellAssertion.assertFilterProbeIsRight(data);
8887
}
8988

9089
@Test
9190
void testFilterFirstInject() {
9291
String url = getUrl(container);
93-
shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container);
94-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
92+
MemShellResult memShellResult = shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
93+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
9594
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
9695
String filterName = ProbeAssertion.extractFilterName(filter.get(0));
97-
assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers")));
96+
assertEquals(filterName, memShellResult.getShellClassName());
9897
}
9998
}

integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly18ContainerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.reajason.javaweb.Server;
44
import com.reajason.javaweb.integration.ProbeAssertion;
5+
import com.reajason.javaweb.integration.ShellAssertion;
56
import com.reajason.javaweb.integration.VulTool;
67
import com.reajason.javaweb.integration.probe.DetectionTool;
8+
import com.reajason.javaweb.memshell.MemShellResult;
79
import com.reajason.javaweb.memshell.ShellTool;
810
import com.reajason.javaweb.memshell.ShellType;
911
import com.reajason.javaweb.packer.Packers;
12+
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
1013
import lombok.SneakyThrows;
1114
import lombok.extern.slf4j.Slf4j;
1215
import org.junit.jupiter.api.Test;
@@ -80,20 +83,17 @@ void testBytecodeReqParamResponseBody() {
8083
@Test
8184
void testFilterProbe() {
8285
String url = getUrl(container);
83-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
84-
System.out.println(data);
85-
assertThat(data, anyOf(
86-
containsString("Context: ")
87-
));
86+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
87+
ShellAssertion.assertFilterProbeIsRight(data);
8888
}
8989

9090
@Test
9191
void testFilterFirstInject() {
9292
String url = getUrl(container);
93-
shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
94-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
93+
MemShellResult memShellResult = shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
94+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
9595
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
9696
String filterName = ProbeAssertion.extractFilterName(filter.get(0));
97-
assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers")));
97+
assertEquals(filterName, memShellResult.getShellClassName());
9898
}
9999
}

integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly23ContainerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.reajason.javaweb.Server;
44
import com.reajason.javaweb.integration.ProbeAssertion;
5+
import com.reajason.javaweb.integration.ShellAssertion;
56
import com.reajason.javaweb.integration.VulTool;
67
import com.reajason.javaweb.integration.probe.DetectionTool;
8+
import com.reajason.javaweb.memshell.MemShellResult;
79
import com.reajason.javaweb.memshell.ShellTool;
810
import com.reajason.javaweb.memshell.ShellType;
911
import com.reajason.javaweb.packer.Packers;
12+
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
1013
import lombok.SneakyThrows;
1114
import lombok.extern.slf4j.Slf4j;
1215
import org.junit.jupiter.api.Test;
@@ -80,20 +83,17 @@ void testBytecodeReqParamResponseBody() {
8083
@Test
8184
void testFilterProbe() {
8285
String url = getUrl(container);
83-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
84-
System.out.println(data);
85-
assertThat(data, anyOf(
86-
containsString("Context: ")
87-
));
86+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
87+
ShellAssertion.assertFilterProbeIsRight(data);
8888
}
8989

9090
@Test
9191
void testFilterFirstInject() {
9292
String url = getUrl(container);
93-
shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
94-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
93+
MemShellResult memShellResult = shellInjectIsOk(url, Server.Undertow, ShellType.FILTER, ShellTool.Command, Opcodes.V1_6, Packers.BigInteger, container);
94+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
9595
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
9696
String filterName = ProbeAssertion.extractFilterName(filter.get(0));
97-
assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers")));
97+
assertEquals(filterName, memShellResult.getShellClassName());
9898
}
9999
}

integration-test/src/test/java/com/reajason/javaweb/integration/probe/wildfly/Wildfly30ContainerTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.reajason.javaweb.Server;
44
import com.reajason.javaweb.integration.ProbeAssertion;
5+
import com.reajason.javaweb.integration.ShellAssertion;
56
import com.reajason.javaweb.integration.VulTool;
67
import com.reajason.javaweb.integration.probe.DetectionTool;
8+
import com.reajason.javaweb.memshell.MemShellResult;
79
import com.reajason.javaweb.memshell.ShellTool;
810
import com.reajason.javaweb.memshell.ShellType;
911
import com.reajason.javaweb.packer.Packers;
12+
import com.reajason.javaweb.probe.payload.FilterProbeFactory;
1013
import lombok.SneakyThrows;
1114
import lombok.extern.slf4j.Slf4j;
1215
import org.junit.jupiter.api.Test;
@@ -80,20 +83,17 @@ void testBytecodeReqParamResponseBody() {
8083
@Test
8184
void testFilterProbe() {
8285
String url = getUrl(container);
83-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
84-
System.out.println(data);
85-
assertThat(data, anyOf(
86-
containsString("Context: ")
87-
));
86+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
87+
ShellAssertion.assertFilterProbeIsRight(data);
8888
}
8989

9090
@Test
9191
void testFilterFirstInject() {
9292
String url = getUrl(container);
93-
shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container);
94-
String data = VulTool.post(url + "/b64", DetectionTool.getUndertowFilterProbe());
93+
MemShellResult memShellResult = shellInjectIsOk(url, Server.Undertow, ShellType.JAKARTA_FILTER, ShellTool.Command, Opcodes.V17, Packers.BigInteger, container);
94+
String data = VulTool.post(url + "/b64", FilterProbeFactory.getBase64ByServer(Server.Undertow));
9595
List<String> filter = ProbeAssertion.getFiltersForContext(data, "/app");
9696
String filterName = ProbeAssertion.extractFilterName(filter.get(0));
97-
assertThat(filterName, anyOf(startsWith("io.undertow.servlet.handlers")));
97+
assertEquals(filterName, memShellResult.getShellClassName());
9898
}
9999
}

0 commit comments

Comments
 (0)