Comment coder un programme Brute Force en PHP ?

Introduction au Brute Force avec une mise en pratique concrète.

→ Corrigé du Challenge : Détermination de mot de passe

Qu’est ce que la méthode « brute force » ?

Une méthode dite « brute force » consiste à tester toutes les solutions possibles jusqu’à trouver la bonne. Quand il n’est pas possible d’écrire un algorithme pour atteindre de façon ordonnée la solution, alors il reste la possibilité de tester tous les cas possibles !

Dans le challenge SECURITY_1, c’est la solution qu’il faut utiliser. On est en effet face à des hashs. Le hash est le résultat d’un algorithme de chiffrage appliqué à une chaîne de caractères donnée. Ces algorithmes ont la spécificité de ne fonctionner que dans un sens. Je peux chiffrer une chaîne de caractères, mais je ne pourrais pas la déchiffrer.

Donc le seul moyen de trouver la chaîne de caractères du départ est de tester toutes les variantes possibles.

Ici, on a une règle plutôt basique, avec un nombre de cas maîtrisé.

Si la personne s’appelle « Néo Anderson », alors les mots de passe possibles sont :

  • neoAND@10A
  • neoAND@10B
  • neoAND@10C
  • neoAND@10Z
  • neoAND@11A
  • neoAND@11B
  • neoAND@35L
  • neoAND@35M
  • neoAND@99Z

Il n’y a que les 3 derniers caractères qui changent, 2 chiffres et une lettre.

  • Le premier chiffre va de 1 à 9 => 9 possibilités
  • Le deuxième chiffre va de 0 à 9 => 10 possibilités
  • La lettre va de A à Z => 26 possibilités

Ce qui donne : 9 x 10 x 26 => 2 340 possibilités à tester.

Le challenge va proposer une dizaine de personnes à tester, soit environ 23 400 combinaisons (maximum) à tester.

Même si ce nombre peut paraître important, on est là sur une volumétrie qui nécessite peu de temps de calcul.

Pour ce programme brute force en PHP : du parsing et des boucles

$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
foreach ($informations as $information) {

	[$firstName, $lastName, $xCompany, $extension, $hash] = preg_split('/[.@:]/', $information);

	$passStart = strtolower($firstName) . strtoupper(substr($lastName, 0, 3)) . '@';

	for ($randomNumber = 10; $randomNumber <= 99; $randomNumber++) {
		for ($indexLetter = 0; $indexLetter < 26; $indexLetter++) {

			$pass = $passStart . $randomNumber . $alphabet[$indexLetter];

			if ($hash === hash('sha256', $pass)) {
				break 3;
			}
		}
	}
}

Un peu d’explications :

  • Je crée un alphabet contenant les lettres majuscules (utile pour la lettre finale du mot de passe)
  • Le foreach me permet de parcourir le jeu de données, $information étant la chaîne de caractères complète, par exemple : neo.anderson@XXXXXXXX.com:1e9c2741b46b3264c5173a274527ac0f8904ed84fe6e44fd24e8a777d7d99f52
  • J’utilise un preg_split qui me permet de séparer ma chaîne de caractères selon une expression régulière. Je précise dans cette expression régulière mes 3 séparateurs : « . » « @ » et « : ». J’utilise une mutli attribution pour ne pas avoir à passer par une variable intermédiaire.
  • Je crée le début de mon mot de passe, qui est fixe, ici neoAND@. J’utilise strtolower pour passer en minuscule. strtoupper pour passer en majuscule. Et substr pour prendre une portion de ma chaîne de caractères, ici 3 caractères à partir de l’index 0 (= du début de ma chaine).
  • Je crée une première boucle pour la valeur numérique de 10 à 99 inclus
  • Puis une seconde boucle, de 0 à 26 exclus qui sont les indices de mon alphabet
  • Je concatène pour avoir le mot de passe complet
  • Je hashe ce mot de passe et je le compare au hash contenu dans les informations
  • S’il y a une correspondance, c’est que j’ai terminé, plus besoin de tester les autres cas. Le break 3 me permet ici de « casser » mes 3 boucles, les 2 for et le foreach

Le brute force correspond donc à mes 2 boucles for enchainées qui vont tester les 2340 cas avant de passer à la ligne suivante.

On est là sur un cas qui peut avoir l’air basique mais ce sont ces méthodes qui peuvent être utilisées par des hackers qui réussissent à mettre leur main sur des bases de données. Les mots de passe sont (normalement) toujours chiffrés mais un brute force bien pensé peut permettre de craquer des mots de passe dits faibles, c’est à dire des mots de passe que l’on peut « deviner » :

  • Mots de passe courant : « azerty », « password », « 1234567890 », « 123soleil », etc. il existe des listes des 100 ou 1000 mots de passe les + courant.
  • Des combinaisons des informations du prénom et du nom : « neoAND », « neoanderson », « anderson123 »
  • Des mots de passe trop courts, même s’ils sont aléatoires : « fe34 », « k1l0 », « x3x21 » car il n’y aura finalement pas de tant de combinaisons à tester

Il y a bien sûr plein de façons de se protéger de la technique du brute force, que ce soit au moment du chiffrement, en ajoutant une clé, c’est-à-dire une chaîne supplémentaire, ou en ayant des mots de passe complexes, longs, avec des caractères spéciaux, ce qui aura tendance à rendre le brute force beaucoup trop long à réaliser.

Enfin, ce corrigé se veut une introduction au concept de brute force. C’est un sujet très complexe qui ne s’applique d’ailleurs pas qu’à la thématique des mots de passe. Si le sujet t’intéresse… Google est ton ami 😉

Pour le fun, une variante sans $alphabet

foreach ($informations as $information) {

	[$firstName, $lastName, $xCompany, $extension, $hash] = preg_split('/[.@:]/', $information);

	$passStart = strtolower($firstName) . strtoupper(substr($lastName, 0, 3)) . '@';

	for ($randomNumber = 10; $randomNumber <= 99; $randomNumber++) {
		
		$letter = 'A';

		for ($indexLetter = 0; $indexLetter < 26; $indexLetter++) {

			$pass = $passStart . $randomNumber . $letter;

			if ($hash === hash('sha256', $pass)) {
				break 3;
			}

			$letter++;
		}
	}
}

La différence se trouve ici dans l’incrémentation d’une lettre !

En effet, le code ci-dessous est tout à fait fonctionnel :

$letter = 'A';
$letter++;

echo $letter; // affiche "B"

Va + loin


Qui a codé ce superbe contenu ?

Keep learning

Autres contenus à découvrir


Ta newsletter chaque mois

Corrigés, challenges, actualités, veille technique... aucun spam.