diff --git a/web/bun.lockb b/web/bun.lockb index e8315880..1c0d17df 100755 Binary files a/web/bun.lockb and b/web/bun.lockb differ diff --git a/web/package.json b/web/package.json index f94a75ba..a72c06d1 100644 --- a/web/package.json +++ b/web/package.json @@ -13,16 +13,16 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@tanstack/router-plugin": "^1.105.0", + "@tanstack/router-plugin": "^1.106.0", "@types/node": "^22.13.4", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-syntax-highlighter": "^15.5.13", - "tailwindcss": "^4.0.6", + "tailwindcss": "^4.0.7", "typescript": "^5.7.3", - "vite": "^6.1.0" + "vite": "^6.1.1" }, "dependencies": { "@hookform/resolvers": "^4.1.0", @@ -37,10 +37,10 @@ "@radix-ui/react-switch": "^1.1.3", "@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.8", - "@tailwindcss/vite": "^4.0.6", + "@tailwindcss/vite": "^4.0.7", "@tanstack/react-query": "^5.66.7", - "@tanstack/react-router": "^1.105.0", - "@tanstack/router-devtools": "^1.105.0", + "@tanstack/react-router": "^1.106.0", + "@tanstack/router-devtools": "^1.106.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "i18next": "^24.2.2", @@ -51,8 +51,9 @@ "react-hook-form": "^7.54.2", "react-i18next": "^15.4.1", "react-syntax-highlighter": "^15.6.1", - "sonner": "^1.7.4", + "sonner": "^2.0.0", "tailwind-merge": "^3.0.1", + "tailwind-scrollbar": "^4.0.0", "tailwindcss-animate": "^1.0.7", "zod": "^3.24.2" }, diff --git a/web/src/components/code-viewer.tsx b/web/src/components/code-viewer.tsx index 77021aa3..2d4a94c7 100644 --- a/web/src/components/code-viewer.tsx +++ b/web/src/components/code-viewer.tsx @@ -1,7 +1,8 @@ import { Button, type ButtonProps } from "@/components/ui/button.tsx"; import { Check, Copy } from "lucide-react"; -import { type HTMLProps, type ReactNode, useEffect, useState } from "react"; +import { type HTMLProps, type ReactNode, useCallback, useEffect, useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; +import { useTranslation } from "react-i18next"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { materialDark } from "react-syntax-highlighter/dist/esm/styles/prism"; import { toast } from "sonner"; @@ -13,24 +14,33 @@ interface CopyButtonProps extends ButtonProps { export function CopyButton({ value }: CopyButtonProps) { const [hasCopied, setHasCopied] = useState(false); + const { t } = useTranslation(); useEffect(() => { if (hasCopied) { - setTimeout(() => { + const timer = setTimeout(() => { setHasCopied(false); }, 1000); + return () => clearTimeout(timer); } }, [hasCopied]); + const handleCopy = useCallback(() => { + if (!hasCopied) { + setHasCopied(true); + toast.success(t("copySuccess"), { duration: 1000 }); + } + }, [hasCopied, t]); + return ( - { - setHasCopied(true); - toast.success("复制成功", { duration: 1000 }); - }} - > - diff --git a/web/src/components/copyable-field.tsx b/web/src/components/copyable-field.tsx index 6b8ca075..e9afc8fa 100644 --- a/web/src/components/copyable-field.tsx +++ b/web/src/components/copyable-field.tsx @@ -1,8 +1,9 @@ import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Check, Copy } from "lucide-react"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; +import { useTranslation } from "react-i18next"; import { toast } from "sonner"; interface CopyableFieldProps { @@ -13,30 +14,39 @@ interface CopyableFieldProps { export function CopyableField({ label, value, text }: CopyableFieldProps) { const [hasCopied, setHasCopied] = useState(false); + const { t } = useTranslation(); - const copyToClipboard = useCallback(() => { - setHasCopied(true); - toast.success(`复制${label}成功`, { - duration: 1000, - }); - setTimeout(() => { - setHasCopied(false); - }, 1000); - }, [label]); + useEffect(() => { + if (hasCopied) { + const timer = setTimeout(() => { + setHasCopied(false); + }, 1000); + return () => clearTimeout(timer); + } + }, [hasCopied]); + + const handleCopy = useCallback(() => { + if (!hasCopied) { + setHasCopied(true); + toast.success(t("copyLabelSuccess", { label }), { + duration: 1000, + }); + } + }, [hasCopied, label, t]); return ( -
-
- -

{text}

+
+
+ + {value && ( + + + + )}
- {value && ( - - - - )} +

{text}

); } diff --git a/web/src/components/main-config-card.tsx b/web/src/components/main-config-card.tsx index f0dc881c..d126de34 100644 --- a/web/src/components/main-config-card.tsx +++ b/web/src/components/main-config-card.tsx @@ -10,9 +10,17 @@ import { MainConfig } from "@/types/shell.ts"; import { JreTip } from "@/components/tips/jre-tip.tsx"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; -import { cn } from "@/lib/utils.ts"; -import { ArrowUpRightIcon, ServerIcon } from "lucide-react"; -import { useState } from "react"; +import { + ArrowUpRightIcon, + AxeIcon, + CommandIcon, + NetworkIcon, + ServerIcon, + ShieldOffIcon, + SwordIcon, + WaypointsIcon, +} from "lucide-react"; +import { JSX, useState } from "react"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; @@ -25,6 +33,17 @@ const JDKVersion = [ { name: "Java21", value: "65" }, ]; +type ShellToolType = "Behinder" | "Godzilla" | "Command" | "AntSword" | "Suo5" | "Neo-reGeorg"; + +const shellToolIcons: Record = { + Behinder: , + Godzilla: , + Command: , + AntSword: , + Suo5: , + "Neo-reGeorg": , +}; + export function MainConfigCard({ mainConfig, form, @@ -101,6 +120,12 @@ export function MainConfigCard({ form.resetField("headerValue"); }; + const resetAntSword = () => { + form.resetField("antSwordPass"); + form.resetField("headerName"); + form.resetField("headerValue"); + }; + if (shellToolMap) { setShellTypes(shellToolMap[value]); form.resetField("urlPattern"); @@ -115,6 +140,8 @@ export function MainConfigCard({ resetCommand(); } else if (value === "Suo5") { resetSuo5(); + } else if (value === "AntSword") { + resetAntSword(); } } form.setValue("shellTool", value); @@ -130,7 +157,7 @@ export function MainConfigCard({ -
+
- 3 ? "grid-flow-col" : `grid-cols-${shellTools.length}`)} - > - {shellTools.map((shellTool) => ( - - {shellTool} - - ))} - +
+ + {shellTools.map((shellTool) => ( + + + {shellToolIcons[shellTool as ShellToolType]} + {shellTool} + + + ))} + +
+ diff --git a/web/src/components/package-config-card.tsx b/web/src/components/package-config-card.tsx index 6dff057d..447d1263 100644 --- a/web/src/components/package-config-card.tsx +++ b/web/src/components/package-config-card.tsx @@ -69,7 +69,11 @@ export function PackageConfigCard({ {t("packageConfig.title")} - + {options.map(({ name, value }) => ( diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index 41de3703..b0232629 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -28,21 +28,25 @@ import { Suo5ShellToolConfig, } from "@/types/shell.ts"; import { TFunction } from "i18next"; -import { CircleHelpIcon, TicketCheckIcon, TriangleAlertIcon } from "lucide-react"; +import { CircleHelpIcon, FileTextIcon, ScrollTextIcon, TriangleAlertIcon } from "lucide-react"; import { Fragment, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; function AgentResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { + const { t } = useTranslation(); return ( - 使用方法 + + + {t("generateResult.usage")} +
  1. - 下载 MemShellAgent.jar + {t("download")} MemShellAgent.jar
  2. - 下载 Jattach 工具(后期考虑直接封装在 Jar 中) + {t("tips.download-jattach")}
  3. -
  4. 将 MemShellAgent.jar 和 jattach 移动到容器中(如果测试环境使用容器部署)
  5. -
  6. 获取目标 jvm 的进程 pid (使用 jps 或 ps)
  7. -
  8. 执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar
  9. -
  10. 尝试利用内存马
  11. +
  12. {t("tips.move-to-container")}
  13. +
  14. {t("tips.get-pid")}
  15. +
  16. {t("tips.execute-command")}
  17. +
  18. {t("tips.try-to-use-shell")}
@@ -145,105 +149,119 @@ function BasicInfo({ generateResult }: { generateResult?: GenerateResult }) {
- + {t("generateResult.basicInfo")}
-
+
+ +
- - - {generateResult?.shellConfig.shellTool === "Behinder" && ( - - - - - - + + + {(generateResult?.shellConfig.shellTool === "Behinder" || + generateResult?.shellConfig.shellTool === "Godzilla" || + generateResult?.shellConfig.shellTool === "Command" || + generateResult?.shellConfig.shellTool === "AntSword" || + generateResult?.shellConfig.shellTool === "Suo5") && ( +
+ {/* Tool-specific fields */} + {generateResult?.shellConfig.shellTool === "Behinder" && ( + <> + + + + + + )} + {generateResult?.shellConfig.shellTool === "Godzilla" && ( + + + + + + + + )} + {generateResult?.shellConfig.shellTool === "Command" && ( + + + + )} + {generateResult?.shellConfig.shellTool === "Suo5" && ( + + + + )} + {generateResult?.shellConfig.shellTool === "AntSword" && ( + + + + + )} +
)} - {generateResult?.shellConfig.shellTool === "Godzilla" && ( - - - - - - - - )} - {generateResult?.shellConfig.shellTool === "Command" && ( - - - - )} - {generateResult?.shellConfig.shellTool === "Suo5" && ( - - - - )} - {generateResult?.shellConfig.shellTool === "AntSword" && ( - - - - - )} - - + +
+ + +
); diff --git a/web/src/i18n/en.json b/web/src/i18n/en.json index 35c62092..7e1f3020 100644 --- a/web/src/i18n/en.json +++ b/web/src/i18n/en.json @@ -1,115 +1,127 @@ { - "download": "Downlaod", - "feedback": "Feedback", - "cancel": "Cancel", - "placeholders": { - "select": "Please select", - "input": "Please input" - }, - "configs": { - "main-config": "Main Config", - "package-config": "Package Config" - }, - "optional": "(Optional)", - "mainConfig": { - "server": "Target Server", - "jre": "Target JRE Version", - "debug": "Debug Mode", - "bypassJavaModule": "Bypass Java Module", - "shellMountType": "Shell Mount Type", - "shellTool": "Shell Tool", - "urlPattern": "URL Pattern", - "shellClassName": "Shell ClassName", - "injectorClassName": "Injector ClassName" - }, - "shellToolConfig": { - "godzilla": "Godzilla", - "behinder": "Behinder", - "command": "Command", - "customHeader": "Custom Header", - "headerName": "Header Name", - "headerValue": "Header Value", - "pass": "Pass", - "key": "Key", - "godzillaHeader": "Request Config -> Request Header", - "godzillaPayload": "Payload", - "godzillaEncryptor": "Encryptor", - "behinderPass": "Pass", - "behinderScriptType": "Script Type", - "behinderEncryptType": "Encrypt Type", - "behinderDefaultEncryptType": "Default", - "paramName": "Param Name", - "suo5Header": "AdvanceConfiguration -> Request Header", - "antSwordPass": "Shell pwd", - "httpHeader": "HTTP -> HTTP HEADERS" - }, - "packageConfig": { - "title": "Package Method", - "packer": { - "Base64": "Base64", - "GzipBase64": "GzipBase64", - "BCEL": "BCEL", - "JSP": "JSP", - "Jar": "Jar", - "EL": "EL", - "SpEL": "SpEL", - "OGNL": "OGNL", - "MVEL": "MVEL", - "Freemarker": "Freemarker", - "Velocity": "Velocity", - "Groovy": "Groovy", - "AgentJar": "AgentJar", - "JavaDeserialize": "JavaDeserialize", - "ScriptEngine": "ScriptEngine", - "XxlJob": "XXL-JOB Executor", - "JinJava": "JinJava", - "Aviator": "Aviator", - "JXPath": "JXPath", - "JEXL": "JEXL", - "Rhino": "Rhino", - "BeanShell": "BeanShell" - } - }, - "tips": { - "shellToolNotSelected": "Please select a shell tool type first", - "targetServerNotFound": "Target server not found?", - "waitingForGeneration": "// Waiting for generation...", - "targetServerRequest": "Request", - "servletUrlPattern": "Servlet type requires a specific URL Pattern, e.g., /hello_servlet", - "controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller", - "handlerUrlPattern": "HandlerMethod/HandlerFunction type requires a specific URL Pattern, e.g., /hello_handler", - "jreTip": "Target JRE version, generally speaking, Java 6 is the default version for maximum compatibility, and Java high versions can load low version bytecode.", - "jreTip2": "In specific cases, such as JDK8 being able to use lambda expressions, and JDK9 and above having module restrictions, a specific version is required.", - "decompileTip": "Decompilation is still under development, so the current only sees the base64 encoding format", - "shellBytesEmpty": "Shell bytes is empty, please generate shell first" - }, - "quickUsage": { - "title": "Quick Usage", - "step1": "Select Target Server", - "step2": "Select Shell Tool, Godzilla, Behinder, etc.", - "step3": "Select Shell Mount Type, Filter, Listener, etc.", - "step4": "Select Packing Method", - "step5": "Click Generate Shell" - }, - "generateResult": { - "basicInfo": "Basic Info", - "usage": "Usage", - "title1": "Generate Result", - "title2": "Shell Class", - "title3": "Injector Class" - }, - "shellNotWork": { - "title": "Shell Not Work ?", - "step1": "1. Try to enable the debug mode, regenerate the memory shell and inject it, check the console or log", - "step2": "2. If an exception stack trace is displayed, or no exception is seen, please take a screenshot of the current generation interface and the exception log, and describe the target environment as much as possible for feedback" + "basicInfo": { + "classInfo": "ShellClass", + "serverInfo": "TargetServer", + "toolInfo": "ShellTool" }, "buttons": { "generate": "Generate Shell" }, + "cancel": "Cancel", + "configs": { + "main-config": "Main Config", + "package-config": "Package Config" + }, + "copyLabelSuccess": "Copy {{label}} successfully", + "copySuccess": "Copy successfully", + "download": "Downlaod", + "errors": { + "generationFailed": "Generation failed, {{error}}" + }, + "feedback": "Feedback", + "generateResult": { + "basicInfo": "Basic Info", + "title1": "Generate Result", + "title2": "Shell Class", + "title3": "Injector Class", + "usage": "Usage" + }, + "mainConfig": { + "bypassJavaModule": "Bypass Java Module", + "debug": "Debug Mode", + "injectorClassName": "Injector ClassName", + "jre": "Target JRE Version", + "server": "Target Server", + "shellClassName": "Shell ClassName", + "shellMountType": "Shell Mount Type", + "shellTool": "Shell Tool", + "urlPattern": "URL Pattern" + }, + "optional": "(Optional)", + "packageConfig": { + "packer": { + "AgentJar": "AgentJar", + "Aviator": "Aviator", + "BCEL": "BCEL", + "Base64": "Base64", + "BeanShell": "BeanShell", + "EL": "EL", + "Freemarker": "Freemarker", + "Groovy": "Groovy", + "GzipBase64": "GzipBase64", + "JEXL": "JEXL", + "JSP": "JSP", + "JXPath": "JXPath", + "Jar": "Jar", + "JavaDeserialize": "JavaDeserialize", + "JinJava": "JinJava", + "MVEL": "MVEL", + "OGNL": "OGNL", + "Rhino": "Rhino", + "ScriptEngine": "ScriptEngine", + "SpEL": "SpEL", + "Velocity": "Velocity", + "XxlJob": "XXL-JOB Executor" + }, + "title": "Package Method" + }, + "placeholders": { + "input": "Please input", + "select": "Please select" + }, + "quickUsage": { + "step1": "Select Target Server", + "step2": "Select Shell Tool, Godzilla, Behinder, etc.", + "step3": "Select Shell Mount Type, Filter, Listener, etc.", + "step4": "Select Packing Method", + "step5": "Click Generate Shell", + "title": "Quick Usage" + }, + "shellNotWork": { + "step1": "1. Try to enable the debug mode, regenerate the memory shell and inject it, check the console or log", + "step2": "2. If an exception stack trace is displayed, or no exception is seen, please take a screenshot of the current generation interface and the exception log, and describe the target environment as much as possible for feedback", + "title": "Shell Not Work ?" + }, + "shellToolConfig": { + "antSwordPass": "Shell pwd", + "behinder": "Behinder", + "behinderDefaultEncryptType": "Default", + "behinderEncryptType": "Encrypt Type", + "behinderPass": "Pass", + "behinderScriptType": "Script Type", + "command": "Command", + "customHeader": "Custom Header", + "godzilla": "Godzilla", + "godzillaEncryptor": "Encryptor", + "godzillaHeader": "Request Config -> Request Header", + "godzillaPayload": "Payload", + "headerName": "Header Name", + "headerValue": "Header Value", + "httpHeader": "HTTP -> HTTP HEADERS", + "key": "Key", + "paramName": "Param Name", + "pass": "Pass", + "suo5Header": "AdvanceConfiguration -> Request Header" + }, "success": { "generated": "Generation successful" }, - "errors": { - "generationFailed": "Generation failed, {{error}}" + "tips": { + "controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller", + "decompileTip": "Decompilation is still under development, so the current only sees the base64 encoding format", + "handlerUrlPattern": "HandlerMethod/HandlerFunction type requires a specific URL Pattern, e.g., /hello_handler", + "jreTip": "Target JRE version, generally speaking, Java 6 is the default version for maximum compatibility, and Java high versions can load low version bytecode.", + "jreTip2": "In specific cases, such as JDK8 being able to use lambda expressions, and JDK9 and above having module restrictions, a specific version is required.", + "servletUrlPattern": "Servlet type requires a specific URL Pattern, e.g., /hello_servlet", + "shellBytesEmpty": "Shell bytes is empty, please generate shell first", + "shellToolNotSelected": "Please select a shell tool type first", + "targetServerNotFound": "Target server not found?", + "targetServerRequest": "Request", + "waitingForGeneration": "// Waiting for generation...", + "download-jattach": "Download the Jattach tool (consider it directly encapsulated in Jar later)", + "move-to-container": "Move MemShellAgent.jar and jattach to the container (if the test environment uses a container deployment)", + "get-pid": "Get the process pid of the target jvm (use jps or ps)", + "execute-command": "Execute the command to inject: /path/to/jattach pid load instrument false /path/to/agent.jar", + "try-to-use-shell": "Try to use the memory shell" } } diff --git a/web/src/i18n/zh-CN.json b/web/src/i18n/zh-CN.json index 328df7e2..1e38c1cd 100644 --- a/web/src/i18n/zh-CN.json +++ b/web/src/i18n/zh-CN.json @@ -1,104 +1,127 @@ { - "download": "下载", - "feedback": "反馈", - "cancel": "取消", - "placeholders": { - "select": "请选择", - "input": "请输入" - }, - "configs": { - "main-config": "核心配置", - "package-config": "打包配置" - }, - "optional": "(可选)", - "mainConfig": { - "server": "目标服务", - "jre": "目标 JRE 版本", - "debug": "调试模式", - "bypassJavaModule": "绕过 Java 模块限制", - "shellMountType": "内存马挂载类型", - "shellTool": "内存马功能", - "urlPattern": "请求路径", - "shellClassName": "内存马类名", - "injectorClassName": "注入器类名" - }, - "shellToolConfig": { - "godzilla": "哥斯拉", - "behinder": "冰蝎", - "command": "命令回显", - "customHeader": "自定义请求头", - "headerName": "请求头键", - "headerValue": "请求头值", - "pass": "密码", - "key": "密钥", - "godzillaPayload": "有效载荷", - "godzillaEncryptor": "加密器", - "godzillaHeader": "请求配置 -> 请求头", - "behinderPass": "连接密码", - "behinderScriptType": "脚本类型", - "behinderEncryptType": "加密类型", - "behinderDefaultEncryptType": "默认", - "paramName": "请求参数", - "suo5Header": "高级配置 -> 请求头", - "antSwordPass": "连接密码", - "httpHeader": "请求信息 -> HTTP HEADERS" - }, - "packageConfig": { - "title": "打包方式", - "packer": { - "EL": "EL 表达式", - "SpEL": "SpEL 表达式", - "OGNL": "OGNL 表达式", - "MVEL": "MVEL 表达式", - "JEXL": "JEXL 表达式", - "BeanShell": "BeanShell 表达式", - "Aviator": "Aviator 表达式", - "JXPath": "JXPath 表达式", - "JavaDeserialize": "Java反序列化", - "ScriptEngine": "内置脚本引擎", - "Rhino": "Rhino 脚本引擎" - } - }, - "tips": { - "shellToolNotSelected": "请先选择内存马工具类型", - "targetServerNotFound": "找不到目标服务 ?", - "targetServerRequest": "请求适配", - "waitingForGeneration": "// 等待填写参数生成中...", - "servletUrlPattern": "Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet", - "controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller", - "handlerUrlPattern": "HandlerMethod/HandlerFunction 类型的需要填写具体的 URL Pattern,例如 /hello_handler", - "jreTip": "目标 JRE 版本,一般而言为了最大的兼容性,默认 Java 6 即可,Java 高版本能加载低版本的字节码。", - "jreTip2": "特定情况下,例如 JDK8 才能使用 lambda 表达式,JDK9 以上存在模块限制时才需要选择特定的版本。", - "decompileTip": "反编译还在开发中,因此当前仅能看到 base64 编码格式", - "shellBytesEmpty": "内存马字节码为空,无法下载, 请先生成内存马" - }, - "quickUsage": { - "title": "快速使用", - "step1": "选择目标服务", - "step2": "选择内存马功能,Godzilla、Behinder 或者其他", - "step3": "选择内存马挂载类型,Filter、Listener 或者其他", - "step4": "选择打包方式", - "step5": "点击生成内存马" - }, - "generateResult": { - "basicInfo": "基本信息", - "usage": "使用方法", - "title1": "生成结果", - "title2": "内存马类", - "title3": "注入器类" - }, - "shellNotWork": { - "title": "内存马利用失败 ?", - "step1": "1. 尝试开启调试模式,重新生成内存马并注入,查看控制台或日志", - "step2": "2. 如果出现异常堆栈信息,或未见异常,请截图当前生成界面以及异常日志,并尽可能描述目标环境进行反馈" + "basicInfo": { + "classInfo": "内存马类信息", + "serverInfo": "目标服务信息", + "toolInfo": "内存马工具信息" }, "buttons": { "generate": "生成内存马" }, + "cancel": "取消", + "configs": { + "main-config": "核心配置", + "package-config": "打包配置" + }, + "copyLabelSuccess": "复制 {{label}} 成功", + "copySuccess": "复制成功", + "download": "下载", + "errors": { + "generationFailed": "生成失败,{{error}}" + }, + "feedback": "反馈", + "generateResult": { + "basicInfo": "基本信息", + "title1": "生成结果", + "title2": "内存马类", + "title3": "注入器类", + "usage": "使用方法" + }, + "mainConfig": { + "bypassJavaModule": "绕过 Java 模块限制", + "debug": "调试模式", + "injectorClassName": "注入器类名", + "jre": "目标 JRE 版本", + "server": "目标服务", + "shellClassName": "内存马类名", + "shellMountType": "内存马挂载类型", + "shellTool": "内存马功能", + "urlPattern": "请求路径" + }, + "optional": "(可选)", + "packageConfig": { + "packer": { + "AgentJar": "AgentJar", + "Aviator": "Aviator 表达式", + "BCEL": "BCEL", + "Base64": "Base64", + "BeanShell": "BeanShell 表达式", + "EL": "EL 表达式", + "Freemarker": "Freemarker", + "Groovy": "Groovy", + "GzipBase64": "GzipBase64", + "JEXL": "JEXL 表达式", + "JSP": "JSP", + "JXPath": "JXPath 表达式", + "Jar": "Jar", + "JavaDeserialize": "Java反序列化", + "JinJava": "JinJava", + "MVEL": "MVEL 表达式", + "OGNL": "OGNL 表达式", + "Rhino": "Rhino 脚本引擎", + "ScriptEngine": "内置脚本引擎", + "SpEL": "SpEL 表达式", + "Velocity": "Velocity", + "XxlJob": "XXL-JOB Executor" + }, + "title": "打包方式" + }, + "placeholders": { + "input": "请输入", + "select": "请选择" + }, + "quickUsage": { + "step1": "选择目标服务", + "step2": "选择内存马功能,Godzilla、Behinder 或者其他", + "step3": "选择内存马挂载类型,Filter、Listener 或者其他", + "step4": "选择打包方式", + "step5": "点击生成内存马", + "title": "快速使用" + }, + "shellNotWork": { + "step1": "1. 尝试开启调试模式,重新生成内存马并注入,查看控制台或日志", + "step2": "2. 如果出现异常堆栈信息,或未见异常,请截图当前生成界面以及异常日志,并尽可能描述目标环境进行反馈", + "title": "内存马利用失败 ?" + }, + "shellToolConfig": { + "antSwordPass": "连接密码", + "behinder": "冰蝎", + "behinderDefaultEncryptType": "默认", + "behinderEncryptType": "加密类型", + "behinderPass": "连接密码", + "behinderScriptType": "脚本类型", + "command": "命令回显", + "customHeader": "自定义请求头", + "godzilla": "哥斯拉", + "godzillaEncryptor": "加密器", + "godzillaHeader": "请求配置 -> 请求头", + "godzillaPayload": "有效载荷", + "headerName": "请求头键", + "headerValue": "请求头值", + "httpHeader": "请求信息 -> HTTP HEADERS", + "key": "密钥", + "paramName": "请求参数", + "pass": "密码", + "suo5Header": "高级配置 -> 请求头" + }, "success": { "generated": "生成成功" }, - "errors": { - "generationFailed": "生成失败,{{error}}" + "tips": { + "controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller", + "decompileTip": "反编译还在开发中,因此当前仅能看到 base64 编码格式", + "handlerUrlPattern": "HandlerMethod/HandlerFunction 类型的需要填写具体的 URL Pattern,例如 /hello_handler", + "jreTip": "目标 JRE 版本,一般而言为了最大的兼容性,默认 Java 6 即可,Java 高版本能加载低版本的字节码。", + "jreTip2": "特定情况下,例如 JDK8 才能使用 lambda 表达式,JDK9 以上存在模块限制时才需要选择特定的版本。", + "servletUrlPattern": "Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet", + "shellBytesEmpty": "内存马字节码为空,无法下载, 请先生成内存马", + "shellToolNotSelected": "请先选择内存马工具类型", + "targetServerNotFound": "找不到目标服务 ?", + "targetServerRequest": "请求适配", + "waitingForGeneration": "// 等待填写参数生成中...", + "download-jattach": "下载 Jattach 工具(后期考虑直接封装在 Jar 中)", + "move-to-container": "将 MemShellAgent.jar 和 jattach 移动到容器中(如果测试环境使用容器部署)", + "get-pid": "获取目标 jvm 的进程 pid (使用 jps 或 ps)", + "execute-command": "执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar", + "try-to-use-shell": "尝试利用内存马" } } diff --git a/web/src/index.css b/web/src/index.css index a4b116f9..476b2f90 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -103,3 +103,39 @@ @apply bg-background text-foreground; } } + +.tabs-list-container { + @apply relative; + + /* Add fade effect for overflow indication */ + &::after { + content: ""; + @apply absolute right-0 top-0 h-full w-8 + bg-gradient-to-l from-background to-transparent + pointer-events-none + md:hidden; + } +} + +/* Custom scrollbar for tabs list */ +.tabs-list { + @apply pb-0.5 overflow-x-auto; + scrollbar-width: thin; +} + +.tabs-list::-webkit-scrollbar { + @apply h-1.5 w-1.5; +} + +.tabs-list::-webkit-scrollbar-track { + @apply bg-transparent; +} + +.tabs-list::-webkit-scrollbar-thumb { + @apply bg-muted-foreground/20 hover:bg-muted-foreground/30 rounded-full; +} + +/* Ensure tab triggers have consistent sizing */ +.tab-trigger { + @apply whitespace-nowrap text-sm; +} diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index 4dfcc1ba..63a5ca70 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -15,12 +15,12 @@ function RootComponent() {
-
+
-

MemShellParty - JavaWeb

+

MemShellParty - JavaWeb

-
+