From cfe01fef65af082dccfc69b2fc78cb07a36ac2b4 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Wed, 26 Aug 2026 01:06:00 +0200 Subject: Second plugin: paramminer, a Param Miner-style hidden parameter prober For every distinct GET endpoint (deduplicated in-memory so revisiting a URL doesn't rerun the whole wordlist each time), sends a fresh baseline resend plus one probe per candidate from a ~40-entry wordlist of parameter names real backends surprisingly often read even when never part of any observed request (debug, admin, redirect, role, token, and similar). A probe whose response differs from baseline by more than a small threshold (body length, or a different status outright) is a likely hit, tagged paramminer:hit with the parameter name and both response sizes as evidence. Deliberately GET-only with a modest wordlist, not exhaustive POST/JSON-aware probing - same "small honest v1" reasoning as authcheck's single-identity simplification. Same discipline as authcheck: speaks the wire protocol directly, no internal/ipc import, proving PLUGINS.md's documented protocol is actually sufficient on its own. Found and documented two real, non-obvious net/http behaviors while building this: Request.Write ignores the RequestURI field entirely (confirmed directly - a deliberately stale RequestURI still produced the correct output, since Write derives the request line from Request.URL instead) and silently adds a default User-Agent header if the cloned request didn't already have one. Neither affects correctness here since baseline and every probe get identical treatment, but both are worth knowing before reusing this resend pattern elsewhere. Verified live end to end: a real daemon, a real Python origin with a genuinely hidden debug parameter that substantially changes the response, and a control endpoint that's stable regardless of any extra parameter - the hidden-parameter endpoint was correctly tagged with exactly the right parameter name, the stable one correctly left alone, confirmed via tag: search and visually in the TUI with the JSON-array tag payload rendering correctly. --- PLUGINS.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'PLUGINS.md') diff --git a/PLUGINS.md b/PLUGINS.md index 630f211..d6c0ee9 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -11,13 +11,16 @@ 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. -`plugins/authcheck` is a real, working reference implementation - an -Autorize-style authorization checker (resends a captured request with -its auth header stripped, tags the entry if the response still -succeeds) - written to only ever exercise what's documented on this -page, not any of mitmux's own internal Go packages, specifically so it -proves this protocol is sufficient on its own. Worth reading alongside -this document, or just copying as a starting point. +`plugins/authcheck` and `plugins/paramminer` are real, working +reference implementations - an Autorize-style authorization checker +(resends a captured request with its auth header stripped, tags the +entry if the response still succeeds) and a Param Miner-style hidden +parameter prober (probes a small wordlist of candidate query +parameters, tags the entry if any noticeably change the response) - +both written to only ever exercise what's documented on this page, not +any of mitmux's own internal Go packages, specifically so they prove +this protocol is sufficient on its own. Worth reading alongside this +document, or just copying as a starting point. ## Connecting @@ -65,7 +68,12 @@ handful of these: `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. + Param-Miner-style plugin uses to send its own probe requests. Every + probe becomes its own history row - a plugin sending many probes per + entry (Param Miner's wordlist, say) will visibly fill the history + view with them. That's intentional (every resend is auditable, same + as a human using Repeater by hand), and `source:proxy` in search + filters them back out when they're just noise. - **`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 -- cgit v1.2.3