;

Si vous aimez aller à WordCamps comme moi, vous avez probablement déjà entendu ceci: « Le hachage de mot de passe WordPress n’est pas sûr », ou dans la version la plus technique: « …parce qu’il est basé sur md5 « .

Vrai ou non, un hachage de mot de passe fort est crucial pour un grand écosystème comme celui de WordPress, qui a toujours été une cible juteuse pour les pirates. J’ai donc décidé d’examiner de plus près le système de hachage et d’essayer de casser les hachages WordPress à partir de zéro!

Comprendre les hachages de mots de passe WordPress

J’ai commencé à faire des recherches sur Google et j’ai constaté que la plupart des informations disponibles sont génériques et déroutantes. Beaucoup de références aux bibliothèques PHP utilisées (hash portable de phpass), mais rien de vraiment concret.

J’ai décidé d’adopter une approche différente à partir d’une hypothèse:

le hachage est un processus à sens unique, mais WordPress est en quelque sorte capable d’authentifier les utilisateurs correspondant à leur entrée de mot de passe avec le hachage stocké dans la base de données

À partir de là, j’ai commencé à vérifier le code et j’ai trouvé la première fonction intéressante: wp_check_password($password,$hash) qui compare le mot de passe en texte brut avec le hachage et renvoie true s’ils correspondent.

1// presume the new style phpass portable hash.
2if ( empty( $wp_hasher ) ) {
3 require_once ABSPATH . WPINC . '/class-phpass.php';
4 // By default, use the portable hash from phpass.
5 $wp_hasher = new PasswordHash( 8, true );
6}
7
8$check = $wp_hasher->CheckPassword( $password, $hash );
9
10/** This filter is documented in wp-includes/pluggable.php */
11return apply_filters( 'check_password', $check, $password, $hash, $user_id );

En parcourant le code, cela nous amène rapidement à CheckPassword, crypt_private et encode64, ce qui est essentiellement l’endroit où la magie se produit.

Pour faire court, crypt_private($password, $stored_hash) re-hachage le mot de passe avant qu’il ne soit comparé au hachage stocké. S’ils correspondent, le mot de passe est correct et l’authentification se poursuit. Ce qui signifie que nous pouvons également utiliser cette fonction pour casser le hachage.

Anatomie du hachage

Ceci est un hachage WordPress:

1$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1

Pour plus de simplicité, nous supposerons que le site utilise PHP > 5 et le dernier hachage portable phpass, qui est la configuration la plus courante.

Les 3 premiers caractères $P$ sont un ID, indiquant au système le type de hachage oh que nous avons.

Le caractère numéro 3 (à partir de 0) est utilisé pour déterminer combien de fois le md5() doit traiter la chaîne d’entrée.

Les caractères de 4 à 12 nPVO4gP9 sont le sel, qui est une chaîne aléatoire ajoutée au mot de passe avant le hachage, pour lui donner plus de caractère aléatoire. Par exemple, si votre mot de passe est admin, il est transformé en nPVO4gP9admin puis haché.

La partie restante du hachage JUMSAM1WlLTHPdH6EDj4e1 est le caractère aléatoire réel, généré par le mot de passe salt + passé dans une fonction encode64 non documentée, qui effectue certaines opérations au niveau du bit sur la chaîne d’entrée et renvoie une sortie de 22 caractères.

Pas si clair, euh? Reste avec moi.

Jusqu’à présent, nous savons:

  • la première partie du hachage est un id fixe
  • la seconde est un seul caractère utilisé comme compteur, également fixe
  • la troisième est le sel, lié au mot de passe
  • le dernier est aléatoire, généré par ‘salt + pass’ traité par la fonction encode64
1

Ainsi, nous pouvons réécrire la logique – sel + mot de passe haché X fois et passé dans encode64 – pour effectuer une attaque de dictionnaire ou de bruteforce, et obtenir la même « dernière partie » du hachage et ce serait une fissure de hachage réussie!

Dans un scénario réel, et les pirates seraient plus intéressés à trouver des mots de passe faibles car ils sont plus susceptibles d’être réutilisés, au lieu de ceux aléatoires qui sont souvent générés par un gestionnaire de mots de passe et donc spécifiques au site.

