Casser la passphrase d'une clé privée SSH avec hashcat et John the Ripper
Extrayez le hash d'un id_rsa chiffré avec ssh2john, choisissez le bon mode hashcat pour les clés PEM classiques, et sachez quand seul John the Ripper casse une clé OpenSSH moderne.
Une clé privée SSH chiffrée n'est jamais qu'un secret protégé par mot de passe parmi d'autres, et comme tous les autres elle se ramène à la même question : extraire un hash, choisir le bon outil et le bon mode, lancer un dictionnaire. La subtilité avec les clés SSH, c'est que deux formats très différents se cachent derrière le même bandeau -----BEGIN ... PRIVATE KEY-----, et qu'aujourd'hui seul l'un des deux se laisse toucher par hashcat.
Deux formats de clé, deux problèmes différents
Les clés plus anciennes — tout ce qui a été généré avec ssh-keygen -m PEM, ou produit par des outils encore réglés sur le format traditionnel — sont des fichiers PEM au style OpenSSL. La passphrase dérive une clé symétrique via un KDF simple basé sur MD5, qui sert ensuite à déchiffrer la clé RSA/DSA/EC intégrée avec DES, 3DES ou AES-CBC selon ce qu'annonce l'en-tête.
Depuis OpenSSH 7.8 (2018), ssh-keygen écrit par défaut le nouveau conteneur openssh-key-v1 pour tous les types de clé, y compris le désormais très répandu id_ed25519. Le seul KDF que ce format accepte est bcrypt-pbkdf, volontairement plus lent et plus gourmand en mémoire que l'ancien schéma MD5 — une bonne nouvelle si c'est votre clé, une mauvaise pour un attaquant, et la raison pour laquelle beaucoup de « j'ai lancé hashcat sur ma clé et ça a planté » relèvent en réalité d'une incompatibilité de format plutôt que d'un problème de cassage.
Extraire le hash avec ssh2john
Les deux formats passent par le même outil. ssh2john.py est fourni avec la distribution jumbo de John the Ripper (sur Kali, généralement dans /usr/share/john/ssh2john.py ou /opt/john/ssh2john.py) et inspecte lui-même l'en-tête de la clé pour décider comment la lire :
python3 /usr/share/john/ssh2john.py id_rsa > hash.txt
Le résultat est une seule ligne préfixée par $sshng$, suivie d'un identifiant de chiffrement, des paramètres du KDF et du blob de clé chiffré. C'est ce préfixe que reconnaissent hashcat et John — on ne donne jamais le fichier de clé brut directement à l'un ou l'autre.
Casser une clé PEM classique avec hashcat
Pour une clé classique, l'identifiant de chiffrement juste après $sshng$ indique à hashcat quel mode utiliser :
| Préfixe du hash | mode hashcat |
|---|---|
$sshng$0$ | -m 22911 |
$sshng$6$ | -m 22921 |
$sshng$1$ / $sshng$3$ | -m 22931 |
$sshng$4$ | -m 22941 |
Lancez-le comme n'importe quel autre job hashcat :
hashcat -m 22911 hash.txt /usr/share/wordlists/rockyou.txt
Si la passphrase suit un schéma connu — un mot suivi d'une année, par exemple — une attaque par masque ou un dictionnaire enrichi de règles aboutira bien plus vite qu'un simple passage de dictionnaire brut ; voir la combinaison dictionnaire et règles qui casse vraiment les mots de passe.
Si hashcat annonce une token length exception, ne supposez pas d'emblée que le hash est corrompu — vérifiez d'abord si la clé n'est pas en réalité une clé openssh-key-v1 moderne. C'est l'objet de la section suivante.
Quand hashcat ne peut rien faire : les clés OpenSSH modernes
Les modes SSH documentés de hashcat (22911–22951) ont été conçus pour l'ancien format PEM/KDF MD5. Une clé protégée par bcrypt-pbkdf — qui, encore une fois, est le réglage par défaut de toute clé générée par ssh-keygen depuis 2018 — n'est pas encore couverte par un mode stable. Inutile de gaspiller du temps GPU à forcer ce hash dans l'un des modes ci-dessus ; la structure des tokens ne correspond pas et hashcat le rejettera.
C'est là que John the Ripper fait la différence. Le même résultat $sshng$ produit par ssh2john.py se casse directement dans John :
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Si John ne détecte pas automatiquement le bon format, listez ce qu'il propose et choisissez l'option liée à SSH (le nom exact — ssh ou ssh-ng — a changé d'une version jumbo à l'autre) :
john --list=formats | grep -i ssh
john --format=ssh-ng --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Comme bcrypt-pbkdf est volontairement coûteux, attendez-vous à un débit bien inférieur à celui d'une clé PEM classique ou d'un hash rapide non salé — un mot de dictionnaire court tombe toujours vite, mais une longue passphrase aléatoire, c'est une autre histoire.
À retenir
Identifiez d'abord le conteneur auquel vous avez affaire avant de choisir un outil : -----BEGIN RSA PRIVATE KEY----- et consorts, c'est l'ancien format PEM que hashcat peut casser directement ; -----BEGIN OPENSSH PRIVATE KEY----- est le conteneur bcrypt-pbkdf qui, pour l'instant, nécessite John the Ripper. Dans tous les cas, ssh2john.py reste le seul moyen d'obtenir un hash exploitable à partir du fichier de clé, et la page clé privée SSH de l'identifiant de hash regroupe l'ensemble des commandes une fois le mode confirmé.