Enumeration & Brute Force

Overview

These notes cover practical authentication enumeration and brute-force fundamentals for web applications, including username discovery, verbose error abuse, password reset weaknesses, HTTP basic authentication attacks, and passive discovery with archived URLs and search operators.

Authentication Enumeration

Authentication enumeration is the process of extracting useful signals from login, registration, and reset flows to determine how an application handles identity checks. The goal is not just to collect data points, but to understand what those differences reveal about the system's underlying behavior.

Once a tester or attacker can reliably distinguish valid from invalid users, the attack surface narrows significantly. Password guessing, credential stuffing, reset abuse, and social engineering all become more targeted and more efficient.

Identifying Valid Usernames

Knowing a valid username removes one half of the authentication problem. Common indicators include different login responses, password reset messages, registration validation, and timing differences that confirm whether an account exists.

Password Policies

Password policy disclosures can help shape attack strategy. If the application reveals complexity requirements, an attacker can generate or tune a dictionary to match those rules instead of guessing blindly.

<?php
$password = $_POST['pass']; // Example1
$pattern = '/^(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).+$/';

if (preg_match($pattern, $password)) {
    echo "Password is valid.";
} else {
    echo "Password is invalid. It must contain at least one uppercase letter, one number, and one symbol.";
}
?>

Why this matters: if the application exposes the exact policy, a brute-force or password spraying attempt can be tuned around realistic candidate passwords instead of wasting requests on strings that would never be accepted.

Common Places to Enumerate

Web applications regularly expose identity checks through user-friendly features. The most useful places to probe are the ones designed to help legitimate users recover or create access.

Verbose Errors

Verbose errors help developers debug, but they also help attackers map application logic. Detailed failures can expose backend paths, database structure, validation logic, or whether a specific user exists.

What Verbose Errors Can Reveal

How Attackers Trigger Them

Enumeration and brute force work together: valid usernames make brute force more efficient, and verbose errors often reveal lockout behavior, password policy hints, or reset flow weaknesses that improve later attack stages.

Enumeration in Authentication Forms

A classic case is a login or reset form that responds differently depending on whether the submitted email exists. If an invalid address returns Email does not exist but a real one returns Invalid password, the application is effectively acting as an account oracle.

This turns a normal form into a username discovery endpoint and makes later password attacks far more practical.

Automation Example

The following script automates email enumeration by submitting a fixed password and interpreting the JSON response returned by the target application.

import requests
import sys

def check_email(email):
    url = 'http://enum.thm/labs/verbose_login/functions.php'
    headers = {
        'Host': 'enum.thm',
        'User-Agent': 'Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Language': 'en-US,en;q=0.5',
        'Accept-Encoding': 'gzip, deflate',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest',
        'Origin': 'http://enum.thm',
        'Connection': 'close',
        'Referer': 'http://enum.thm/labs/verbose_login/',
    }
    data = {
        'username': email,
        'password': 'password',
        'function': 'login'
    }

    response = requests.post(url, headers=headers, data=data)
    return response.json()

def enumerate_emails(email_file):
    valid_emails = []
    invalid_error = "Email does not exist"

    with open(email_file, 'r') as file:
        emails = file.readlines()

    for email in emails:
        email = email.strip()
        if email:
            response_json = check_email(email)
            if response_json['status'] == 'error' and invalid_error in response_json['message']:
                print(f"[INVALID] {email}")
            else:
                print(f"[VALID] {email}")
                valid_emails.append(email)

    return valid_emails

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python3 script.py <email_list_file>")
        sys.exit(1)

    email_file = sys.argv[1]
    valid_emails = enumerate_emails(email_file)

    print("\\nValid emails found:")
    for valid_email in valid_emails:
        print(valid_email)

Typical usage against a candidate list:

python3 script.py usernames_gmail.com.txt

Testing logic: if the response contains the known invalid-user message, treat the address as invalid. Any different response path is worth reviewing because it may indicate a valid account, alternate validation, or application inconsistency.

Password Reset Flow Vulnerabilities

Password reset workflows are high-value targets because they sit at the intersection of identity verification and credential replacement. A weak reset flow can give attackers account access without ever knowing the original password.

Common Reset Models

Common Weaknesses

Predictable Token Example

If a reset token has low entropy, brute force becomes realistic. In the vulnerable example below, the token is only a three-digit number generated with mt_rand(100, 200).

$token = mt_rand(100, 200);
$query = $conn->prepare("UPDATE users SET reset_token = ? WHERE email = ?");
$query->bind_param("ss", $token, $email);
$query->execute();

That gives an attacker only 101 possible values. Capturing the reset request in Burp and brute-forcing the token parameter becomes entirely practical.

crunch 3 3 -o otp.txt -t %%% -s 100 -e 200

After generating the list, Intruder can replay each candidate token. The successful response usually stands out through a different status code, redirect behavior, or response size.

Defensive baseline: reset tokens should be long, random, single-use, tied to a user and action, and expire quickly.

Basic Authentication

HTTP Basic Authentication is a simple challenge-response scheme defined in RFC 7617. Credentials are sent in the Authorization header as a base64-encoded username:password string.

Authorization: Basic <credentials>

Base64 is only encoding, not encryption. On non-HTTPS transport it is trivial to recover the credentials. Even over HTTPS, weak passwords remain vulnerable to brute force if the endpoint has no rate limiting or lockout protection.

Basic Auth Brute Force Workflow

Operational detail: because the payload ultimately becomes a base64 string, Burp payload processing needs to reconstruct username:password first and only then encode it back into the header format expected by the application.

Wayback URLs and Google Dorks

Enumeration is not limited to the live target. Archived content and search engine indexing can reveal historical files, admin panels, backups, logs, and forgotten endpoints that still exist or still matter.

Wayback URLs

The Internet Archive’s Wayback Machine can expose older versions of a site and URLs that are no longer linked publicly. Tools like waybackurls make it easy to dump archived URLs for triage.

git clone https://github.com/tomnomnom/waybackurls
cd waybackurls
sudo apt install golang-go -y
go build
./waybackurls tryhackme.com

Google Dorks

Search operators can quickly expose indexed resources that were never meant to be easily found.

Key Takeaways