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.
What Is a Brute-Force Attack?
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.
Types of Brute-Force Attacks
- 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.
Identifying a Login Form
Before attacking, understand the login mechanics:
- Method: GET or POST?
- Fields: Usually
username=andpassword=, 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.
Tools of the Trade
Hydra
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
Burp Suite Intruder
- Capture a login request.
- Use Intruder to define payload positions (
§user§and§pass§). - Load your wordlists.
- Configure grep match for success/failure.
Patator
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
Username Enumeration
Some login forms return different messages for:
- Invalid username vs invalid password
- User exists but locked
- Timing differences (use
ffufor Burp Comparer)
Enumerating valid usernames before brute-forcing improves your chances drastically.
Bypassing Rate Limits and Detection
Brute-force attacks are noisy, but there are ways to reduce your footprint:
- Slow down your attack with delay options (
--delayin 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.
Example Scenario
You find a login page at /admin/login.php. Testing in Burp shows:
- POST parameters:
usernameandpassword - 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.
Writing a Simple Python Brute-Forcer
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
Defensive Considerations
When you’re done, report the lack of:
- Lockout mechanisms
- Rate-limiting or IP bans
- CAPTCHA on login forms
- Error message differentiation
Final Thoughts
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.
