| Age | Commit message (Collapse) | Author | Files | Lines |
|
Generalizes Intrude beyond Sniper to all four of Burp's attack modes
(proxy.AttackMode). Sniper and Battering ram only ever need one shared
payload set; Pitchfork and Cluster bomb are inherently per-position, so
they take one payload set per §marked§ position instead.
Request-set generation (intrudeValues) is pure and side-effect free,
so the total request count is validated against the existing 1000
cap before anything is dispatched - Cluster bomb's product is checked
incrementally, one payload set at a time, so a pathological product
bails out before ever trying to enumerate it. This also makes the
combinatorics unit-testable without a live target.
IntrudeResultMsg now reports Values (one substitution per marked
position, in order) instead of a single Position/Payload pair, since
three of the four modes touch multiple positions per request.
TUI: `a` cycles the attack mode. Pitchfork/Cluster bomb reuse the
existing single Payloads pane rather than a new multi-widget editor -
sets are separated by a `---` delimiter line, in position order.
Verified live against a real daemon: all four modes produce the
expected substitution values and request counts, and pitchfork
correctly rejects a payload-set count that doesn't match the
template's marked positions.
|
|
internal/proxy/intrude.go's buildRequest substitutes marker text but
never recalculated Content-Length. A payload's length routinely differs
from the base value it replaces, so any body-parameter fuzzing attack
left a stale Content-Length from the original captured request in every
substituted request. When the declared length is larger than the actual
body sent, the target server blocks waiting for bytes that never
arrive, and each such request eats the full 60s upstreamTimeout before
failing - silently, with no error or warning anywhere. Since body-
parameter fuzzing is one of the most common Intruder use cases and
payload lengths vary within essentially every real attack, this made
most real body-fuzzing attacks take payloads×60s for no visible reason.
Found by a live audit that timed identical attacks: URL-only marker
fuzzing (no body length change) completed in single-digit milliseconds
per payload; the same attack with the marker in a body parameter took
60s per payload.
fixContentLength recalculates an existing Content-Length header to
match the actual body length after substitution, called right after
buildRequest in the Intrude loop. Deliberately narrow: only touches a
request with exactly one Content-Length header and a clean header/body
boundary. Zero found means nothing to fix (unchanged). More than one is
left alone too - a request smuggling test's own deliberately ambiguous
framing, where guessing which one to "fix" would be worse than leaving
both as the user built them.
This is Intruder-specific, not a change to Repeater: what the user
types into Repeater still goes on the wire completely unmodified, no
auto-fixed Content-Length there, same as always. A fuzzed value's
length is a side effect of automated substitution Intruder performs on
the user's behalf, not a deliberate edit the way a Repeater request is.
internal/proxy/intrude_test.go: TestFixContentLength covers recalculating
a stale length, case-insensitive header matching, no-header and
no-boundary no-ops, and the two-headers-left-alone case.
Verified live against a real HTTP target and a real daemon (JSON over
the control socket, not the TUI, for precise timing): a template with
Content-Length declared far larger than any actual substituted body -
the exact hang-triggering direction - completed all 4 payloads in 0.01s
total, and the recorded history entries carry exactly the correct
recalculated Content-Length for each (10/19/11/14, byte-for-byte
matching each actual body).
go build/vet/gofmt/test/mod tidy all clean.
|
|
Implements build-order step 7, the last (optional) item. Scoped to
Sniper only - one payload set, one §-marked position fuzzed at a time,
others held at their base value - since that covers most real Intruder
usage; battering ram / pitchfork / cluster bomb aren't implemented.
Sequential sending, capped at 1000 generated requests as a fixed safety
limit.
internal/proxy: repeat.go's Repeat() is refactored into a shared
sendRaw(..., source) primitive so Intrude can reuse the exact same
raw-byte send/record path with source="intruder" instead of
duplicating it. intrude.go adds ParseMarkers/buildRequest (marker
parsing and payload substitution, covered by intrude_test.go - this is
fiddly byte-splicing logic, worth locking down with real tests rather
than trusting it by inspection) and Intrude(), which walks positions ×
payloads calling sendRaw and streaming each result through a callback.
internal/ipc gains a dedicated streaming "intrude" connection (same
shape as Subscribe, but blocking sends rather than drop-on-slow-
consumer - each result is the attack's actual data, not a
notification). cmd/mitmux gains an Intruder view: editable request
template (ctrl+p inserts a § marker at the cursor - typing § directly
also works, ctrl+p just doesn't require a keyboard layout that can
produce it), editable payload list, and a live results table wired to
the existing detail view (selecting a row and hitting enter opens the
full request/response for that specific attack request).
Verified live against real external traffic: a Sniper attack against
httpbin.org/status/§200§ with payloads 200/404/500 produced exactly the
three corresponding real status codes back (not a canned/local result),
confirmed the three requests landed in history tagged source="intruder"
with the § markers correctly stripped from what was actually sent, and
confirmed opening a result row's full detail from the results table.
This closes out the full build order from PLAN.md (steps 1-7).
|