diff options
Diffstat (limited to 'PLUGINS.md')
| -rw-r--r-- | PLUGINS.md | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/PLUGINS.md b/PLUGINS.md new file mode 100644 index 0000000..bb46461 --- /dev/null +++ b/PLUGINS.md @@ -0,0 +1,117 @@ +# mitmux plugins + +A plugin is any external process, in any language, that connects to +`mitmuxd`'s control socket and speaks the same JSON protocol the `mitmux` +TUI itself uses - there's no separate "plugin API," no interpreter +embedded in mitmuxd, and no in-process extension mechanism to trust. +This is deliberate: it keeps the daemon simple, lets a plugin be written +in whatever language actually suits the job (a JWT plugin doing crypto +work might want Python's `jwcrypto`; a fast passive scanner might want +Go), and means a plugin can be developed and tested against the exact +same socket the TUI is already using, with `mitmux` itself open in +another terminal watching what happens in real time. + +## Connecting + +The socket path is the same one `mitmux -socket` and `mitmuxd -socket` +use - `$XDG_RUNTIME_DIR/mitmux.sock` by default, else +`<config-dir>/mitmux.sock` (see the README's Platforms section for the +per-OS config directory). A plugin needs **two connections**, for two +different jobs: + +1. A **subscribe connection** - long-lived, one-way, the daemon pushes + newly-captured entries to it as they happen. Send one `{"type": + "subscribe"}` request, then just keep reading `Response` objects off + the connection; no more requests are ever sent on it. +2. A **request/response connection** - send one JSON request object, + read back exactly one JSON response object, repeat. This is how a + plugin looks up entries, resends requests, and tags things - anything + that isn't the live feed. + +Both are the same wire format: JSON values written directly to the +socket, no length prefix or newline delimiter required (Go's +`encoding/json` reads a stream and extracts one balanced JSON value at a +time; if your language's JSON library needs an explicit framing, treat +each object as ending where its braces balance - using a proper +streaming/incremental JSON parser, not naive line-splitting, is the +reliable way to consume this). + +## Requests a plugin actually needs + +The full protocol (`internal/ipc/ipc.go`'s `Request`/`Response` structs) +also covers everything the TUI itself does - search, export, rules, +scope, client certs, Intruder attacks, and so on. A plugin only needs a +handful of these: + +- **`subscribe`** - see above. No fields. Response stream: each object + has `"type": "new"` and a `"new"` field (a `store.Summary`) for one + freshly-captured entry. **Slow consumers silently drop entries** - the + daemon never blocks proxying to wait for a plugin to keep up. If your + plugin needs to guarantee it never misses one, don't rely on the live + feed alone; periodically reconcile against `list`/`search` too. +- **`get`** - `{"type": "get", "id": <entry id>}`. Returns the full + entry (raw request/response bytes, exact/truncated flags, existing + tags) as `"detail"`. +- **`repeat`** - `{"type": "repeat", "scheme": "https", "host": + "example.com", "raw": <base64 raw bytes>}`. Sends `raw` to + `scheme://host` exactly as given - no normalization, no header + injection, no auto-fixed `Content-Length` - and records the exchange + to history with `source: "repeater"`. This is what an Autorize- or + Param-Miner-style plugin uses to send its own probe requests. +- **`list`** / **`search`** - read existing history, same filters the + TUI's own `/` search uses (`status:`, `source:`, `flagged:`, `tag:`, + free text). Useful for a plugin that reconciles past traffic on + startup rather than only watching what happens from here on. +- **`tag_entry`** - the actual plugin-integration primitive: + + ```json + { + "type": "tag_entry", + "id": 42, + "tag_plugin": "jwt-decoder", + "tag": "jwt", + "tag_data": "{\"header\":{...},\"payload\":{...}}" + } + ``` + + `id` is the history entry being marked. `tag_plugin` is a + human-readable name your plugin picks for itself - purely + informational, not an identity or auth mechanism, since anything that + can reach the socket can claim any name (the socket itself is the + trust boundary - see Security below). `tag` is the short marker shown + as a badge in the TUI's history list and searchable via `tag:jwt`. + `tag_data` is an opaque string - conventionally JSON, since the TUI's + tag-detail view syntax-highlights it automatically if it parses as + JSON (same highlighter the pretty-printed response body view uses), + falling back to plain text otherwise - that a human reviewing the + entry later can open and read. Response: `{"type": "tag_entry", + "tag_id": <new tag's id>}`, or `{"type": "error", "error": "..."}`. + +A tagged entry shows its tags as a comma-joined badge in the TUI's +history table (a new `Tags` column) and sortable via `o`/`O` like any +other column; from the detail view, `T` opens the full tag list, `enter` +on one shows its data. + +## What's not here yet + +Everything above covers a plugin that **observes and marks** traffic - +enough for a JWT decoder, an authorization-bypass checker (replay with +a different session token, diff the response, tag it if it looks like +an IDOR), a hidden-parameter prober, or a known-vulnerable-JS-library +scanner. It does not yet cover a plugin **acting interactively** on +demand from the TUI - e.g. JWT Editor's "re-sign this token with a +different key, right now, from the panel" - which needs a live +round-trip to a specific still-connected plugin process, not just +stored data. That's a deliberately separate, second protocol addition, +not yet built; see `PLAN.md`'s plugin section for where it's headed. + +## Security + +The control socket has no authentication of its own beyond whatever the +OS's Unix domain socket file permissions grant - the same trust +boundary the `mitmux` TUI itself already operates inside. A plugin +connected to it has the same level of access the TUI has: it can read +every captured request and response (which may contain credentials, +session tokens, anything else that crossed the proxy), resend traffic, +and tag entries. Only run plugins you trust, the same way you'd only +run any other local tool with access to your intercepted traffic. |