Cet article va aborder différentes techniques de cassage de clés privées SSH.
Une clé privée non chiffrée peut être utilisée par n’importe qui ayant accès au fichier.
Alors qu’une clé chiffrée, elle, ne sera utilisable que par les personnes connaissant le mot de passe permettant de déchiffrer la clé.
Ainsi, une clé privée chiffrée compromise n’a pas de valeur pour l’attaquant tant qu’il n’a pas réussi à la casser.
Dans une première partie, nous aborderons les différents types de clé disponibles et comment les générer. Dans une deuxième partie, nous verrons comment essayer de casser ces clés sommairement avec un script "naïf", John the Ripper et Hashcat.
Cet article est aussi disponible en anglais 🇬🇧.
Note 📝 : un lexique est disponible en fin de document.
Motivation
En tant qu’auditeur technique (ou apprenant sur un laboratoire virtuel), il est probable de tomber, tôt ou tard, nez à nez avec une clé privée SSH après avoir compromis une machine ou un compte utilisateur. À ce moment-là, il est intéressant de connaître les moyens à sa disposition pour pouvoir profiter de cette opportunité (déchiffrer la clé et l’utiliser). D’autant plus, qu’en cas de succès, cela permettrait de pivoter sur une des machines où elle est utilisable (voir comment casser un fichier known_hosts
haché).
ssh-keygen
Général
Pour générer des clés de test, nous allons utiliser la commande ssh-keygen
qui fait partie d’openssh.
Note 📝 : dropbear possède une commande dropbearkey
mais ne supporte pas les clés chiffrées. Pas de bras clé chiffrée pas de chocolat cassage.
Pour installer openssh sur ArchLinux : pacman -Syu openssh
. Pour les autres distributions, voir le nom du paquet sur repology.
Normalement, les clés privées générées seront stockées dans ~/.ssh/
, c’est-à-dire dans le répertoire personnel de chaque utilisateur.
Cet article utilise ssh-keygen
fourni avec OpenSSH 9.6 et reposant sur OpenSSL 3.2.1.
➜ ssh -V
OpenSSH_9.6p1, OpenSSL 3.2.1 30 Jan 2024
La base
Il est possible de générer une clé avec la configuration par défaut sans spécifier aucune option.
➜ ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/noraj/.ssh/id_ed25519): /tmp/clé_démo
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /tmp/clé_démo
Your public key has been saved in /tmp/clé_démo.pub
The key fingerprint is:
SHA256:Fh+BPhBLTUY8/9n1b/DQQTvHoSkPZ4N20wpiOivM6DE noraj@norarch
The key's randomart image is:
+--[ED25519 256]--+
| o*+.. |
| ..o= . o |
| .o.o. . =.o|
| o=.B O =+|
| S.+.Oo+o=|
| + oo+ o|
| E+ o +.|
| .o+ . +|
| .. . . |
+----[SHA256]-----+
Nous obtiendrons une clé privée de la sorte :
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBgxQkqMd
jyuADNv6HN31l5AAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBqcVNY4wFSlVOz+
EpJAa06Qtuv1uciGbBUCRHmHhbGoAAAAkNl+6oYEq7ZyEWuubCSBuATjTVf0if/QdNYWB6
e8NGSrpGEgoSCzaJOo2mnBp20P4G8hpT5RFs5skfEWBlItEyX85FO2bj8YCIlRtCruaegC
f40zSY7acP8Y2YE5v6RCPZ9TT3TckMERlKsMSWM6ksmvBkoYLZq/kR7Od2XuQTrsAXdxMb
cHXF72FPtfdiN1Pw==
-----END OPENSSH PRIVATE KEY-----
Dont la clé publique correspondante est :
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBqcVNY4wFSlVOz+EpJAa06Qtuv1uciGbBUCRHmHhbGo noraj@norarch
Par défaut, la clé est générée au format privé OpenSSH (les autres formats supportés sont PEM, PKCS8 et RFC4716), mais cela peut changer selon le type de clé ou l’option utilisée.
-m key_format
Specify a key format for key generation, the -i (import), -e (export) conversion options, and the -p change passphrase operation. The latter may be used to convert between OpenSSH private key and PEM private key formats. The supported key formats are: “RFC4716” (RFC 4716/SSH2 public or private key), “PKCS8” (PKCS8 public or private key) or “PEM” (PEM public key). By default OpenSSH will write newly-generated private keys in its own format, but when converting public keys for export the default format is “RFC4716”. Setting a format of “PEM” when generating or up‐dating a supported private key type will cause the key to be stored in the legacy PEM private key format.
Note 📝 : RFC4716
est un format spécifique aux clés publiques, il ne s’applique donc pas aux clés privées. Je ne sais pas pourquoi la page man
de ssh-keygen
en parle aussi pour les clés privées. D’ailleurs, exporter une clé privée en demandant le format RFC4716 donnera une clé privée au format OpenSSH.
Voici la liste des formats supportés par ssh-keygen
selon le type de clé :
Type ⬇️ Format ➡️ | Défaut | PEM | PKCS8 | OpenSSH |
---|---|---|---|---|
DSA | OpenSSH | ✅ | ✅ | ✅ |
RSA | OpenSSH | ✅ | ✅ | ✅ |
ecdsa | OpenSSH | ✅ | ✅ | ✅ |
ed25519 | OpenSSH | ❌ | ❌ | ✅ |
Attention : Par exemple, ssh-keygen -t ed25519 -f clé_ed25519 -m PKCS8
fournira une clé au format OpenSSH et pas PKCS8 (solution de repli silencieuse). Si le format demandé n’est pas disponible, il sera remplacé par le format privé OpenSSH.
Pour pouvoir lire la clé privée dans un format compréhensible par un humain, il faut utiliser l’une des commandes ci-dessous selon le type de clé et le format.
# DSA
openssl dsa -in clé_dsa_pem -text -noout
openssl dsa -in clé_dsa_pkcs8 -text -noout
# RSA
openssl rsa -in clé_rsa_pem -text -noout
openssl rsa -in clé_rsa_pkcs8 -text -noout
# ecdsa
openssl ec -in clé_ecdsa_pem -text -noout
openssl ec -in clé_ecdsa_pkcs8 -text -noout
Pour les clés ed25519, qui ne peuvent être générées par ssh-keygen
qu’au format OpenSSH, il faudra les convertir en amont, par exemple à l’aide de la commande sshpk-conv
fourni dans le paquet npm sshpk.
# ed25519
npm i -g sshpk
sshpk-conv clé_ed25519_openssh -t pem -p -o clé_ed25519_pem
sshpk-conv clé_ed25519_openssh -t pkcs8 -p -o clé_ed25519_pkcs8
Cependant, même au format PEM ou PKCS8, il sera impossible de les lire directement avec OpenSSL.
The only Elliptic Curve algorithms that OpenSSL currently supports are Elliptic Curve Diffie Hellman (ECDH) for key agreement and Elliptic Curve Digital Signature Algorithm (ECDSA) for signing/verifying.
x25519, ed25519 and ed448 aren’t standard EC curves so you can’t use ecparams or ec subcommands to work with them. If you need to generate x25519 or ed25519 keys then see the genpkey subcommand.
_Source_
En effet, Ed25519 est le système de signature EdDSA utilisant SHA-512 (SHA-2) et Curve25519 (cas particulier d’EdDSA), il n’y aurait de toute façon pas grand-chose à afficher.
Types de clés
Voici les différents types de clés supportés par ssh-keygen
:
- DSA
- RSA
- ecdsa
- ecdsa-sk
- ed25519
- ed25519-sk
Les deux types terminant par MARKDOWN_HASHdcf8c5b65ddef54be59c5ece40fffecdMARKDOWNHASH
(Security Key_) sont des variantes spécifiquement réservées aux appareils d’authentification à deux facteurs matériels supportant FIDO/U2F (ex : YubiKey).
Pour spécifier le type de clé à générer, il faut utiliser l’option -t
.
Types de chiffrements
Les différents algorithmes de chiffrement sont :
- 3DES CBC
- AES 128/192/256 CBC/CTR/GCM
- chacha20-poly1305
La liste peut potentiellement différer selon la version d’OpenSSL installée. La commande ci-dessous permet de lister ceux qui sont supportés :
➜ ssh -Q cipher
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com
Pour spécifier l’algorithme de chiffrement, il faut utiliser l’option -Z
.
Exemples de génération
Voici quelques scripts ZSH pour générer des clés SSH.
Générer une clé de chaque type de clé :
#!/usr/bin/env zsh
for key_type in dsa rsa ecdsa ed25519 # ecdsa-sk ed25519-sk
do
ssh-keygen -N '123soleil' -t ${key_type} -f /tmp/all-keys/clé_${key_type}_openssh
done
Générer une clé pour chaque algorithme de chiffrement :
#!/usr/bin/env zsh
for cipher in $(ssh -Q cipher)
do
ssh-keygen -N '123soleil' -t ed25519 -Z $cipher -f /tmp/all-ciphers/clé_ed25519_${cipher}_openssh
done
Générer une clé pour chaque type de clé avec chaque algorithme de chiffrement :
#!/usr/bin/env zsh
for key_type in dsa rsa ecdsa ed25519 # ecdsa-sk ed25519-sk
do
for cipher in $(ssh -Q cipher)
do
ssh-keygen -N '123soleil' -t $key_type -Z $cipher -f /tmp/all-keys-ciphers/clé_${key_type}_${cipher}_openssh
done
done
Générer une clé pour chaque type de clé avec chaque format d’export :
#!/usr/bin/env zsh
for key_type in dsa rsa ecdsa ed25519 # ecdsa-sk ed25519-sk
do
for format in OpenSSH PEM PKCS8 RFC4716
do
if [[ $format = 'OpenSSH' ]]
then
ssh-keygen -N '123soleil' -t $key_type -f /tmp/all-keys-formats/clé_${key_type}_${format}
else
ssh-keygen -N '123soleil' -t $key_type -f /tmp/all-keys-formats/clé_${key_type}_${format} -m ${format}
fi
done
done
Générer un fichier contenant le pseudo-haché pour chaque type de clé avec chaque algorithme de chiffrement au format OpenSSH et PEM (ce sera utile pour plus tard) :
#!/usr/bin/env zsh
for key_type in dsa rsa ecdsa ed25519 # ecdsa-sk ed25519-sk
do
for cipher in $(ssh -Q cipher)
do
ssh2john /tmp/all-keys-ciphers/clé_${key_type}_${cipher}_openssh > /tmp/all-keys-ciphers/clé_${key_type}_${cipher}_openssh.jtr
ssh2john /tmp/all-keys-ciphers/clé_${key_type}_${cipher}_PEM > /tmp/all-keys-ciphers/clé_${key_type}_${cipher}_PEM.jtr
done
done
Approches
Nous allons maintenant essayer de casser ces clés sommairement avec trois méthodes :
- script "naïf",
- John the Ripper,
- Hashcat.
Par soucis de simplicité, pour chaque méthode, nous considérons uniquement l’attaque par dictionnaire.
Les temps indicatifs d’exécution sont donnés pour un processeur Intel i5-1145G7 @ 2.6 GHz (script, John the Ripper) doté d’un iGPU Intel® Iris® Xe Graphics (Hashcat) fonctionnant avec OpenCL 3.0 NEO
.
Naïve (script)
Ce script Ruby, dit naïf, va lire un dictionnaire de mots de passe et exécuter une commande ssh-keygen
avec le mot de passe candidat jusqu’à ce que ssh-keygen
renvoie autre chose qu’une erreur. Ce qui indiquera alors que le bon mot de passe a été trouvé.
require 'open3'
if ARGV.size == 2
password_found = false
File.readlines(ARGV[1], chomp: true).each do |password|
Open3.popen3("ssh-keygen -y -f #{ARGV[0]} -P '#{password}'") { |i,o,e,t|
error = e.read.chomp
if error.empty?
puts "\nThe password is: #{password}"
password_found = true
elsif /incorrect passphrase supplied to decrypt private key/.match?(error)
print '.'
else
puts "Error: #{t.value}"
puts error
end
}
break if password_found
end
else
puts "Usage : ruby #{__FILE__} SSH_KEY WORDLIST"
puts "Example: ruby #{__FILE__} ~/.ssh/id_ed25519_crack /usr/share/wordlists/passwords/richelieu-french-top20000.txt"
end
Note 📝 : l’utilisation de l’option -y
ne fonctionne que pour le format OpenSSH. Pour une clé au format PEM, il faudra une commande tentant de changer le mot de passe (ou supprimer le chiffrement) de la clé : ssh-keygen -f /chemin/clé -m pem -p -P tentative_mdp
. Mais n’effectuez pas cette opération dans le cadre d’un audit sans l’autorisation du client, ou alors copiez la clé localement avant.
Ce script s’est exécuté en 89 secondes (ou 80 sans l’affichage de .
quand le mot de passe n’est pas bon).
Sortie d’affichage :
➜ time ruby ssh-bf.rb ~/.ssh/id_ed25519_crack /usr/share/wordlists/passwords/richelieu-french-top20000.txt
.....................................................................................................................................................................................................................
.....................................................................................................................................................................................................................
.........................................................................................................................
The password is: fripouille
ruby ssh-bf.rb ~/.ssh/id_ed25519_crack 87,56s user 1,28s system 99% cpu 1:29,02 total
Ce script est notamment dit "naïf" car il n’est pas multifil (pas d’utilisation de fil d’exécution ou processus fils), ce qui est extrêmement peu performant.
Par contre, l’avantage de cette méthode est de fonctionner pour tous les formats de fichiers, algorithmes de chiffrement ou types de clé supportés, car elle utilise directement ssh-keygen
.
John the Ripper
Comme une très grande durée sépare souvent deux versions de JtR, il existe souvent de nombreux bogues corrigés ou nouvelles fonctionnalités dans la branche principale du dépôt git qui ne le sont pas dans la dernière version disponible. Ainsi, je recommande d’installer la version git de JtR (ex : john-git pour ArchLinux).
Tous les tests seront effectués avec la version ci-dessous :
John the Ripper 1.9.0-jumbo-1+bleeding-173b5629e8 2024-01-18 00:08:42 +0100 MPI + OMP [linux-gnu 64-bit x86_64 AVX AC]
ssh2john permet de créer un pseudo-haché compréhensible par JtR à partir d’une clé privée SSH.
➜ ssh2john ~/.ssh/id_ed25519_crack > /tmp/hash_jtr.txt
/home/noraj/.ssh/id_ed25519_crack:$sshng$6$16$3843af13aef53d4c0906f2998b082b3d$274$6f70656e7373682d6b65792d7631000000000a6165733235362d6374720000000662637279707400000018000000103843af13aef53d4c0906f2998b082b3d0000001800000001000000330000000b7373682d6564323535313900000020785c404a9750e39a4cdb788e787f13fdf0d62ca91ea76e3034272722980c222d00000090a99a138ebcd23a3fac923d88fb2b42833e4fc29d409efe86d543f8224cd11263b511e6cc858919bb58692a07664fb56905915bfe8d4a31db398827a65070f33dc127c3ca7d2ad9d184922e7a5e657de10166ee6adfc0b4cc736567adaeb8b1a160d008b1e5bd0a0188be18152d8eecec7bbd9b35d8f551e059bc57fa7642b7535a4d1aad8bb616576b9fb6b2e62bb7e5$24$130
Cette fois-ci, le cassage prend 18 secondes, ce qui est beaucoup moins que l’approche naïve, grâce à l’exécution multifil.
➜ time john /tmp/hash_jtr.txt -w=/usr/share/wordlists/passwords/richelieu-french-top20000.txt --format=ssh
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes
Cost 2 (iteration count) is 24 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
fripouille (/home/noraj/.ssh/id_ed25519_crack)
1g 0:00:00:15 DONE (2024-01-24 17:23) 0.06601g/s 38.02p/s 38.02c/s 38.02C/s michael1..poiuyt
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
john /tmp/hash_jtr.txt --format=ssh 136,21s user 0,04s system 719% cpu 18,947 total
Ce qui est aussi pratique avec JtR, c’est que peu importe le type de clé ou les algorithmes de chiffrement utilisés, la référence à spécifier est toujours la même : ssh
.
Types de clés supportés par JtR et ssh2john
:
Type | JtR | ssh2john |
---|---|---|
DSA | ✅ | ✅ |
RSA | ✅ | ✅ |
ecdsa | ✅ | ✅ |
ed25519 | ✅ | ✅ |
Formats de clé supportés par ssh2john
:
Format | Support |
---|---|
OpenSSH | ✅ |
PEM | ✅ |
PKCS8 | ❌ |
RFC4716 | N/A |
Algorithmes de chiffrement supportés par ssh2john
(possiblement certains algorithmes non supportés par ssh2john
le sont par john
mais aucun outil ne permet de générer le pseudo-haché) :
Algorithme ⬇️ Format ➡️ | OpenSSH (tous) | PEM (DSA, RSA, ecdsa) | PEM (ed25519) |
---|---|---|---|
3des-cbc | ❌ | ✅ | ❌ |
aes128-cbc | ❌ | ✅ | ❌ |
aes128-ctr | ❌ | ✅ | ❌ |
aes128-gcm@openssh.com | ❌ | ✅ | N/T |
aes192-cbc | ❌ | ✅ | ❌ |
aes192-ctr | ❌ | ✅ | ❌ |
aes256-cbc | ✅ | ✅ | ❌ |
aes256-ctr | ✅ | ✅ | ❌ |
aes256-gcm@openssh.com | ❌ | ✅ | N/T |
chacha20-poly1305@openssh.com | ❌ | ✅ | N/T |
Note 📝 : Pour les clés de type ed25519
, sshpk
a été utiliser pour les convertir au format PEM car ssh-keygen
ne peut les exporter qu’au format OpenSSH. Les algorithmes @openssh.com
n’ont pas pu être convertis par sshpk
. sshpk
a été utile dans le cadre de la rédaction de l’article, mais ne le sera pas pour un auditeur, car convertir la clé requiert de connaitre le mot de passe.
Algorithmes de chiffrement supportés par JtR :
Algorithme | Support |
---|---|
3des-cbc | ✅ |
aes128-cbc | ✅ |
aes128-ctr | ✅ |
aes128-gcm@openssh.com | ✅ |
aes192-cbc | ✅ |
aes192-ctr | ✅ |
aes256-cbc | ✅ |
aes256-ctr | ✅ |
aes256-gcm@openssh.com | ✅ |
chacha20-poly1305@openssh.com | ✅ |
En conclusion, ssh2john
ne fonctionne qu’avec 2 algorithmes lorsque la clé privée est au format OpenSSH, ce qui est vraiment dommage, car c’est le format par défaut de ssh-keygen
. Au format PEM, tous les algorithmes sont supportés par ssh2john
pour les clés de type DSA, RSA, ecdsa mais aucun pour les clés de type ed25519.
Hashcat
Comme pour JtR, une très grande durée sépare souvent deux versions de Hashcat. Pour avoir les corrections de bogues ou les nouvelles fonctionnalités, il faudra installer la version git utilisant la branche principale du dépôt. Ainsi, je recommande d’installer la version git de Hashcat (ex : hashcat-git pour ArchLinux).
Tous les tests seront effectués avec la version ci-dessous :
v6.2.6-846-g4d412c8e0+
Le format du pseudo-code de hachage SSH géré par Hashcat semble être celui généré par ssh2john
. Hashcat ne fournit aucun outil à cet effet. Cependant, le format supporté semble être une ancienne version et ne supporte pas le nouveau format requis pour les algorithmes utilisant du Bcrypt PBKDF (bcrypt_pbkdf.3) introduit en 2013 dans OpenSSH.
Contrairement à JtR, Hashcat utilise différents modules et a donc différentes références selon les clés. La distinction est faite selon les numéros d’identification choisis arbitrairement par ssh2john
.
$0$
: module_22911$6$
: module_22921$1$
et$3$
: module_22931$4$
: module_22941$5$
: module_22951$2$
: aucun module
Nous verrons par la suite à quoi correspondent ces numéros dans une section dédiée.
Toutefois, Hashcat ne supporte pas le « nouveau » format de sortie de ssh2john
tel quel : /chemin/fichier:pseudo-haché
. Il faudra donc supprimer le chemin du fichier de sortie. La commande ci-dessous permet de supprimer le chemin de tous les fichiers .jtr
(extension arbitraire) pour une édition en masse.
find . -type f -name '*.jtr' -exec sed -i -E 's/.+://' {} \;
Pour un haché seul, la commande suivante devrait suffire :
ssh2john clé_rsa_aes256-cbc_PEM_demo | cut -d ':' -f 2 > clé_rsa_aes256-cbc_PEM_demo.hc
Types de clés supportés par Hashcat :
Type | HC |
---|---|
DSA | ✅ |
RSA | ✅ |
ecdsa | ✅ |
ed25519 | ❌ |
Il n’y a pas de formats de clé supportés à proprement parler, car Hashcat ne propose pas d’outil de conversion de clé en pseudo-haché, mais repose sur ssh2john
. Les mêmes limitations s’appliqueront donc.
Algorithmes de chiffrement supportés par Hashcat :
Algorithme ⬇️ Type ➡️ | DSA | RSA | ecdsa | ed25519 |
---|---|---|---|---|
3des-cbc | ✅ | ✅ | ✅ | N/A |
aes128-cbc | ✅ | ✅ | ✅ | N/A |
aes128-ctr | ✅ | ✅ | ✅ | N/A |
aes128-gcm@openssh.com | ✅ | ✅ | ✅ | N/A |
aes192-cbc | ✅ | ✅ | ✅ | N/A |
aes192-ctr | ✅ | ✅ | ✅ | N/A |
aes256-cbc | ✅ | ✅ | ✅ | ❌ |
aes256-ctr | ✅ | ✅ | ✅ | ❌ |
aes256-gcm@openssh.com | ✅ | ✅ | ✅ | N/A |
chacha20-poly1305@openssh.com | ✅ | ✅ | ✅ | N/A |
En conclusion, il est difficile de tester ed25519
car ssh2john
a un faible support pour ce type de clé. À la sortie de ssh-keygen
+ ssh2john
, seuls les numéros d’identification $1$
, $2$
, $3$
et $6$
sont sortis. $1$
et $3$
sont gérés par le même module 22931 et semble fonctionner. $1$
est géré par le module 22921, mais ne fonctionne jamais. Le $1$
(AES 256 bits CTR) est sorti uniquement au format OpenSSH pour tous les types de clé. $2$
n’est géré par aucun module Hashcat.
Finalement, le seul module qui est utilisable en pratique est donc le 22931
, les autres correspondent soit à des combinaisons de clé qui ne sont jamais sorties par ssh-keygen
(peut-être OpenSSL ? ou de très vieilles versions d’OpenSSH ?), soit qui ne sont pas gérés par ssh2john
(il faudrait extraire les paramètres cryptographiques de la clé privée et créer un pseudo-haché à la main).
Note 📝 : avec HC impossible de casser la clé de référence ~/.ssh/id_ed25519_crack
générée avec les paramètres par défaut de ssh-keygen
.
Autres outils
À l’instar des archives chiffrées ou des conteneurs de mots de passe KDBX, il n’existe pas vraiment d’outils en dehors de JtR et HC pour casser les clés SSH chiffrées.
Il y a bien ssh-key-crack, outil en C, exécution monofil, abandonné depuis 16 ans, ne gérant que les clés du type RSA et DSA, au format PEM uniquement, directement sur la clé (sans format intermédiaire comme pour JtR et HC avec ssh2john
).
Ou encore, sshPrivateKeyCrack, outil en python, archivé, abandonné depuis 2 ans, n’est qu’un script "naïf" faisant des appels système à ssh-keygen
, supprime le chiffrement de la clé une fois le mot de passe trouvé, mais supporte l’exécution multifil.
Format ssh2john
Le format de pseudo-haché généré par ssh2john
est arbitraire et ne correspond à aucun standard.
Il se décompose comme ci-dessous, avec le nom de fichier et le pseudo-haché séparé par :
:
(fichier:)$sshng$alg_type$len_salt$salt$len_data$data($rounds$ciphertext_begin_offset)
Le pseudo-haché est composé d’une signature sshng
en préfixe et de 5 ou 7 parties délimitées par des $
.
Exemple de haché :
/home/noraj/.ssh/id_ed25519_crack:$sshng$6$16$3843af13aef53d4c0906f2998b082b3d$274$6f70656e7373682d6b65792d7631000000000a6165733235362d6374720000000662637279707400000018000000103843af13aef53d4c0906f2998b082b3d0000001800000001000000330000000b7373682d6564323535313900000020785c404a9750e39a4cdb788e787f13fdf0d62ca91ea76e3034272722980c222d00000090a99a138ebcd23a3fac923d88fb2b42833e4fc29d409efe86d543f8224cd11263b511e6cc858919bb58692a07664fb56905915bfe8d4a31db398827a65070f33dc127c3ca7d2ad9d184922e7a5e657de10166ee6adfc0b4cc736567adaeb8b1a160d008b1e5bd0a0188be18152d8eecec7bbd9b35d8f551e059bc57fa7642b7535a4d1aad8bb616576b9fb6b2e62bb7e5$24$130
La première partie après la signature, correspond à un numéro d’identification (arbitraire) associant type de clé + algorithme de chiffrement.
0
: RSA/DSA + 3DES1
: RSA/DSA + AES-1282
: RSA/DSA/EC + Bcrypt PBKDF + AES-256-CBC3
: EC + AES-1284
: RSA/DSA + AES-1925
: RSA/DSA + AES-2566
: RSA/DSA/EC + Bcrypt PBKDF + AES-256-CTR
À noter que ssh2john
génère quand même un haché avec $1$
pour une clé DSA + 3DES au lieu de $0$
car ssh2john
génère un $0$
uniquement pour une "longueur de clé de 24" (pourquoi sachant que 16, 24 et 32 sont généralement des tailles de clé AES là où 3DES utilise plutôt 112 ou 168 bits ?).
Les parties suivantes correspondent à
- la longueur du sel
- le sel
- la longueur des données
- les données
- optionnellement, le nombre de passes pour
bcrypt_pbkdf
- optionnellement,
ciphertext_begin_offset
pourbcrypt_pbkdf
Étude comparée
Prenons la clé suivante :
- Type : RSA
- Algorithme de chiffrement : AES 256 bits avec mode CBC
- Format : PEM
- Taille : 4096 bits
- Mot de passe :
test12345
(position 385742 dansrockyout.txt
)
➜ ssh-keygen -N test12345 -t rsa -Z aes256-cbc -m PEM -f clé_rsa_aes256-cbc_PEM_demo -b 4096
Generating public/private rsa key pair.
Your identification has been saved in clé_rsa_aes256-cbc_PEM_demo
Your public key has been saved in clé_rsa_aes256-cbc_PEM_demo.pub
The key fingerprint is:
SHA256:zys3VyMJ6r9laWTGgo/QsrsCbaxV1tu3iRR4GlKW80E noraj@norarch
The key's randomart image is:
+---[RSA 4096]----+
| oE |
| = . |
| + + . |
| +.+.=. |
| o oo.SB.o=. |
| . = ++=o=+.o |
| = ....+o== . |
| . . .o +=+ |
| .o. +++ |
+----[SHA256]-----+
➜ ssh2john clé_rsa_aes256-cbc_PEM_demo
clé_rsa_aes256-cbc_PEM_demo:$sshng$1$16$31C54C9A4E9873B4DD6C58DC79B80A6C$2352$7189892c8e079116a1115d3496eb8e17e789e65ce7cbc1b6e0bc03e69034a6bf0f9bfb0d52be414942ae19691c43084ddcf2d3acda121bee07f64e980666c695a2dd713621129cb3490b85369c5233c0613f409c52cc6f9e82eae37dd7113fc3f17d63b6ac09f400bf55a1fd7739e483f02f3c1b6b2c8a13ea22250b0cfff832f7efd309501c5a7188f47d4654372e5ab0191a303765cbb592aaf97f07186edbfcb1b4f9eb0798a395448a64dec5d38eb9db616f2eed80aa94261c513e79b87a495d458a5da75efbc292e7c8c721a41b10f4e775e7d97e43716225bc6162a0665624acee70962d3e8b4eb3dc7d87db653345b1ef6da2beb5f35efc3724d9eac03a94065f6a96c44cd344529a3295e1efec7b218d179780e16f9c49bc8976ae1390e0eb9a885f0245cb9ad8aa4530a343afbdfafd7ae3e04ed5a122abfeedd1860e8ae82a6b3f728472b650bbfe3a7536296af24540c67f79bb13b8b497b1ffea30373d665202e3d80223c5e3f7d19b982a567c6b545392d559f5f42947e0aaec6b16cfb44a53f2cea559a87f0ea6b15bbf25fb3cc7139b66822bd21e91972d4db8d0e894b6472da4246f454d28fe3e05a898d6e1ef4141afaaa52e3b1691eba3be9ebc372262f7c2e2db0b44aa3dbefbc93d85bc69b70456447c06b029809e3c7c7be5511a83be0164d510ebc93bd0e75e971dea579eac03197a9e25f061c075b7934b3a3e8942c9a52d25d260365c9990c0dc7c79d64e868570b9033fdc322cffaa753b4526c7403a47667443942ebe99798a2eb7b228bf00526679856bd2bd0895dd1bb70064c0c8f06cb31d9c95e246cb781f9f701aafcefb6e454e2ffe1e68dbdb1202ca000e0d379be7f9f59ab87dd255f53a0e69e13215fb47bec6158e2cb5341f3ce6c4c51475634150467316b62f5fd9fbfef6ee0d891f595f38cd29724af3efa543ccf16cea9d0c1da5ce430e2112e811ae1a50c6de930722bb0425221fb6ea1f4404fccdda0824043111170c81c0c7311774a577a44fd3529dd848c6bf24920d74f23d4b9bad9a7a7baaab99efcfe35a46bf8234b546bb4fd122876de2a0b61d01b32e05f975f4bd1df0d56c6fc4e64c354f6329908e038899a97f00dd2f0d2aafe57195faa35f3c4943e59757e7262336fdd1972183927225e4097642c3be4152be32c149d20a07f3a07860c6adc0da3a9dd8454362adbeacf296abeb9e9a38ac923235f9c32b6f926e302ba9ed07744602875400e8d0dede22c3232f1a5d7a7c989f55dbba073eff87ac1ef00b2e1e686553c35bd9dc8aff32b1cdc25bf0b99bdeb561b1f39f3812ba33be6b94997edc89a44fe44e728290f9a8bbcdcac05426de57ec85c93e6825cc44aa92c8192485c3300f36fc08cee81babb9778a8653ecd01155018e6e3310629cf21f42b7aa9dbd6ba88bf80bd896c81ad0f426b162e70398dadc610d116decb0b71cc59468a2d14aa678f3e4d33e6fab715a195b2e61ef243a8ddbff50096948f8fc249aba75bde37a2abc9dff3d05a1e8a651f0efe9e24e22441499e7b0068109e3d16073b46dfa1eca94344feabc0959644ae56c330084cd8d05a089beced712da5c33bd3764129433ec1403a4e73d2b3a34173068bd6f5b84bf1e2e53eef9e89a2da217ada0bbd2d13fc4e1d9c24a16973cf0f5c79cc0eb3469716e7b584d8bcb3808aa05376c3a8334b53c5afca68d371688bf7607768c93abca882bd50feef2180c1fb5127ba4d1b9e7fcf0443b058115032b7bf896ad8b43136f124857d518a184e8c69e94b70982797db721fade1686574eb3f9f3d02de8bfd4ed56a43b4f16cc21adac5e517b5e7b15fecf921df9b294a374a4205638a41cc0aafbfe2324b4b862ffeb918bcf65228c736cdb5e9f1b5c440e39732e815ca7e589aa72f77c4b81d94d7e647f01e81022ad25e7d8fb0bcfcec2e01ce2a01c35ee8abfb56fd4c299184d0d0fba1ae08e1284d7f9de90c56616a0304705a9face5503338f0b44621be71643375b0d5b0fcce1f415238332e37dede2115faff839cfef64d2886ec030955d2db7300ac48896334d48ce9fc69285d3558ab2e7fbc12948445ba6ca11c320b3bf7abc937e12ec0f524144cf4a908fff0a6b496c9e23fd03da7f9b87ddd797cec432ac6ba8a48bda0b35559002c04557e7512c7592a2a27274000421ec9822544cb510d63a8d190af9f8ae973e0dcc319d4d34ddfdf6c2d6cc90329192722c78005aa1abe0f8729356d615abfb08daabae633e61eed4c3831869e7d4859ef3a67d1cfb24e8ddd14e5e3e75aaec1eb1c148776e7705533b3188f161fef4ece79a2af9ffa72f0e01c75a47cbe9c276c30eea386db17829c76cdf28fca3dec9a6b1c6bd3776905486b409cce506c6ef080bbc8601981d71a185dfc9fd332522c96b52fbc90d8a76e7dfca06b7d92248bf1aee8e72f115c8d6f519f6361b90cb3b52e8de05322121fb27735b9f1bae76e696aae0a905d41316b05959dd0d8ba5ae1dd5a1b867ea2182d113174f6963e7c83437af8c0da98167795c2725bca59d5cc726e01be0e0d43ae78fbc7cb9d370a26b80a1bf3136e9328752e750d241df3c9973d486e51ce054d0378b834973e22aa21887500a94d3769ac833d1d303236bed07958568b1a5fa8b1efd6eb6f942253feae44b36a1ca55643a2f0469f4997dd0a548bd4f8b24225209e5d7f14ffc2e4f6e995f8ae138015265b8ce28794ac756289900b14049a92c4ba3ceb098d3d50c113911a0f5266c6a9f9d1f55a1fefd6c187127a4f94bc5efdb9812492fbfad0241b4ba3c1f4cb78fd6212bf1718eaf22f509354a8bab7ac05d5e74b2bb640bc4d375b664cd834ffa84301b027126fade04c4dad8c6f9aca3a740ea5206572a9b68558ef8dc8b7f141a5ac2dd6fee7f4237cdfd481ebe6da1298f037ad05fe760ff82fdca30d3d738d8646b7bcfc1ba4db1f26451a29a882b67674495d521a69b7e3ca73d6170778ba168d073f8876ff04f63cee50a240b77b7902c46e489e75bf4c9169eb78906a2b23f3238c5f3f14a0f3a244aab6a65888e1c50c178e3d4a7cfbbb9dcc57dbc3432aacb2fe7e522ffbb11556086646619dd7b8f9ce1a6f3ad8ed37ab633047294a4905f117dad4f0e9d3f21d78dba9647854d252fb923c7065a25ce63cb8a337d38242eca70fff909f5546b80cc2318bde243781d44812918a7f1c1a3c5965e601d219bd62c484762900721f04ff031075068efbca0b02c3e624b2f956a63902f01e04f901bff7a099094c34c61b9abc570faa1962c07ae05ce7372a6f97eb5f46b1b
Voici le temps d’exécution pour retrouver la clé avec les différentes méthodes.
Note 📝 : time
est la version intégrée de ZSH.
Pour le script de l’approche naïve séquentielle, le temps d’exécution est de 32 minutes :
➜ time ruby scripts/ssh-bf.rb /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo /usr/share/wordlists/passwords/rockyou.txt
...
ruby scripts/ssh-bf.rb /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo 1340,63s user 621,71s system 101% cpu 32:21,10 total
Pour le script de l’approche naïve multifil (avec sshPrivateKeyCrack
), le temps d’exécution est d’environ 8 minutes (4 fois moins de temps en parallèle (sur 8 fils) qu’en monofil) :
➜ time python sshCrack.py -f /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo.jtr -w /usr/share/wordlists/passwords/rockyou.txt
Starting with 8 processes...
Working...
✓ test12345 ✓
CRACKED:
/tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo:test12345
python sshCrack.py -f /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo -w 2119,32s user 1008,62s system 656% cpu 7:56,77 total
Pour l’approche JtR (processeur), le temps d’exécution est d’environ 5 secondes :
➜ time john /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo.jtr -w=/usr/share/wordlists/passwords/rockyou.txt --format=ssh
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
test12345 (clé_rsa_aes256-cbc_PEM_demo)
1g 0:00:00:00 DONE (2024-02-14 16:04) 12.50g/s 4822Kp/s 4822Kc/s 4822KC/s teubesk..terminator3
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
john /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo.jtr --format=ssh 18,71s user 0,07s system 371% cpu 5,050 total
Pour l’approche HC (unité graphique), le temps d’exécution est d’environ 3 secondes :
➜ time hashcat -m 22931 /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo.hc /usr/share/wordlists/passwords/rockyou.txt
...
hashcat -m 22931 /tmp/all-keys-ciphers/clé_rsa_aes256-cbc_PEM_demo.hc 0,50s user 1,15s system 47% cpu 3,476 total
Pour conclure, les approches optimisées de JtR et HC sont extrêmement plus rapides de plusieurs ordres de grandeur que les approches naïves faisant des appels à la commande ssh-keygen
. Cependant, ces dernières sont tout de même intéressantes pour les types de clé non supportés par JtR, ssh2john
et HC.
La taquinerie du chef
Pour enquiquiner au maximum les attaquants qui voudraient du mal à la confidentialité de votre clé privée SSH, il serait de bon ton d’avoir une clé de type ed25519
chiffrée avec l’algorithme chacha20-poly1305@openssh.com
. Bonus ? Ce sont le type de clé et l’algorithme de chiffrement les plus robustes disponibles via ssh-keygen
.
ssh-keygen -t ed25519 -Z chacha20-poly1305@openssh.com
Alternativement, cela peut être de stocker sa clé au format PKCS8
avec le type de clé ecdsa
.
ssh-keygen -t ecdsa -Z chacha20-poly1305@openssh.com -m PKCS8
Si toutefois votre clé est de type rsa
, chiffrée avec aes256-cbc
et stockée au format pem
, sachez qu’en tant qu’auditeur je vous remercie et vous souhaite bonne chance.
Plus sérieusement, voici quelques vraies recommandations :
- chiffrez la clé privée,
- positionnez des permissions système en
600
(-rw-------
, vous seul devez pouvoir lire la clé), - le mot de passe de déchiffrement doit être :
- robuste,
- stocké dans un gestionnaire de mot de passe,
- différent de celui de l’utilisateur.
Lexique
Traductions
🇫🇷 | 🇬🇧 |
---|---|
multifil | multithread |
fil d’exécution | thread |
processus fils | fork |
haché | hash |
Acronymes
- JtR : John the Ripper
- HC : Hashcat
- N/A : non applicable
- N/T : non testé
À propos de l’auteur 📝
Article écrit par Alexandre ZANNI alias noraj, Ingénieur en Test d’Intrusion chez ACCEIS.