burp suite is the default for almost everything in a web pentest, and the community edition is what i reach for first. but there's one specific case where i keep coming back to OWASP ZAP: brute-forcing a login form that rotates an anti-csrf token on every request.
this is the form that taught me the difference.
the setup
the endpoint was ba_pwd_attacks_2.php on bwapp at medium difficulty. a standard username + password form, with one twist: a hidden input named salt regenerated on every page load. submitting the form with a stale or missing token produced an "Invalid salt!" error before the credentials were even checked.
that's the textbook anti-csrf pattern, and it does its job — burp intruder's basic configuration sends each payload with the same captured token, which means request two onward all fail token validation.
what intruder needs to handle it
burp intruder can handle rotating tokens, but it takes a custom macro or extension to do it cleanly in the community edition. the flow is: a pre-request macro fetches the form page, extracts the new token, and substitutes it into the attack request. it's doable but fiddly, and the macro configuration is one of the parts of burp where the UX shows its age.
what zap does out of the box
zap's fuzzer has a feature called anti-csrf token that does exactly this without configuration gymnastics:
- in options → anti-csrf tokens, register the token name —
salt. - in the fuzzer dialog, enable the anti-csrf token handler.
- set thread count to 1 with a small delay between requests, so the token-fetch and the attack-submit stay in lockstep.
for each fuzz iteration, zap fetches the form page first, parses the token out, and submits it with the payload. no macro. no extension. the flow that took serious burp configuration is two checkboxes.
the wordlist i used
the credentials were bee / bug — known, displayed on the page. the exercise was to confirm i could find them with brute-force despite the token. i used wfuzz/general/big.txt for the password field, with bug manually appended to the end so the success case existed in the list.
the success signal wasn't HTTP status — every response was 200, since "invalid credentials" and "login successful" both render normally. the signal was response body size. the success page was smaller than the failure page. sorting fuzzer results by Size Resp. Body put the hit at the top.
where burp wins anyway
zap's UX is rougher overall. once you're past the fuzzer-with-csrf case:
- repeater is faster and more reliable in burp.
- http history is laid out in a way that scales to long sessions; zap's equivalent is busier.
- proxy interception workflow in burp is the gold standard.
- extensions — burp's ecosystem is larger and the community releases are usually higher quality.
if you're doing a long engagement, burp is your daily driver. zap shines for specific tasks where its built-in features happen to save you from a burp configuration nightmare.
the takeaway
a defensive read first: if your login form is protected only by a rotating csrf token, you have not implemented rate limiting. the token slows down naive attackers; a tool that handles rotation reduces the form to a credential check, and you're back to "the wordlist will find your weak password eventually". add rate limiting, account lockout, and CAPTCHA after N failures. the token is a control against csrf, not against brute-force.
an offensive read second: if you're attacking a form like this and burp intruder's macro setup is taking too long, zap's anti-csrf feature is worth knowing about. use the right tool for the job.
bonus footnote
by the time i ran this attack, one of the test users had already disappeared from the database — a side effect of an earlier sql injection that i'd exploited in the same engagement. another user existed in the dumped credentials but couldn't log in through the form. both observations went into the report as findings of their own. in a real engagement, side effects from earlier exploits are part of what you document — the client needs to know what state you left the system in.