The lab#
here is how portswigger describes it
This lab is vulnerable due to a logic flaw in its brute-force protection. To solve the lab, brute-force Carlos's password, then access his account page.
the earlier ip block lab beat the rate limit by interleaving a valid login to reset the counter. this one has an even sharper logic flaw. the protection counts requests, so we simply put the entire password list inside a single request and let the counter stay at one.
why counting requests is the wrong thing to count#
brute force protection usually works by limiting how many login attempts come from you, and it measures attempts by counting requests. one request, one guess. that assumption holds right up until the login accepts more than one guess in a single request.
this login takes its credentials as JSON, and JSON lets a value be a whole array instead of a single string. so where the app expects one password, we can hand it a list of passwords all at once. the server then checks our username against every password in that array, and if any one of them matches it logs us in, but as far as the rate limiter is concerned only a single request ever arrived. we have smuggled hundreds of guesses past a guard that was only ever counting envelopes, not the guesses inside them.
Step 1 - spot the JSON login#
we open the login page and submit a request to see its shape, then send the POST /login request to repeater. the useful detail is that the credentials are submitted as JSON rather than ordinary form fields, which is what gives us room to change the password from a single value into a list.
Step 2 - swap the password for an array#
in repeater we target carlos and replace the single password string with an array holding all of the candidate passwords:
{
"username" : "carlos",
"password" : [
"123456",
"password",
"qwerty"
...
]
}
this is still one request, so it counts as one attempt against the brute force protection, but inside it we are asking the server to test carlos against every password in the list in a single shot.
Step 3 - send it and solve#
we send the request. the server works through the array, and the moment one entry matches carlos's real password it logs us in, returning a 302 redirect rather than the usual failed login response.
that redirect means a password in our array was correct and carlos is now logged in, so we load that 302 response in the browser to follow it into his session and land on his account page.
with this, the lab is solved!
