Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions .github/workflows/dev-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ jobs:
run: bun install --frozen-lockfile && bun run build

- name: Build Boot with Gradle
run: ./gradlew -Pversion=dev :boot:bootjar -x test
run: ./gradlew :boot:bootjar -x test

- name: Upload Boot Jar
uses: actions/upload-artifact@v4
with:
name: boot
path: boot/build/libs/boot-dev.jar
path: boot/build/libs/*.jar

docker-push:
name: Docker Push
Expand Down Expand Up @@ -78,6 +78,30 @@ jobs:
push: true
tags: docker.io/reajason/memshell-party:dev

deploy-maven:
name: Deploy to Maven Central
needs: [ build-jar ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Publish with Gradle
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralUsername }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralPassword }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKey }}
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyId }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyPassword }}
run: ./gradlew publishAllToMavenCentral

deploy-northflank:
name: Deploy to Northflank
needs: [ docker-push ]
Expand Down
35 changes: 26 additions & 9 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ jobs:
build-jar:
name: Build Jar
runs-on: ubuntu-latest
needs: [ info ]
steps:
- uses: actions/checkout@v4

Expand All @@ -58,13 +57,13 @@ jobs:
run: bun install --frozen-lockfile && bun run build

- name: Build Boot with Gradle
run: ./gradlew -Pversion=${{ needs.info.outputs.version-without-v }} :boot:bootjar -x test
run: ./gradlew :boot:bootjar -x test

- name: Upload Boot Jar
uses: actions/upload-artifact@v4
with:
name: boot
path: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar
path: boot/build/libs/*.jar

docker-push:
name: Docker Push
Expand Down Expand Up @@ -110,6 +109,29 @@ jobs:
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
ghcr.io/reajason/memshell-party:latest

deploy-maven:
name: Deploy to Maven Central
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Publish with Gradle
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralUsername }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralPassword }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKey }}
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyId }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyPassword }}
run: ./gradlew publishAllToMavenCentral

create-release:
name: Create Release
needs: [ info, docker-push ]
Expand All @@ -125,18 +147,13 @@ jobs:
name: boot
path: boot/build/libs

- name: Calculate SHA-256
id: calculate_sha256
run: |
sha256sum boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar > boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.sha256

- name: Release
uses: ncipollo/release-action@v1
with:
name: ${{ needs.info.outputs.version }}
tag: ${{ needs.info.outputs.version }}
body: ${{ needs.info.outputs.changelog }}
artifacts: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar,boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.sha256
artifacts: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar

deploy-northflank:
name: Deploy to Northflank
Expand Down
24 changes: 21 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06

### Added

- 支持发布到 MavenCentral,可通过引入依赖使用生成 API by @ReaJason(#41)
- 支持 CC3、CC4 反序列化 payload 打包方式
- 支持随机参数生成与默认选项(#50)

### Changed

- 去除代码混淆相关代码
- 为了更好地在 MavenCentral 展示,重命名部分模块
- 使用 Jackson 代替 Fastjson 降低 boot 打包体积
- 移除 commons-codec 降低 boot 打包体积
- 升级 shadcn/ui 所有 component 代码

**Full Changelog:** [v1.6.0...v1.7.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)

## [v1.6.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.6.0) - 2025-03-30

> 做代码生成以及代码混淆真是一件需要耐心的事情

### Added

- 支持自定义内存马生成(#49)by @ReaJason
- 支持命令回显 ASM Agent 内存马(#51)by @ReaJason
- 支持简易的代码混淆(#13)by @ReaJason
- 支持自定义内存马生成 by @ReaJason(#49)
- 支持命令回显 ASM Agent 内存马 by @ReaJason(#51)
- 支持简易的代码混淆 by @ReaJason(#13)
- 支持自动发布 DEV 分支代码 CD

### Changed
Expand Down
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,97 @@ docker rm -f memshell-party
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
```

### SDK 集成到现有工具中

> 适合集成到已有工具中,实现内存马 payload 的生成,支持 JDK8 以上版本,v1.7.0 开始支持

1. 添加依赖,Maven Or Gradle

```xml
<!-- Maven Repo-->
<dependency>
<groupId>io.github.reajason</groupId>
<artifactId>generator</artifactId>
<version>1.7.0</version>
</dependency>
```

```groovy
// Gradle Repo
implementation 'io.github.reajason:generator:1.7.0'
```

2. 生成 Tomcat Godzilla Filter 内存马示例

```java
ShellConfig shellConfig = ShellConfig.builder()
.server(Server.Tomcat)
.shellTool(ShellTool.Godzilla)
.shellType(ShellType.FILTER)
.shrink(true) // 缩小字节码
.debug(false) // 关闭调试
.build();

InjectorConfig injectorConfig = InjectorConfig.builder()
// .urlPattern("/*") // 自定义 urlPattern,默认就是 /*
// .shellClassName("com.example.memshell.GodzillaShell") // 自定义内存马类名,默认为空时随机生成
// .injectorClassName("com.example.memshell.GodzillaInjector") // 自定义注入器类名,默认为空时随机生成
.build();

GodzillaConfig godzillaConfig = GodzillaConfig.builder()
// .pass("pass")
// .key("key")
// .headerName("User-Agent")
// .headerValue("test")
.build();

GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);

System.out.println("注入器类名:"+result.getInjectorClassName());
System.out.println("内存马类名:"+result.getShellClassName());

System.out.println(result.getShellConfig());
System.out.println(result.getShellToolConfig());

System.out.println("Base64 打包:"+Packers.Base64.getInstance().pack(result));
System.out.println("脚本引擎打包:"+Packers.ScriptEngine.getInstance().pack(result));
```
3. 生成 Tomcat Godzilla AgentFilterChain 示例
```java
ShellConfig shellConfig = ShellConfig.builder()
.server(Server.Tomcat)
.shellTool(ShellTool.Godzilla)
.shellType(ShellType.AGENT_FILTER_CHAIN)
.shrink(true) // 缩小字节码
.debug(false) // 关闭调试
.build();

InjectorConfig injectorConfig = InjectorConfig.builder()
// .urlPattern("/*") // 自定义 urlPattern,默认就是 /*
// .shellClassName("com.example.memshell.GodzillaShell") // 自定义内存马类名,默认为空时随机生成
// .injectorClassName("com.example.memshell.GodzillaInjector") // 自定义注入器类名,默认为空时随机生成
.build();

GodzillaConfig godzillaConfig = GodzillaConfig.builder()
// .pass("pass")
// .key("key")
// .headerName("User-Agent")
// .headerValue("test")
.build();

GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);

System.out.println("注入器类名:" + result.getInjectorClassName());
System.out.println("内存马类名:" + result.getShellClassName());

System.out.println(result.getShellConfig());
System.out.println(result.getShellToolConfig());

byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
Files.write(Paths.get("agent.jar"), agentJarBytes);
```
4. 封装统一生成接口可参考 [GeneratorController.java](boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java)

## 适配情况

已兼容 Java6 ~ Java8、Java9、Java11、Java17、Java21
Expand Down
1 change: 1 addition & 0 deletions boot/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
implementation 'org.apache.commons:commons-lang3:3.+'
implementation 'org.springframework.boot:spring-boot-starter-undertow'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package com.reajason.javaweb.boot.controller;

import com.reajason.javaweb.boot.entity.Config;
import com.reajason.javaweb.memshell.Packers;
import com.reajason.javaweb.memshell.Server;
import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.server.AbstractShell;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -20,8 +18,28 @@
@RequestMapping("/config")
@CrossOrigin("*")
public class ConfigController {

@RequestMapping("/servers")
public Map<String, List<String>> getServers() {
Map<String, List<String>> servers = new LinkedHashMap<>();
for (Server server : Server.values()) {
if (server.getShell() != null) {
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
servers.put(server.name(), supportedShellTypes.stream().toList());
}
}
return servers;
}

@RequestMapping("/packers")
public List<String> getPackers() {
return Arrays.stream(Packers.values())
.filter(packers -> packers.getParentPacker() == null)
.map(Packers::name).toList();
}

@RequestMapping
public ResponseEntity<?> config() {
public Map<String, Map<?, ?>> config() {
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
for (Server value : Server.values()) {
AbstractShell shell = value.getShell();
Expand All @@ -38,21 +56,6 @@ public ResponseEntity<?> config() {
}
coreMap.put(value.name(), map);
}
Config config = new Config();
Map<String, List<String>> servers = new LinkedHashMap<>();
for (Server server : Server.values()) {
if (server.getShell() != null) {
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
servers.put(server.name(), supportedShellTypes.stream().toList());
}
}
config.setServers(servers);
config.setCore(coreMap);
config.setPackers(
Arrays.stream(Packers.values())
.filter(packers -> packers.getParentPacker() == null)
.map(Packers::name).toList()
);
return ResponseEntity.ok(config);
return coreMap;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package com.reajason.javaweb.boot.controller;

import com.reajason.javaweb.memshell.MemShellGenerator;
import com.reajason.javaweb.boot.dto.GenerateRequest;
import com.reajason.javaweb.boot.dto.GenerateResponse;
import com.reajason.javaweb.memshell.MemShellGenerator;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.packer.AggregatePacker;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Base64;
Expand All @@ -24,18 +23,18 @@
@CrossOrigin("*")
public class GeneratorController {
@PostMapping
public ResponseEntity<?> generate(@RequestBody GenerateRequest request) {
public GenerateResponse generate(@RequestBody GenerateRequest request) {
ShellConfig shellConfig = request.getShellConfig();
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
InjectorConfig injectorConfig = request.getInjectorConfig();
GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
Packer packer = request.getPacker().getInstance();
if (packer instanceof JarPacker) {
return ResponseEntity.ok(new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult))));
return new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult)));
} else if (packer instanceof AggregatePacker) {
return ResponseEntity.ok(new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult)));
return new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult));
} else {
return ResponseEntity.ok(new GenerateResponse(generateResult, packer.pack(generateResult)));
return new GenerateResponse(generateResult, packer.pack(generateResult));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public VersionController(RestTemplate restTemplate) {

@GetMapping
public VersionInfo version() {
if ("dev".equals(version)) {
if (version.endsWith("-SNAPSHOT")) {
return VersionInfo.builder()
.currentVersion(version)
.latestVersion(version).build();
Expand Down
Loading
Loading