Skip to content

SSH Private Key Discovery and Passphrase Cracking

4 min read Created Jan 3, 2026 Last updated Aug 11, 2026

Compromised user accounts frequently contain reusable SSH keys. Private keys with trusted public counterparts on other hosts allow silent lateral movement without password exposure. Keys often persist long after the original use case ends. Check every account you compromise, not just the primary target. Key discovery costs almost nothing and regularly opens paths that password reuse does not.

Locating Keys

System-wide public keys often reveal host identities or trusted configurations. Look for multiple pub files pointing to different host entries. Each one is a potential lateral movement target worth recording.

user@host ~ $ find /etc/ssh -name "*.pub" 2>/dev/null

User-specific keys hold the highest reuse potential. The output lists every file matching the id_ prefix across all home directories. Pay close attention to keys owned by service accounts and non-interactive users. These accounts often have keys configured for automated tasks and rarely have passphrases set.

user@host ~ $ find /home -name "id_*" 2>/dev/null

Narrow to the current user for speed when you already have a working session. This avoids noisy filesystem traversal. Also check for non-default key names the user may have generated manually, such as id_rsa_work or deploy_key.

user@host ~ $ ls ~/.ssh/id_*
user@host ~ $ find ~/.ssh -name "id_*" 2>/dev/null

Key types to prioritize:

  • id_rsa (most common, widely accepted)

  • id_ed25519 (modern, fast)

  • id_ecdsa (less common, but still found)

  • Non-default names like deploy_key or id_rsa_work

Also read authorized_keys to understand which public keys the current account trusts. The known_hosts file reveals other SSH targets the user has connected to previously. Both files guide your next lateral movement targets. Exfiltrate all private keys immediately. Unencrypted keys are directly usable with no additional cracking step required.

┌──(kali㉿kali)-[~]
└─$ ssh -i id_rsa $USERNAME@next_target_ip

Success confirms the target has this public key in its authorized_keys file. A permission denied error means the key is not trusted on that host, or you used the wrong username. Try the key against every host listed in the user's known_hosts file. Vary the username if the owner account differs between hosts.

Cracking Passphrase-Protected Keys

Encrypted keys prompt for a passphrase on use. Crack them offline after exfiltration to avoid on-host detection risk. Running a cracking tool directly on the compromised host generates process noise and may trigger endpoint controls. Set strict permissions on the key file before conversion if ssh2john complains about insecure permissions.

┌──(kali㉿kali)-[~]
└─$ chmod 600 id_rsa

Convert the key to John format. The output is a single-line hash prefixed with the filename. If ssh2john.py is not on PATH, locate it with find / -name ssh2john.py 2>/dev/null. The hash file must carry the correct prefix or John will refuse to recognize the format.

┌──(kali㉿kali)-[~]
└─$ python3 ssh2john.py id_rsa > ssh.hash

Use the standalone ssh2john binary if it is available. Both produce identical output. Some Kali versions ship one but not the other, so try both paths if the first is missing.

┌──(kali㉿kali)-[~]
└─$ ssh2john id_rsa > ssh.hash

Crack the hash against a wordlist. John prints the passphrase next to the key filename when it finds a match. If rockyou.txt returns nothing, try a targeted wordlist built from the organization name, domain name, or passwords already recovered from the environment. Company names and years are common weak passphrases.

┌──(kali㉿kali)-[~]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt ssh.hash
hunter2         (id_rsa)

Weak passphrases fall quickly against rockyou.txt. Cracked keys unlock the same lateral movement potential as unencrypted ones. Test the key with the recovered passphrase against every host in the user's known_hosts file. The key owner's username is usually the right starting point, but service accounts and shared deployment keys may accept different usernames. Check the authorized_keys file on reachable hosts to confirm which accounts trust this public key.

Edge Cases and Broader Searches

Keys in non-standard locations require broader filesystem searches. Developers and DevOps users sometimes store keys under project directories or config paths outside the home directory.

user@host ~ $ find / -name "id_*" 2>/dev/null

Suppress errors on inaccessible directories using 2>/dev/null. Root access expands scope significantly and reveals keys owned by system service accounts. Check backup directories, deployment scripts, Ansible configuration, and Docker build contexts for keys written to disk. Keys committed to .git history or embedded in CI configuration files are a common find. Application user accounts under /var or /opt sometimes store keys used for automated deployments. Those accounts frequently have no passphrase and trust set across multiple internal hosts.