Skip to content
Merged

2.5.0 #134

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9329145
build: autoRelease and validateComponents
ReaJason Jan 12, 2026
844d2ae
feat: shellConfig support set isJakarta field
ReaJason Jan 12, 2026
79eba5e
feat: add jakarta-api deps
ReaJason Jan 12, 2026
752bf61
chore: 2.4.3-SNAPSHOT
ReaJason Jan 12, 2026
0baf561
refactor: optimize import
ReaJason Jan 12, 2026
6844c83
fix(ui): file input height error
ReaJason Jan 12, 2026
37aec27
refactor(ui): change serverVersion field localtion
ReaJason Jan 12, 2026
dedc7c8
feat(ui): add targetJdkVersion field
ReaJason Jan 12, 2026
bb071b8
refactor: change field location
ReaJason Jan 12, 2026
251b398
refactor: rename asserts to assets
ReaJason Jan 13, 2026
4331feb
feat: support Tomcat Command WebSocketBypassNginx
ReaJason Jan 13, 2026
da4502e
refactor: rename test case
ReaJason Jan 13, 2026
74dd440
docs: add websocket usage
ReaJason Jan 14, 2026
0d773ef
feat: add proxy ws
ReaJason Jan 14, 2026
b49da4e
docs: add some highlights
ReaJason Jan 14, 2026
6b5a837
refactor: change godzilla websocket base64 to raw
ReaJason Jan 16, 2026
c0a2e95
test: add filter
ReaJason Jan 16, 2026
918ae6f
feat: support ws proxy
ReaJason Jan 16, 2026
95ec3ed
test: skip proxy
ReaJason Jan 16, 2026
effe8e1
refactor: memshell integration-test
ReaJason Jan 17, 2026
7e13d3b
feat: add jsp unicode packer
ReaJason Jan 17, 2026
4747797
fix: weblogic upload jsp failed
ReaJason Jan 17, 2026
99a2a08
fix: NPE
ReaJason Jan 17, 2026
c70a2b3
test: probe not work
ReaJason Jan 17, 2026
13204c0
refactor: probe integration-test
ReaJason Jan 17, 2026
5dff8d7
test: jdk assert error
ReaJason Jan 17, 2026
e1a6de6
test: jetty6 start failed
ReaJason Jan 17, 2026
264827d
docs: update changelog
ReaJason Jan 17, 2026
a85e0a9
test: add empty component
ReaJason Jan 18, 2026
6c54abe
chore: upgrade deps
ReaJason Jan 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
rm -rf vul integration-test tools

# https://hub.docker.com/r/oven/bun
FROM --platform=$BUILDPLATFORM oven/bun:1.3.4 AS frontend
FROM --platform=$BUILDPLATFORM oven/bun:1.3.6 AS frontend

ARG ROUTE_ROOT_PATH="/"
ARG CONTEXT_PATH=""
Expand All @@ -25,7 +25,7 @@ COPY --from=source /usr/src/web /usr/src/web
RUN bun run build

# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.15_6-jdk-noble AS backend
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.15_10-jdk-noble AS backend

WORKDIR /usr/src

Expand All @@ -35,7 +35,7 @@ COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/res

RUN ./gradlew :boot:bootjar -x test

FROM eclipse-temurin:17.0.15_6-jre-noble
FROM eclipse-temurin:17.0.17_10-jre-noble

LABEL authors="ReaJason<reajason1225@gmail.com>"

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。

<p align="center">
<img src="asserts/normal_memshell.png" alt="normal_memshell" width="24%">
<img src="asserts/agent_memshell.png" alt="agent_memshell" width="24%">
<img src="asserts/dnslog_probe.png" alt="dnslog_probe" width="24%">
<img src="asserts/about_page.png" alt="about_page" width="24%">
<img src="assets/normal_memshell.png" alt="normal_memshell" width="24%">
<img src="assets/agent_memshell.png" alt="agent_memshell" width="24%">
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
<img src="assets/about_page.png" alt="about_page" width="24%">
</p>

## 主要特性
Expand Down
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion boot/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM eclipse-temurin:17.0.14_7-jre-noble
FROM eclipse-temurin:17.0.17_10-jre-noble

