If you've spent any time configuring user authentication on... Full Story
By Manny Fernandez
October 23, 2026
Hydra for the Blue Team: Install, Configure, and Run It Against Your Own Defenses
Executive Summary
Objective: Stand up THC-Hydra 9.6, learn its syntax well enough to drive it deliberately, and then use it the way a defender should: as an authorized way to prove whether your authentication surfaces lock out, rate-limit, and alert the way you think they do.
Target audience: SOC analysts, detection engineers, and network/security engineers who own authentication-facing systems (SSH, RDP, web logins, VPN portals, mail) and need to validate controls and tune detections with real brute-force telemetry instead of theory.
Hydra is a network logon cracker. Attackers use it to spray and guess credentials across dozens of protocols. That is exactly why it belongs in your toolkit too. You cannot confidently say “we detect credential brute-forcing” until you have generated the traffic on a system you are authorized to test and watched your own pipeline catch it. This guide treats Hydra as a purple-team instrument: you run the attack against your own lab, then pivot to the logs, SIEM rules, and hardening that actually stop it.
A Word on Authorization (Read This First)
Scope every engagement in writing before you launch anything:
- Target hosts and services, by IP and port, are named explicitly.
- A testing window is agreed, ideally in a maintenance window.
- You run from a known source IP so the SOC can distinguish your test from a real attack (or you tell them nothing, on purpose, to test detection).
- You throttle (
-t,-w) so you do not take down the service you are validating.
Everything below assumes a lab you control. Our examples target a self-contained range, never a third party.
Prerequisites and Lab Architecture
Assumed knowledge
- Comfort on a Linux shell and basic networking (ports, protocols).
- You can read an
auth.logline and a Windows Security event. - You have a victim host or two you are allowed to beat on.
Lab environment
| Component | Role | Address | Notes |
|---|---|---|---|
| Attacker (Kali/Ubuntu) | Runs Hydra | 10.0.10.5 |
Where you launch from |
| Target: Linux | SSH + web login | 10.0.20.10 |
OpenSSH, a simple login form |
| Target: Windows | RDP + SMB | 10.0.20.20 |
Watch Event IDs here |
| SIEM / log collector | Detection | 10.0.30.40 |
Wazuh, Elastic, or FortiAnalyzer |
| Perimeter firewall | Control under test | 198.18.0.1 |
FortiGate transit edge |
Internal LANs use 10.0.0.0/16. The transit/public-facing edge uses 198.18.0.0/15 so nothing here collides with a real routable block.
Password and username lists
Hydra is only as good as its lists. For validation work you do not need SecLists-scale files. A short, targeted list proves the control and keeps the test from running for hours.
# A deliberately tiny list for control validation
printf 'admin\nroot\nservice\ntest\n' > users.txt
printf 'Password1\nWelcome1\nSummer2026!\nchangeme\n' > passwords.txt
For realistic coverage, rockyou.txt ships with Kali under /usr/share/wordlists/. Point at it only when you intend a long run and your target can take it.
Part 1: Installation
Debian, Ubuntu, Kali (apt)
On Kali, Hydra is already present. On Debian or Ubuntu:
sudo apt update
sudo apt install -y hydra
hydra -h | head -n 3
The packaged build may trail upstream. As of this writing the current release is 9.6. If your distro ships an older build and you need the newest modules, build from source.
Build from source (newest modules, optional libraries)
Source gives you the latest protocol modules and lets you link optional libraries (mysql, postgres, mongodb, SSH, SVN, and more).
# Dependencies for a full-featured build on Debian/Ubuntu
sudo apt install -y build-essential libssl-dev libssh-dev \
libidn11-dev libpcre3-dev libgtk2.0-dev libmysqlclient-dev \
libpq-dev libsvn-dev firebird-dev libmemcached-dev \
libgpg-error-dev libgcrypt20-dev
git clone https://github.com/vanhauser-thc/thc-hydra.git
cd thc-hydra
./configure
make
sudo make install
After ./configure, read the summary it prints. It tells you which optional modules will be compiled and which were skipped for missing libraries. If ssh or mysql shows as unavailable and you need it, install the matching -dev package and re-run ./configure.
Docker (no local build)
The maintainer publishes an image, which is handy for a throwaway run or a CI job:
docker pull vanhauser/hydra
docker run -it --rm vanhauser/hydra hydra -h
macOS (Homebrew)
brew install hydra
The Homebrew formula links a reduced module set. If you need a module it was not built with, use the Docker image or a Linux VM.
Confirm the build
hydra -h
The banner lists every protocol your binary supports. If a protocol you expect is missing, that is a build/library issue, not a syntax error. Check the ./configure output.
Part 2: Configuration and Syntax
Hydra has two equivalent invocation styles. Learn the URL style; it is less error-prone.
# URL style (preferred)
hydra [options] PROTOCOL://TARGET:PORT/MODULE-OPTIONS
# Positional style
hydra [options] -s PORT TARGET PROTOCOL MODULE-OPTIONS
The flags you will actually use
| Flag | Meaning | Defender note |
|---|---|---|
-l LOGIN |
Single username | Validate lockout on one known account |
-L FILE |
Username list | Spray across accounts |
-p PASS |
Single password | Password-spray one password across many users |
-P FILE |
Password list | Classic brute-force |
-C FILE |
Combo login:pass file | One credential per line |
-e nsr |
Try null (n), same-as-login (s), reversed (r) | Cheap wins defenders should test |
-t N |
Parallel tasks per target | Lower to stay gentle; raise to stress-test rate limits |
-w N |
Wait seconds per response | Slow the run to dodge or test thresholds |
-f |
Stop after first valid pair on a host | Keep runs short in validation |
-s PORT |
Non-default port | For services moved off the standard port |
-S |
Use SSL/TLS | For wrapped services |
-o FILE |
Write results to file | Evidence for your report |
-b FORMAT |
Output format (text/json/jsonv1) | Feed results into tooling |
-M FILE |
Target list, one per line | Multi-host validation |
-x MIN:MAX:CHARSET |
Generate candidates | Brute-force without a wordlist |
-V / -vV |
Verbose, show each attempt | Correlate attempts against your logs |
-R |
Restore a crashed/aborted session | Resume long runs |
Discover a module’s options
Every module documents its own extra parameters:
hydra -U http-post-form
hydra -U smtp
Read this before you fight a form-based login. The http-post-form module in particular needs its own string, covered below.
Part 3: Running It Against Your Lab
Each example targets lab hosts you own. All use -f and conservative -t so you prove the control without hammering the box.
SSH
hydra -l admin -P passwords.txt -t 4 -f -o ssh_test.txt ssh://10.0.20.10
A single-password spray across many users (often quieter per account, which is the point of testing whether you still catch it):
hydra -L users.txt -p 'Summer2026!' -t 4 ssh://10.0.20.10
RDP (Windows)
hydra -l administrator -P passwords.txt -t 1 -f rdp://10.0.20.20
Keep -t low for RDP. The service is sensitive to parallelism and you will get false negatives if you push it. This run is what generates the Windows events you will hunt for in Part 4.
FTP
hydra -L users.txt -P passwords.txt -t 4 -f ftp://10.0.20.10
HTTP Basic auth
hydra -l admin -P passwords.txt -f http-get://10.0.20.10/protected/
HTTP POST form login
This is the one people get stuck on. The module string has three colon-separated fields: the path, the POST body with ^USER^ and ^PASS^ placeholders, and a failure condition string that Hydra looks for to know a login failed.
hydra -l admin -P passwords.txt 10.0.20.10 http-post-form \
"/login.php:username=^USER^&password=^PASS^:Invalid credentials"
Get the failure string right by submitting one bad login in your browser, reading the response, and copying a phrase that appears only on failure. If you instead have a string that appears only on success, prefix it with S=:
hydra -l admin -P passwords.txt 10.0.20.10 http-post-form \
"/login.php:username=^USER^&password=^PASS^:S=Dashboard"
Capture the exact field names and path with your browser dev tools (Network tab) or a proxy. Guessing the body is the number one reason a form run reports every password as wrong.
Resuming and output
If a long run dies, Hydra drops a hydra.restore file. Resume with:
hydra -R
Write machine-readable results for your report or pipeline:
hydra -l admin -P passwords.txt -b jsonv1 -o ssh_results.json ssh://10.0.20.10
Note: a hydra.restore file is tied to the platform that made it and cannot be moved between systems.
Part 4: The Blue-Team Payoff, Detecting the Attack
This is why you ran it. Now go read what it left behind and make sure your pipeline saw it.
Linux SSH (auth.log / journald)
A Hydra SSH run produces a burst of failures from one source. On Debian/Ubuntu:
grep "Failed password" /var/log/auth.log | tail -n 20
journalctl -u ssh --since "10 min ago" | grep -i fail
The signal is rate and ratio: many failures from one IP in a short window, often cycling usernames, sometimes hitting invalid users (Failed password for invalid user ...). A quick count:
grep "Failed password" /var/log/auth.log \
| awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
Windows RDP and SMB
Your RDP run lights up the Security log. The events that matter:
| Event ID | Meaning |
|---|---|
4625 |
Failed logon (the bread and butter of brute-force detection) |
4771 |
Kerberos pre-authentication failed |
4740 |
Account locked out (your lockout policy fired) |
4776 |
NTLM credential validation failed |
Look at the Logon Type and Status/Sub-Status codes on 4625 to tell a wrong password (0xC000006A) from a disabled or nonexistent account (0xC0000064, 0xC0000072). A flood of 4625 with a single source workstation or IP, across many target accounts, is your password-spray signature.
Web login
A form brute-force shows up as many POSTs to the login endpoint from one source, each returning the same failure status (often 200 with a failure body, or 401/403), at machine speed.
awk '$7 ~ /login/ {print $1}' /var/log/nginx/access.log \
| sort | uniq -c | sort -rn | head
Turn it into a detection
The durable signature across every protocol is the same: N authentication failures from one source within T seconds. Build that once and apply it everywhere.
- Wazuh: the default ruleset already flags SSH brute-force (rule groups around repeated
authentication_failed). Run your Hydra test and confirm the alert fires; if it does not, your agent is not shippingauth.logor the decoder is off. - Elastic/Splunk: a threshold rule, “more than X failed logons from the same
source.ipin Y minutes,” is the baseline. Add a second rule for “one password, many usernames” to catch spraying that stays under the per-account threshold. - Account-centric vs source-centric: spraying defeats per-account lockout by touching each account only once or twice. You need a source-centric rule (failures grouped by source IP across all accounts), not just a per-account one.
Run Hydra with -vV so each attempt is timestamped on your side, then line those timestamps up against what landed in the SIEM. Gaps are detection failures. That comparison is the entire value of the exercise.
Part 5: Defenses and Hardening
Detection tells you it happened. These controls stop it.
Everywhere
- Multi-factor authentication. The single highest-value control. A correct password is not enough, so credential guessing stops being a path to access even when it succeeds.
- Rate limiting and lockout. Throttle attempts per source and per account. Tune the threshold against your Hydra run: set it, attack, confirm lockout at the number you expect.
- Remove default and weak credentials. Hydra’s
-e nsrand combo-file runs exist because defaults and reused passwords still work. Kill them.
SSH
- Disable password auth entirely where you can:
PasswordAuthentication no, key-based only. - fail2ban is the classic, effective control. The
sshdjail bans a source after N failures:
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
Run Hydra, then confirm the ban landed:
sudo fail2ban-client status sshd
Windows / RDP
- Set an account lockout policy (threshold, window, duration) and confirm Event
4740fires during your test. - Do not expose RDP to the internet. Front it with a VPN or an RD Gateway with MFA.
- Enable Network Level Authentication.
Web applications
- CAPTCHA or progressive delays after repeated failures.
- A generic failure message (do not reveal whether the username exists).
- A WAF rule that rate-limits the login endpoint per source.
FortiGate perimeter controls
If a FortiGate sits in front of the service, several native controls blunt or detect the run.
DoS policy to cap new connections and concurrent sessions per source, which caps attempt rate at the edge:
config firewall DoS-policy
edit 1
set interface "wan1"
set srcaddr "all"
set dstaddr "all"
set service "ALL"
config anomaly
edit "tcp_src_session"
set status enable
set action block
set threshold 300
next
end
next
end
IPS carries signatures for brute-force patterns against SSH, RDP, FTP, and more. Apply an IPS profile with the relevant signatures to the inbound policy and let it rate-track failed-login anomalies:
config ips sensor
edit "brute-force-protect"
config entries
edit 1
set rule 1
set status enable
set action block
next
end
next
end
Then reference that sensor from the firewall policy protecting the service.
Geo-blocking and allow-lists. If the service should only ever be reached from specific countries or known source networks, a geo-based address object on the policy removes most of the internet as an attack surface before Hydra ever connects.
FortiAuthenticator / FortiToken. Push MFA and lockout at the identity layer so a successful guess still fails to produce a session, and repeated failures lock the account and log it centrally.
Verification and Validation
A control is not validated until you have watched it work:
- Lockout fires at the threshold. Attack one account with
-t 1; confirm it locks at exactly the configured number of failures (Event 4740 on Windows,fail2ban-client statuson Linux). - Spray is caught source-side. Run
-L users.txt -p oneShotPassword; confirm your source-centric SIEM rule alerts even though no single account crossed its lockout threshold. - MFA holds. Supply a known-good password via Hydra against an MFA-protected service; confirm the login still fails and the event is logged.
- Edge throttle works. Raise
-tand confirm the FortiGate DoS policy or WAF rate limit starts dropping before the backend is saturated.
Expected healthy result: short, loud, and stopped. The attack generates a clear alert, trips a ban or lockout quickly, and never produces a usable session.
Troubleshooting and Gotchas
Every password reports as wrong on an http-post-form run. Your failure-condition string or POST body is off. Submit one bad login in a browser, read the actual response, and copy a phrase that appears only on failure. Confirm the field names and path in the Network tab. If you are keying on a success string, remember the S= prefix.
A module you need is missing from the banner. That is a build issue, not syntax. Install the matching -dev library, re-run ./configure, read its summary to confirm the module is now listed, then make again. Or use the Docker image, which ships a fuller module set.
RDP run reports nothing found even with the right password. RDP is sensitive to parallelism. Drop to -t 1 and add a small -w. High task counts cause missed hits and false negatives.
The run is slow or the target falls over. That is your own rate control, or lack of it. Lower -t, add -w, and shorten your wordlist. If you are validating a control rather than cracking, a tiny targeted list and -f get you the answer in seconds.
Hydra exits and leaves hydra.restore. Resume with hydra -R. Do not copy that file to another machine; it is platform-specific and will not restore elsewhere.
Validate your controls on systems you are authorized to test. Then go turn what you learned into a detection that never sleeps.
Recent posts
-
-
DNS is one of those technologies that quietly underpins... Full Story
-
BGP issues on FortiGate firewalls usually trace back to... Full Story
-
Every time your laptop talks to your router, a... Full Story
-
If you've spent any time configuring NAT on a... Full Story
-
If you have spent any time configuring firewall policies... Full Story
-
High availability on FortiGate is one of those features... Full Story
-
If you've configured SD-WAN on a FortiGate, you've almost... Full Story
-
FortiLink is the management protocol that turns a FortiSwitch... Full Story
-
FortiSwitches are pretty rock solid from Mean Time Between... Full Story
-
This is a quicky tip. Have you ever gone... Full Story
-
DNS is one of those quiet pieces of internet... Full Story
-
This article is an updated version of the previous... Full Story
-
You will add ns2 as a secondary (slave) BIND9... Full Story
-
In the process of deploying my lab, I needed... Full Story
-
RFC 8805, used to be known as Self-Correcting IP... Full Story
-
Years back, I wrote an article about certificate pinning. ... Full Story
-
FortiGates have the ability to send alerts to Microsoft... Full Story
-
In this post, I am going to walk through... Full Story
-
Troubleshooting VoIP on a FortiGate can feel like trying... Full Story
-
Prior to FortiOS 7.0, there were three commands to... Full Story
-
In this post, I am going to go over... Full Story
-
What we are going to do: We are going... Full Story
-
Choosing between FGCP (FortiGate Clustering Protocol) and FGSP (FortiGate... Full Story
-
Creating a VLAN on macOS (The "Pro" Move) A... Full Story
-
This blog post explores the logic behind how macOS... Full Story
-
Pretty Fly for a Wi-Fi Tell My Wi-Fi Love... Full Story
-
Part of my daily gig is creating BoMs (Bill-of-Materials)... Full Story
-
ICMP introduces several security risks, but careful filtering, rate... Full Story
-
The command diag debug application dhcps -1 enables full... Full Story
-
In the world of FortiOS, execute tac report is... Full Story
-
LLDP; What is it The Link Layer Discovery Protocol... Full Story
-
What it actually does When you run diagnose fdsm... Full Story
-
Monkey Bites are bite-sized, high-impact security insights designed for... Full Story
-
I have run macOS in macOS with Parallels but... Full Story
-
Don't be confused with my other FortiNAC posts where... Full Story
-
This is the third session in a multi-part article... Full Story
-
Today I was configuring key-based authentication on a FortiGate... Full Story
-
Netcat, often called the "Swiss Army knife" of networking,... Full Story
-
At its core, IEEE 802.1X is a network layer... Full Story
-
In case you did not see the previous FortiNAC... Full Story
-
This is our 5th session where we are going... Full Story
-
Now that we have Wireshark installed and somewhat configured,... Full Story
-
The Philosophy of Packet Analysis Troubleshooting isn't about looking... Full Story
-
Plus what you actually get with FortiCare Essential, Premium... Full Story
-
No fluff. Just the config that works. This one... Full Story
-
No fluff. Just the config that works. Executive Summary... Full Story