srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
AgeCommit message (Collapse)AuthorFilesLines
2026-03-27Intruder payload processing and grep-match/grep-extractsrdusr1-1/+32
Payload processing: an optional case rule (upper/lower) and an optional encode rule (URL/Base64/Hex/HTML) applied to every payload line before it's substituted into the request, cycled with 'c'/'e'. Case always runs before encode - folding an already-encoded value would corrupt it (e.g. uppercasing Base64 padding). Applied entirely client-side in startIntrude() (payload_rules.go): a pure string transform with no proxy-side state, so it needs no protocol changes and reuses the Decoder's own urlEncodeAll. Grep-match/grep-extract: two optional Go regexps, edited with 'm'/'v' using the same modal edit-buffer pattern as the history list's '/' search (enter validates-and-commits, esc reverts to the last-confirmed pattern, an unparseable regexp is rejected with an error rather than silently accepted). Evaluated server-side, in internal/ipc/server.go's "intrude" handler, against each result's actual entry.ResponseRaw - that's where the real response bytes already are, and it's how Burp's own grep options work (matched against the real response, not a client-refetched copy). Grep-match flags a result (new Match column); grep-extract captures the first submatch, or the whole match if the pattern has no capturing group (new Extract column). Both patterns are compiled once before the attack starts and apply for that run only, not retroactively if changed mid-attack. All four new keys (c/e/m/v) are gated to normal mode, checked in the view's outer key switch before ever reaching the template/payloads vi-textareas - otherwise they'd be either untypeable letters or steal keystrokes mid-edit. Same discipline as the Repeater tab keys. internal/ipc: Request gained GrepMatch/GrepExtract string fields (for "intrude"), IntrudeResultMsg gained GrepMatch bool/GrepExtract string, and the client Intrude() helper takes the two pattern strings as new trailing parameters. Verified live in tmux against a running daemon and real httpbin.org traffic: built a template with a §marked§ query param, payloads 1/2/3, grep-match `"id": "2"` and grep-extract `"id": "([0-9]+)"`, ran the attack and confirmed the Match column flagged only the payload=2 row and Extract correctly pulled 1/2/3 from each response respectively; cycled case/encode through all states; confirmed an invalid regexp (`[abc`) is rejected with a visible error and esc correctly reverts to the last-confirmed pattern instead of committing the invalid one. (Also confirmed, incidentally: a batch of vi normal-mode two-key commands like "gg"/"dd" sent as one multi-character tmux send-keys argument doesn't reliably reach the app as separate keystrokes - a tmux scripting artifact, not a bug in the vi-mode implementation, which works correctly when each key is sent as its own event, as any real keypress would be.) go build/vet/gofmt/test/mod tidy all clean.
2026-03-18Multiple concurrent Repeater tabssrdusr1-1/+10
Repeater previously had one shared request/response buffer - sending a new entry to Repeater silently overwrote whatever was already open, even mid-edit. Replaced the singular reqArea/respView/repeaterScheme/ etc. model fields with a []*repeaterTab slice plus an active index; 'r' now opens a new tab and switches to it, existing tabs stay put. New keys, all gated to normal mode so they stay inert while typing (]/[ show up in JSON bodies constantly, and ctrl+w is the textarea's own delete-word-backward that must still work mid-edit): ] next tab [ previous tab ctrl+w close the active tab (falls back to a neighbor, or to the history list if it was the last one) Async send results now carry the tab index they belong to, so a slow send whose response lands after the user has switched tabs (or closed one) updates the right tab rather than whichever happens to be active when the result arrives; the status line and response pane only reflect it live if that tab is still the one being viewed. Verified live in tmux against a running daemon: opened two tabs from different history entries, confirmed independent buffers, sent from a background tab while another was active and confirmed the result routed to the correct (non-visible) tab, switched with ]/[, closed with ctrl+w down to zero tabs (falls back to the history list), and confirmed [, ], and ctrl+w are all correctly inert in insert mode (typed "[a]" literally, ctrl+w did textarea's word-delete instead of closing the tab). go build/vet/gofmt/test/mod tidy all clean.
2026-03-17Standalone Decoder: URL/Base64/Hex/HTML encode & decodesrdusr1-0/+13
First of the remaining "worth considering" items. A self-contained tool ('d' from the history list, not seeded from any entry - this is for arbitrary snippets, pasted tokens, encoded parameter values) with a vi-modal input pane and a live output pane that updates on every keystroke and every transform switch (tab/shift+tab cycles through the 8 transforms). decoder.go is pure logic, deliberately kept separate from the TUI wiring so it's directly testable: urlEncodeAll implements strict RFC 3986 percent-encoding (space -> %20) rather than using Go's url.QueryEscape, whose form-encoding behavior (space -> '+') isn't what "URL encode" means to a pentester reaching for this tool. Base64 decode tries standard/URL-safe/padded/unpadded encodings in turn rather than requiring the user to know which one they're looking at - real pasted data is as likely to be one as the other. Decode failures return a visible "(error: ...)" placeholder rather than blanking the output, so a bad guess at the transform is obviously wrong rather than looking like nothing happened. decoder_test.go covers each transform directly, three "this input isn't valid for this transform" error cases, and a round-trip matrix (all 4 encode/decode pairs against 5 inputs chosen to be awkward for at least one encoding - spaces, slashes, HTML-special characters, empty string, embedded newlines) confirming encode-then-decode always recovers the original. Single-transform only, not chained/pipelined like Burp's Decoder - v1 scope, tracked in PLAN.md. Verified live: typed text and watched the output pane update in real time; confirmed URL-encoding, then cycled to Base64 via tab and watched it re-encode the same input live; confirmed the active-transform highlighting via raw ANSI codes in the captured pane; fed invalid input to Base64 decode and confirmed the error placeholder renders instead of silently showing stale output; confirmed esc correctly backs out to the history list.
2026-02-24Comparer: unified diff between two history entriessrdusr1-3/+15
Next item off the "worth considering" list from the Burp/ZAP/Caido gap research. Mark an entry with 'c' (from the history list or detail view - no fetch yet, just remembers the ID), then 'c' on a different entry fetches both and opens a colored unified diff of either side's request or response, tab to switch between them. Unified (git-diff style: +/- prefixed lines) rather than Burp's side-by-side two-pane layout - a two-column view fights terminal width for anything but a wide window, and unified reuses the same scrollable viewport pattern already used everywhere else in this TUI rather than needing new layout machinery. Uses github.com/pmezard/go-difflib (SequenceMatcher-based, a tested port of Python's difflib) rather than hand-rolling LCS/Myers diff, which has real edge cases worth not reinventing. CRLF is normalized to LF before diffing - display-only, same reasoning as the JSON pretty-printer - so an HTTP/1.1 exact capture doesn't show every single line as changed purely from an invisible trailing \r. Verified live against two real, distinctly different captured POST requests (different form bodies, different Content-Length): the request diff correctly isolated exactly the two changed lines with the unchanged headers shown as context, colors confirmed via raw ANSI codes in the captured pane output (red 203 for removed, green 42 for added) rather than assumed from the code, and the response tab showed a correct independent diff of the two responses (Date header, JSON body). Also confirmed the "same entry marked twice" path shows a hint rather than silently doing something confusing.
2026-02-18Add READMEsrdusr1-0/+258
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.