srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2026-02-18 21:55:00 +0200
committersrdusr <[email protected]>2026-02-18 21:55:00 +0200
commit5200e412606c221fb618bd8e9a57a897553215d9 (patch)
treef3d118728f6986bad065cd82f290350cdcb6ab4a /README.md
parentb8e5d5ea37cc64ffa05352c3fb3130ca59471935 (diff)
downloadmitmux-5200e412606c221fb618bd8e9a57a897553215d9.tar.gz
mitmux-5200e412606c221fb618bd8e9a57a897553215d9.zip
Add README
the third explicit ask, alongside the Burp/ZAP/Caido gap pass and vi bindings: user-facing documentation. Covers what mitmux is and why it's two binaries (daemon owns the proxy and history, TUI is a thin client - restarting or crashing the UI never interrupts capture), install/build, a quick-start walkthrough (start daemon, trust the CA, point a client at it, open the TUI), per-feature usage (History, Repeater, Intruder, match-and-replace), the full search syntax (free text, host:/status:/source:/flagged: filters, AND/OR/NOT), the vi-modal command set for the Repeater/Intruder editors, an architecture section (daemon/TUI split, the raw-bytes-as-source-of-truth capture model and exact-vs-reconstructed distinction), package layout, dev commands, and an honest known-limitations list matching the scope decisions already tracked in PLAN.md rather than overselling anything. Verified rather than just written: built both binaries with the exact commands in the Install section, ran mitmuxd with no flags to confirm the documented defaults (127.0.0.1:8080, ~/.config/mitmux) are actually what ships, ran the exact curl command from Quick start against a real site through the proxy, and opened the TUI to confirm the captured request actually shows up - the full documented flow, end to end, not assumed correct because it reads correctly.
Diffstat (limited to 'README.md')
-rw-r--r--README.md258
1 files changed, 258 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..70375c7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,258 @@
+# mitmux
+
+A terminal-based intercepting proxy for manual pentest work - a
+daily-driver alternative to Burp Suite, Caido, or OWASP ZAP that runs
+entirely in your terminal, with vi-style modal editing for raw
+requests.
+
+mitmux is two binaries: `mitmuxd`, a headless daemon that owns the
+proxy listener and the SQLite history database, and `mitmux`, a Bubble
+Tea TUI that talks to it over a Unix socket. The daemon keeps running
+(and keeps capturing traffic) independently of the TUI - close the UI,
+reopen it later, the proxy never stopped.
+
+For the build history, the architectural decisions behind it, and a
+list of what's deliberately not implemented (and why), see
+[`PLAN.md`](PLAN.md).
+
+## Features
+
+- **Intercepting proxy**: plaintext HTTP passthrough and TLS
+ interception (per-host leaf certificates signed by a locally
+ generated CA), with HTTP/1.1 and HTTP/2 handled natively and
+ independently on the client and upstream legs - a client that only
+ speaks HTTP/1.1 and an origin that prefers HTTP/2 both work correctly
+ in the same request.
+- **History**: every request/response captured to SQLite. Raw wire
+ bytes are preserved byte-for-byte on HTTP/1.1 legs (what request
+ smuggling and parser-differential analysis actually needs); HTTP/2
+ legs - which have no single "raw bytes" representation, being
+ multiplexed HPACK-compressed framing - are reconstructed and marked
+ as such, never silently presented as exact.
+- **Search**: full-text search (FTS5) across headers and bodies, plain
+ text just works (`example.com`, `x-forwarded-for`, `192.168.1.1` -
+ no quoting needed), plus structured filters: `status:404`,
+ `status:4xx`, `status:>=400`, `source:repeater`, `flagged:true`,
+ column filters like `host:example.com`, and `AND`/`OR`/`NOT`.
+- **Repeater**: edit and resend a raw request. What you type is what
+ goes on the wire - no normalization, no auto-fixed `Content-Length`,
+ no "helpful" reformatting. That's the point of a Repeater.
+- **Intruder** (Sniper only): mark positions in a request template
+ with `§markers§`, supply a payload list, fuzz one position at a time
+ against a shared payload set. Results land in the same history table
+ as everything else, searchable the same way.
+- **Match-and-replace**: header rewrite rules (add, remove, or modify)
+ for requests and/or responses, applied live as traffic passes
+ through. History still shows what was actually sent/received on each
+ side - match-and-replace transforms the wire, it doesn't rewrite the
+ audit trail.
+- **Flagging**: mark an entry to revisit later (★), filterable via
+ `flagged:true`.
+- **Vi-modal editing**: the raw request editors (Repeater, Intruder)
+ are real modal editors - normal mode by default, `i`/`a`/`o`/etc. to
+ insert, `hjkl`, `dd`/`yy`/`p`, word motions, `gg`/`G`. See
+ [Vi bindings](#vi-bindings) below. Everywhere else (history table,
+ read-only response views), standard vi navigation (`j`/`k`, `g`/`G`,
+ `ctrl+u`/`ctrl+d`) already works - that's the underlying TUI
+ library's default, not something layered on top.
+
+## Install / build
+
+Requires Go 1.26.5+ (see `go.mod`).
+
+```sh
+git clone <this repo>
+cd mitmux
+go build -o bin/mitmuxd ./cmd/mitmuxd
+go build -o bin/mitmux ./cmd/mitmux
+```
+
+## Quick start
+
+1. **Start the daemon.** By default it listens on `127.0.0.1:8080` and
+ stores its CA and history database under `~/.config/mitmux` (XDG
+ config dir):
+
+ ```sh
+ ./bin/mitmuxd
+ ```
+
+ On first run it generates a root CA and prints where the cert
+ landed, e.g. `~/.config/mitmux/ca.pem`.
+
+2. **Trust the CA.** To intercept HTTPS without constant certificate
+ warnings, import `ca.pem` into whatever's making the requests -
+ your browser's certificate store, `curl --cacert`, a mobile device's
+ trusted-certificate settings, etc. (Automated per-OS trust-store
+ installation isn't implemented yet - see `PLAN.md`.)
+
+3. **Point a client at the proxy.** e.g.:
+
+ ```sh
+ curl -x http://127.0.0.1:8080 --cacert ~/.config/mitmux/ca.pem https://example.com/
+ ```
+
+ Or configure your browser's proxy settings to `127.0.0.1:8080`.
+
+4. **Open the TUI** (in another terminal - the daemon keeps running
+ independently):
+
+ ```sh
+ ./bin/mitmux
+ ```
+
+Both binaries take flags for non-default setups - `-listen`, `-socket`,
+`-ca-dir`, `-db` on `mitmuxd`; `-socket` on `mitmux`. Run either with
+`-h` for the full list.
+
+## Usage
+
+Press `?` from any screen in the TUI for the full, current keybinding
+reference - it's generated from the same source as this document, so
+it never drifts out of date the way a static list can. The summary
+below is enough to get going.
+
+### History (the default view)
+
+| Key | Action |
+|---|---|
+| `↑`/`↓` or `j`/`k` | navigate (also `g`/`G` top/bottom, `ctrl+u`/`ctrl+d` half-page) |
+| `enter` | view request/response detail |
+| `r` | open in Repeater |
+| `i` | open in Intruder |
+| `f` | toggle flag |
+| `/` | search |
+| `m` | match-and-replace rules |
+| `q` | quit |
+
+### Detail view
+
+`tab` switches request/response, `p` toggles pretty-printed JSON on the
+response (display-only - never touches the stored or resent bytes),
+`r`/`i` jump straight to Repeater/Intruder seeded from this entry, `esc`
+back.
+
+### Search syntax
+
+Plain text searches headers and bodies on both sides of the exchange.
+A handful of characters that are FTS5 syntax rather than literal text
+(`.`, `-`, `/`, `@`, and more) are handled transparently - you don't
+need to quote a domain name or an IP address for it to work.
+
+- `example.com`, `x-forwarded-for`, `192.168.1.1` - literal text, just works
+- `host:example.com`, `AND`, `OR`, `NOT` - FTS5 syntax for column
+ filters and boolean queries
+- `status:404` - exact status code
+- `status:4xx` (also `2xx`/`3xx`/`5xx`) - status range shorthand
+- `status:>=400`, `status:!=200` - status comparison operators
+- `source:proxy` / `source:repeater` / `source:intruder` - where the
+ request came from
+- `flagged:true` / `flagged:false`
+- Combine freely: `admin status:200 source:repeater`
+
+### Repeater / Intruder - vi bindings
+
+The request editors start in **normal mode**, not insert mode - like
+real vi. Press `i` (or `a`/`I`/`A`/`o`/`O`) to start typing, `esc` to
+go back to normal mode. The mode indicator (`-- NORMAL --` /
+`-- INSERT --`) is always visible while one of these editors is
+focused.
+
+| Normal-mode key | Action |
+|---|---|
+| `h` `j` `k` `l` | left / down / up / right |
+| `0` / `$` | line start / end |
+| `w` / `b` | word forward / back |
+| `x` | delete character |
+| `i` `a` `I` `A` | insert: before cursor / after cursor / line start / line end |
+| `o` / `O` | open a line below / above and insert |
+| `dd` / `yy` | delete / yank the current line |
+| `p` / `P` | paste below / above |
+| `dw` `d$` `d0` | delete word / to end of line / to start of line |
+| `gg` / `G` | top / bottom of the buffer |
+| `esc` | (in insert mode) back to normal mode - never leaves the view |
+
+This is a genuine, if intentionally scoped, modal editor: it translates
+these commands into the underlying text widget's own editing primitives
+rather than reimplementing cursor and line manipulation. Not
+implemented: registers beyond a single yank slot, visual mode, ex
+commands, macros, and counts (`3dd`, `5j`). There's no undo, because
+the underlying text widget doesn't have one either.
+
+`ctrl+r` sends (Repeater) or starts the attack (Intruder). `tab`
+switches panes. In Intruder's template pane specifically, `ctrl+g`
+inserts a `§` marker at the cursor if typing the character directly
+isn't convenient on your keyboard/terminal.
+
+### Match-and-replace rules
+
+Press `m` from the history view. Rules match request or response
+headers (`a` add, `enter`/`e` edit, `d` delete, `space` toggle
+enabled). Matching is literal-substring by default, or regex if the
+rule's Regex toggle is on. Rules operate on the raw header *block* as
+text, not per-value substitution, so a rule can add or remove a header
+entirely, not just rewrite an existing one. Currently headers only -
+see `PLAN.md` for why body rules are a separate, harder problem.
+
+## Architecture
+
+`mitmuxd` owns the proxy listener and the SQLite database; `mitmux` is
+a thin client that only ever talks to the daemon over a Unix socket
+(`internal/ipc`). This split is deliberate: a web UI, a CLI scanner, or
+any other client could be bolted on later without touching the proxy
+engine, and the TUI restarting (or crashing) never interrupts capture.
+
+Capture fidelity is the other core design constraint: for HTTP/1.1
+traffic, request and response bytes stored in history are exactly what
+was read off the wire - captured via a `net.Conn` wrapper that records
+bytes as `net/http`'s own (memory-safe, battle-tested) parser consumes
+them, rather than re-serializing a parsed representation. For HTTP/2,
+which has no meaningful single "raw bytes" form, the stored
+representation is a reconstruction, and every stored entry says which
+kind it is (`request_exact`/`response_exact` in the database, "exact"
+vs. "reconstructed" in the UI). Repeater and Intruder both write raw
+bytes straight to the wire for the same reason - the whole point of a
+Repeater is that a deliberately malformed request reaches the target
+unmodified.
+
+Package layout:
+
+```
+cmd/mitmuxd/ daemon entrypoint
+cmd/mitmux/ TUI entrypoint
+internal/ca/ root CA + per-host leaf certificate generation
+internal/proxy/ proxy engine: HTTP/CONNECT handling, capture, Repeater, Intruder
+internal/rules/ match-and-replace engine
+internal/store/ SQLite storage, FTS5 search
+internal/ipc/ daemon <-> client protocol (JSON over a Unix socket)
+```
+
+## Development
+
+```sh
+go build ./...
+go vet ./...
+gofmt -l . # should print nothing
+go test ./...
+```
+
+There's no mock traffic layer - the test suite covers pure logic
+(marker parsing, search-query parsing) that's worth locking down with
+real tests rather than trusting by inspection. Everything that touches
+the network, the daemon, or the TUI has been verified by actually
+running it against real traffic during development; see commit
+messages for what was checked and how.
+
+## Known limitations
+
+Deliberate scope decisions, not oversights - see `PLAN.md` for the
+reasoning behind each:
+
+- Match-and-replace: headers only, no body rules yet
+- Intruder: Sniper attack only (no battering ram / pitchfork / cluster
+ bomb), sequential sending, capped at 1000 requests per attack
+- No automated CA installation into OS/browser trust stores
+- No WebSocket interception
+- No client (mutual-TLS) certificate support
+- No active or passive vulnerability scanning, no plugin system - this
+ is a manual-testing tool, not a scanner