Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type Authentication — Broken Brute-Force Protection
Difficulty Practitioner
Objective Brute-force the victim's password, then log in and access their account page
Note Own credentials wiener:peter, victim username carlos

Broken Brute-Force Protection, IP Block

The app rate-limits login attempts, so I started by confirming exactly how the protection works.

Screenshot

After a few failed attempts against carlos, the app returned "You have made too many incorrect login attempts. Please try again in 1 minute(s)." Switching to wiener:peter, logging in successfully, then going back to carlos with a wrong password reset the counter entirely. That confirmed two things: the block is tracked per source IP rather than per account, and a single successful login from that IP clears it. The reset condition is the actual flaw — not the rate limiting itself.

That means interleaving a successful wiener:peter login between every couple of carlos attempts keeps the block from ever triggering. The challenge is automating it cleanly, which requires two aligned wordlists so Intruder's pitchfork attack sends username and password in lockstep.

For the username list, a short Python script alternates wiener into roughly every third slot with carlos filling the rest:

for i in range(0,200):
    if i % 3 == 0:
        print("wiener")
    else:
        print("carlos")
Screenshot

The password list follows the same alternation pattern — peter for the wiener slots, actual candidates from the wordlist for the carlos slots, keeping the two lists aligned line-for-line:

with open("passwords") as f:
    lines = f.readlines()

i = 0

for line in lines:
    if i % 3 == 0:
        print("peter")
    else:
        print(line.strip())

    i += 1
Screenshot

With both wordlists ready, I intercepted a login request and sent it to Intruder as a pitchfork attack with the two lists paired against the username and password fields.

Screenshot

I created a new resource pool with maximum concurrent requests set to 1. This is what makes the alternating pattern actually work — parallel or out-of-order requests would break the interleaving the attack depends on, since the reset needs to land between specific attempts, not just somewhere in the batch.

The results showed several 302s for wiener:peter (expected — those are just the reset logins doing their job) and exactly one 302 for carlos.

Screenshot

The password for carlos was ranger. Logging in as carlos:ranger landed on the account page.

Screenshot

Lab solved

Resources