Douze constats, six familles
Un cabinet d'audit teste le site d'une PME et rend un rapport de douze constats. Ils semblent sans lien : une page d'erreur, un lien étrange, un nom de fichier dans une adresse.
Un bon auditeur lit la liste et voit six familles. Chaque famille a une cause et un remède. Cette leçon apprend à ranger les constats par famille.
La règle unique
Attention
Ce laboratoire est un site volontairement fragile. Attaquez votre copie privée, et rien d'autre : elle n'a aucune sortie vers Internet. Attaquer un système qui n'est pas le vôtre, ou sans permission de test, est un délit dans presque tous les pays.
À la fin de cette leçon
Remarque
Je peux associer une page vulnérable à la classe de faille qu'elle montre.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Classe de faille | une famille de faiblesses qui ont la même cause | |
| Injection | un texte tapé qui est lu comme une partie d'une commande ou d'une requête | |
| Traversée de chemin | un nom de fichier qui sort du dossier où il devrait rester | ../ |
| Redirection ouverte | un lien qui envoie le visiteur vers n'importe quelle adresse donnée | |
| Entrée | tout ce qu'un visiteur tape ou envoie à une page | |
| Point d'arrivée | l'endroit du programme où une valeur est enfin utilisée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Suivez l'entrée jusqu'à son point d'arrivée
La plupart des failles suivent un même schéma. Une valeur arrive d'un visiteur. Elle traverse le programme. Elle atteint un point d'arrivée, où elle sert.
La classe de la faille dépend de ce point d'arrivée. Posez une seule question à toute page : où finit ce que je tape ?
Exemple travaillé : point d'arrivée et classe
| Où finit la valeur | Classe de faille | Le remède en une ligne |
|---|---|---|
| Dans une requête à la base | Injection SQL | L'envoyer comme paramètre |
| Dans la page que dessine le navigateur | Script intersite | L'échapper à la sortie |
| Dans un nom de fichier que le serveur ouvre | Traversée de chemin | N'accepter que les noms d'une liste |
| Dans une commande que le serveur lance | Injection de commande | Ne jamais fabriquer une commande avec du texte |
| Dans une adresse vers laquelle on envoie le visiteur | Redirection ouverte | N'accepter que vos propres adresses |
| Comme numéro sans contrôle du propriétaire | Contrôle d'accès défaillant | Vérifier le propriétaire à chaque fois |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Chaque classe laisse une trace dans la requête
On devine souvent la classe d'après une seule requête. Un nom de fichier avec ../ évoque une traversée de chemin. Une balise dans une valeur évoque un XSS. Une valeur redirect= qui contient une adresse complète évoque une redirection ouverte.
Pour classer, il ne faut rien lancer. On lit la requête et on se demande à quoi sert la valeur.
Exemple travaillé : cinq requêtes inventées
| Requête | Classe |
|---|---|
| /lire?fichier=../../etc/hosts | Traversée de chemin |
| /accueil?nom=<i>Bo</i> | Script intersite |
| /sortie?redirect=http://autre.example | Redirection ouverte |
| /chercher?id=5 UNION SELECT 1 | Injection SQL |
| /outils?hote=a.example; cat notes | Injection de commande |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Regardez le site du laboratoire
Votre laboratoire fait tourner Mutillidae, un site plein de failles volontaires. Démarrez-le, puis lancez ces trois commandes dans l'ordre.
La première se connecte avec le compte du laboratoire et garde la connexion dans un fichier. La deuxième cherche ce compte par son nom et son mot de passe. La troisième cherche un nom que le site n'a pas. Les trois sont un usage ordinaire.
Se connecter avec le compte du laboratoire
curl -s -c jar -d "username=admin&password=adminpass&login-php-submit-button=Login" -o /dev/null -w "%{http_code} %{redirect_url}\n" "http://www/index.php?page=login.php"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Chercher un compte
curl -s -b jar -c jar -G "http://www/index.php" --data-urlencode "page=user-info.php" --data-urlencode "username=admin" --data-urlencode "password=adminpass" --data-urlencode "user-info-php-submit-button=View Account Details" | grep -o "[0-9]* records found"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Chercher un nom absent
curl -s -b jar -c jar -G "http://www/index.php" --data-urlencode "page=user-info.php" --data-urlencode "username=personne" --data-urlencode "password=rien" --data-urlencode "user-info-php-submit-button=View Account Details" | grep -o "[0-9]* records found"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Ce que disent les trois réponses
La première affiche 302 et une adresse qui se termine par AU1 : le site a accepté la connexion. La deuxième affiche 1 records found. La troisième affiche 0 records found.
La page compte donc les lignes que renvoie sa requête. C'est un point d'arrivée : le nom que vous tapez entre dans une requête à la base. Pour quelle classe la tester ? Vérifiez votre réponse dans le tableau plus haut.
Une erreur fréquente
Attention
Beaucoup pensent qu'une seule liste de mots interdits arrête toutes les classes. C'est faux : chaque classe a un autre point d'arrivée, donc son propre remède. Un filtre contre les balises script ne fait rien contre un nom de fichier. Réglez chaque point d'arrivée comme sa classe l'exige.
Une même cause sous la plupart des classes
Injection, XSS, traversée et les autres ont une cause commune. Un programme mélange des données et des instructions, et la couche suivante ne sait plus les distinguer.
Le remède est la même idée à chaque fois : garder les données dans leur voie, par des paramètres, de l'échappement ou des listes permises. Mutillidae a les niveaux de sécurité 0, 1 et 5, pour voir la même page avec et sans le remède.
Pour aller plus loin : un encodage double
Le devoir décode %2e et %2f. Un attaquant peut encoder deux fois : le % devient %25, et ../ s'écrit %252e%252e%252f. Les règles du devoir classent /lire?fichier=%252e%252e%252fsecret comme normale.
Une fois le devoir réussi, copiez classer dans un bloc de code à vous. Ajoutez le remplacement qui l'attrape, au bon endroit dans la liste. Expliquez ensuite pourquoi un vrai serveur décode l'adresse une seule fois, avant tout contrôle.