| Field | Detail |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | Authentication — Username Enumeration, Brute Force |
| Difficulty | Practitioner |
| Objective | Enumerate a valid username, brute-force that user's password, then access their account page |
Username Enumeration via Subtly Different Responses¶
I started by intercepting a login request to see what the application sends.
I sent the request to Intruder and set up a sniper attack against the username field using the candidate username wordlist, planning to repeat the same process against the password field once I had a confirmed username.
Running the attack, almost every candidate returned the same Invalid username or password. message — no obvious differences in status code or response length compared to valid entries, unlike the previous enumeration lab.
Since the response text was nearly identical across the board, I switched to a negative search filter on that dominant string to surface anything that didn't match exactly.
That's where the outlier appeared: the username accounts came back with Invalid username or password — no trailing period. Every other candidate had it; this one didn't. The inconsistency is subtle enough that you'd miss it scrolling through results manually, but it's exactly the kind of detail that leaks which error branch the server actually hit. When a single error message is reused for both "bad username" and "bad password" cases, any variation in how it gets generated — even a missing punctuation mark — can reveal which case applies.
With accounts confirmed as a valid username, I ran a second sniper attack against the password field using the candidate password wordlist.
The payload jordan returned a 302 while everything else failed.
Logging in as accounts:jordan landed on the account page.
Lab solved :p