LABEL authors="ReaJason<reajason1225@gmail.com>"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public ShellToolConfig parseShellToolConfig() {
case Command -> CommandConfig.builder()
.shellClassName(shellToolConfig.getShellClassName())
.paramName(shellToolConfig.getCommandParamName())
.headerName(shellToolConfig.getHeaderName())
.headerValue(shellToolConfig.getHeaderValue())
.template(shellToolConfig.getCommandTemplate())
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
Expand All @@ -75,6 +77,10 @@ public ShellToolConfig parseShellToolConfig() {
.shellClassBase64(shellToolConfig.getShellClassBase64())
.shellClassName(shellToolConfig.getShellClassName())
.build();
case Proxy -> ProxyConfig.builder()
.headerName(shellToolConfig.getHeaderName())
.headerValue(shellToolConfig.getHeaderValue())
.shellClassName(shellToolConfig.shellClassName).build();
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.reajason.javaweb.boot.entity;

import lombok.Data;
import lombok.Builder;
import lombok.Data;

/**
* @author ReaJason
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author ReaJason
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

mavenPublishing {
publishToMavenCentral()
publishToMavenCentral(automaticRelease = true, validateDeployment = true)
signAllPublications()
coordinates(
"io.github.reajason",
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ idea {
}
}

version = "2.4.2"
version = "2.4.3-SNAPSHOT"

tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral")
Expand Down
4 changes: 2 additions & 2 deletions docs/README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ What you can learn or try from this project:
4. Try using [Byte Buddy](https://bytebuddy.net/) to generate classes and write Agents.
5. Try using Gradle to build Java projects (using platform for dependency version management, toolchain to compile JDK 6 source code even in a JDK 17 environment within the root project).

![normal_generator](../asserts/normal_generator.png)
![normal_generator](../assets/normal_generator.png)

![agent_generator](../asserts/agent_generator.png)
![agent_generator](../assets/agent_generator.png)

## Key Features

Expand Down
2 changes: 2 additions & 0 deletions generator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ dependencies {
api(libs.byte.buddy)
implementation(libs.asm.commons)
implementation(libs.javax.websocket.api)
implementation(libs.jakarta.websocket.client.api)
implementation(libs.javax.servlet.api)
implementation(libs.jakarta.servlet.api)
implementation(libs.spring.webmvc)
implementation(libs.spring.webflux)
implementation(libs.reactor.netty.core)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator;
import com.reajason.javaweb.memshell.server.AbstractServer;
import com.reajason.javaweb.probe.ProbeContent;
import com.reajason.javaweb.probe.ProbeMethod;
Expand Down Expand Up @@ -63,6 +64,11 @@ public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig in
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
injectorConfig.setShellClassBytes(shellBytes);

if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(shellConfig, shellToolConfig));
}

InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
import com.reajason.javaweb.memshell.shelltool.suo5.*;
import com.reajason.javaweb.memshell.shelltool.suo5v2.*;
import com.reajason.javaweb.memshell.shelltool.wsproxy.ProxyWebSocket;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -60,6 +61,8 @@ public class ServerFactory {
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
.addShellClass(WEBSOCKET, GodzillaWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, GodzillaWebSocket.class)
.addShellClass(BYPASS_NGINX_WEBSOCKET, GodzillaWebSocket.class)
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, GodzillaWebSocket.class)
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, GodzillaInterceptor.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
Expand Down Expand Up @@ -137,6 +140,8 @@ public class ServerFactory {
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
.addShellClass(WEBSOCKET, CommandWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
.addShellClass(BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
.addShellClass(UPGRADE, CommandUpgrade.class)
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
Expand Down Expand Up @@ -235,6 +240,13 @@ public class ServerFactory {
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
.addShellClass(ACTION, NeoreGeorgStruct2Action.class)
.build());

addToolMapping(ShellTool.Proxy, ToolMapping.builder()
.addShellClass(WEBSOCKET, ProxyWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, ProxyWebSocket.class)
.addShellClass(BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
.build());
}

public static void register(String serverName, Supplier<AbstractServer> shellSupplier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public class ShellTool {
public static final String Suo5v2 = "Suo5v2";
public static final String AntSword = "AntSword";
public static final String NeoreGeorg = "NeoreGeorg";
public static final String Proxy = "Proxy";
public static final String Custom = "Custom";
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class ShellToolFactory {
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class);
register(ShellTool.Proxy, ProxyGenerator.class, ProxyConfig.class);
}

public static void register(String shellToolName, Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ public class ShellType {
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction";
public static final String WEBSOCKET = "WebSocket";
public static final String BYPASS_NGINX_WEBSOCKET = "BypassNginx" + WEBSOCKET;
public static final String JAKARTA_WEBSOCKET = "JakartaWebSocket";
public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET;

public static final String ACTION = "Action";
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ public class CommandConfig extends ShellToolConfig {
@Builder.Default
private String paramName = CommonUtil.getRandomString(8);

/**
* 只有在 WebSocket Bypass 的时候才有用,防止对业务的干扰
*/
@Builder.Default
private String headerName = "User-Agent";

/**
* 只有在 WebSocket Bypass 的时候才有用,防止对业务的干扰
*/
@Builder.Default
private String headerValue = CommonUtil.getRandomString(8);

/**
* 加密器
*/
Expand All @@ -48,6 +60,22 @@ public B paramName(String paramName) {
}
return self();
}

public B headerName(final String headerName) {
if (StringUtils.isNotBlank(headerName)) {
this.headerName$value = headerName;
headerName$set = true;
}
return self();
}

public B headerValue(final String headerValue) {
if (StringUtils.isNotBlank(headerValue)) {
this.headerValue$value = headerValue;
headerValue$set = true;
}
return self();
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,38 @@
@AllArgsConstructor
@Builder(toBuilder = true)
public class InjectorConfig {
/**
* 注入器 Builder
*/
DynamicType.Builder<?> injectorBuilder;
/**
* 内存马 Builder
*/
DynamicType.Builder<?> shellBuilder;
/**
* 注入器模板类
*/
private Class<?> injectorClass;

/**
* 注入器类名
*/
@Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName();

/**
* 注入访问的地址
*/
@Builder.Default
private String urlPattern = "/*";

/**
* 内存马类名
*/
private String shellClassName;

/**
* 内存马类字节
*/
private byte[] shellClassBytes;

/**
* 辅助类字节码
*/
private byte[] helperClassBytes;

/**
* 添加静态代码块调用构造方法初始化
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.reajason.javaweb.memshell.config;

import com.reajason.javaweb.utils.CommonUtil;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.StringUtils;

@Getter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ProxyConfig extends ShellToolConfig {
@Builder.Default
private String headerName = "User-Agent";
@Builder.Default
private String headerValue = CommonUtil.getRandomString(8);

public static abstract class ProxyConfigBuilder<C extends ProxyConfig, B extends ProxyConfig.ProxyConfigBuilder<C, B>>
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {

public B headerName(final String headerName) {
if (StringUtils.isNotBlank(headerName)) {
this.headerName$value = headerName;
headerName$set = true;
}
return self();
}

public B headerValue(final String headerValue) {
if (StringUtils.isNotBlank(headerValue)) {
this.headerValue$value = headerValue;
headerValue$set = true;
}
return self();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,18 @@ public class ShellConfig {
@Builder.Default
private boolean lambdaSuffix = false;

/**
* 将 Java EE 转换为 Jakarta EE 类名
*/
@Builder.Default
private boolean jakarta = false;

public boolean isDebugOff() {
return !debug;
}

public boolean isJakarta() {
return shellType.startsWith(ShellType.JAKARTA);
return jakarta || shellType.startsWith(ShellType.JAKARTA);
}

public boolean needByPassJavaModule() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public DynamicType.Builder<?> getBuilder() {
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));

byte[] helperClassBytes = injectorConfig.getHelperClassBytes();
if (helperClassBytes != null) {
String helperBase64 = Base64.getEncoder().encodeToString(CommonUtil.gzipCompress(helperClassBytes));
builder = builder.method(named("getHelperBase64String")).intercept(FixedValue.value(helperBase64));
}

if (shellConfig.needByPassJavaModule()) {
builder = ByPassJavaModuleInterceptor.extend(builder);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.reajason.javaweb.memshell.generator;

import com.reajason.javaweb.memshell.config.ProxyConfig;
import com.reajason.javaweb.memshell.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;

public class ProxyGenerator extends ByteBuddyShellGenerator<ProxyConfig> {
public ProxyGenerator(ShellConfig shellConfig, ProxyConfig shellToolConfig) {
super(shellConfig, shellToolConfig);
}

@Override
protected DynamicType.Builder<?> getBuilder() {
return new ByteBuddy().redefine(shellToolConfig.getShellClass());
}
}
Loading