Brute-Force Attacks on Web Logins

Brute-force attacks are the digital equivalent of kicking in the front door. It’s loud, sometimes messy, but when there’s no lockout policy or rate-limiting, it works. As pentesters, our job is to identify weak authentication mechanisms—and exploiting them with brute-force is often the first step toward initial access.

A brute-force attack attempts to guess valid credentials by trying numerous username and password combinations against a login form. While it’s considered a “noisy” method, it’s shockingly effective when:

  • There’s no account lockout or alerting.
  • Default credentials are still in place.
  • Credentials are reused across systems.
  • Error messages are too helpful.
  • Simple Brute-Force: Try every possible password for one known user (e.g., admin).
  • Dictionary Attack: Use a wordlist of likely passwords (e.g., rockyou.txt).
  • Credential Stuffing: Reuse known username-password pairs from previous breaches.
  • Username Enumeration + Targeted Attack: Find valid usernames, then pair with common passwords.

Before attacking, understand the login mechanics:

  • Method: GET or POST?
  • Fields: Usually username= and password=, but names can vary (user, pass, login, auth, etc.)
  • Responses: What does success or failure look like? Different status codes, error messages, redirects?

Use Burp Suite to intercept and inspect a login request.

hydra -l admin -P /usr/share/wordlists/rockyou.txt <IP> http-post-form "/login.php:user=^USER^&pass=^PASS^:Invalid credentials"
# -l: Single username
# -P: Password list
# POST endpoint format: URI:body:failure-string
  • Capture a login request.
  • Use Intruder to define payload positions (§user§ and §pass§).
  • Load your wordlists.
  • Configure grep match for success/failure.
patator http_fuzz url="http://target/login.php" method=POST body="username=admin&password=FILE0" 0=/usr/share/wordlists/rockyou.txt -x ignore:fgrep="Invalid"
# fgrep: String to filter failed logins

Some login forms return different messages for:

  • Invalid username vs invalid password
  • User exists but locked
  • Timing differences (use ffuf or Burp Comparer)

Enumerating valid usernames before brute-forcing improves your chances drastically.

Brute-force attacks are noisy, but there are ways to reduce your footprint:

  • Slow down your attack with delay options (--delay in Hydra).
  • Rotate IPs using proxychains or Tor.
  • Bypass WAFs by changing headers, user-agent strings, or using alternative encodings.
  • Credential Spraying: Try one password across many users to avoid lockouts.

You find a login page at /admin/login.php. Testing in Burp shows:

  • POST parameters: username and password
  • Error response contains: Login failed
  • No rate-limiting or CAPTCHA

Hydra becomes your friend:

hydra -L users.txt -P passwords.txt target.com http-post-form "/admin/login.php:username=^USER^&password=^PASS^:Login failed"

Hydra churns through the list. Boom—admin : summer2024 gives you access.

import requests

url = "http://target/login.php"
username = "admin"
with open("rockyou.txt") as file:
    for password in file:
        password = password.strip()
        data = {"username": username, "password": password}
        r = requests.post(url, data=data)
        if "Login failed" not in r.text:
            print(f"[+] Success: {username}:{password}")
            break

When you’re done, report the lack of:

  • Lockout mechanisms
  • Rate-limiting or IP bans
  • CAPTCHA on login forms
  • Error message differentiation

Brute-force might not be elegant, but when a target leaves the front door wide open, it’s not your fault for walking in. Use it wisely, document responsibly, and always check for more stealthy login bypasses once you’re in.

Scroll to Top