Réécriture de l’encode64 en utilisant golang

J’ai décidé d’utiliser golang car il est très rapide et nous avons besoin de toute cette vitesse pour calculer de gros dictionnaires de mots de passe.

Tout comme dans la procédure de cryptage WordPress, le script prend le hachage et isole le sel, puis il compose le mot de passe (salt + pass) en essayant chaque mot de passe du dictionnaire et md5 – hachage X nombre de fois, et nous avons vu comment X est déterminé.

1itoa64 := "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
2hashloop := 1 << strings.Index(itoa64, string(hash)); // char n. 4 in the hash

Cela fait, il effectue une série d’opérations au niveau du bit sur des octets obtenus en utilisant ord() en PHP, dont nous n’avons pas besoin dans golang car nous avons déjà des valeurs d’octets:

1itoa64 & 0x3f]

À ce stade, j’ai réalisé que nous n’avions même pas besoin de trouver toute la chaîne. Il suffit de faire correspondre quelques caractères pour faire correspondre tout le mot de passe et rendre le script plus performant! Donc, en raison de la nature du processus de hachage, si char n. 0 / 4 / 8 … correspond, le mot de passe passé en entrée est correct.

Et BOUM, nous avons craqué le hachage:

1wphashcrash '$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1' Dev/wphashcrash/dict.txt
2$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1 admin
32020/05/30 12:44:15 Executed in 0.000221

Le code est comme d’habitude sur GitHub – https://github.com/francescocarlucci/wphashcrash – et pour le moment, le script est un POC et n’obtient qu’un seul hachage de mot de passe en entrée, et le chemin d’accès au dictionnaire de mots de passe.

J’ai déjà décrit dans le readme quelques améliorations qui seraient bien d’avoir et que j’ajouterai probablement à l’avenir.

Si vous voulez vraiment essayer de pirater une liste de hachages, vous pouvez la forker ou simplement envelopper le script dans une boucle bash for.

Considérations de sécurité

À ce stade, je pense qu’il est assez clair que si un attaquant accède à la base de données sur un site WordPress, il peut fondamentalement casser chaque mot de passe faible.

Ce malheureux, surtout parce que:

  • L’injection SQL n’est pas si rare dans les plugins WordPress
  • RCE accordera également très probablement l’accès à la base de données
  • L’écosystème WordPress est un vaste territoire pour le travail des pigistes et il est très courant de trouver des comptes wp-admin et FTP anciens / inutilisés, créés pour des besoins temporaires

Ce dernier point, combiné à l’énumération des utilisateurs qu’un problème courant WordPress, laisse la porte ouverte à l’accès à la base de données en utilisant des informations d’identification d’administrateur volées / mises en gage.

En plus de cela, de nombreux sites Web n’appliquent pas de mots de passe forts pour ne pas nuire à l’expérience utilisateur, et j’ai une expérience directe de l’un des points mentionnés.

Une fois qu’un site Web est compromis, le stockage de hachages faibles permet aux attaquants de compromettre d’autres comptes d’utilisateurs sur d’autres sites, s’ils ont tendance à réutiliser les mots de passe et nous savons qu’ils le font.

Avons-nous des solutions ?

Mes recherches ne sont pas allées aussi loin, je voulais seulement voir comment casser les hachages WordPress.

Bcrypt est connu pour être une méthode de hachage plus puissante que md5, et il existe un plugin existant qui utilise bcrypt et remplace toutes les fonctions de base nécessaires pour gérer les mots de passe:

  • wp_check_password()
  • wp_hash_password()
  • wp_set_password()

Et bien sûr, vous pouvez écrire votre propre solution en tant que développeur, mais je pense que c’est un problème à résoudre au niveau de base pour viser une adoption massive.

Note finale

Il existe de nombreux outils pour casser les hachages, comme Hashcat et John The Ripper, qui peuvent être encore plus performants, mais encore une fois, la portée de cette recherche est de comprendre la structure de hachage WordPress et de la fissurer à partir de zéro.

Merci d’avoir lu.

frenxi

Write a Comment

Votre adresse e-mail ne sera pas publiée.