Au début de mon apprentissage en cybersécurité web, la vulnérabilité de parcours de répertoire me semblait étonnamment simple. Comment une manipulation basique de noms de fichiers pouvait-elle entraîner des conséquences aussi graves ? Pourtant, après des heures passées à tester des applications réelles en laboratoire, j'ai constaté que cette simplicité même la rendait extrêmement dangereuse. Les développeurs la sous-estiment, les filtres ne la détectent pas toujours, et avant qu'on ne s'en rende compte, un attaquant peut lire les fichiers les plus sensibles d'un serveur.
Cet article vous expliquera la nature du parcours de répertoire, où le repérer, comment le tester à l'aide de cinq techniques de contournement distinctes, et enfin, comment automatiser sa détection avec Python.
Qu'est-ce que le pacrours de répertoire ?
Le parcours de répertoire, également connu sous le nom de "Path Traversal" ou "Directory Traversal", est une faille permettant à un attaquant d'accéder à des fichiers et répertoires situés en dehors du répertoire racine de l'application web. En manipulant les références de chemin d'accès aux fichiers, un agresseur peut explorer l'arborescence des dossiers du serveur et lire des fichiers arbitraires.
La cible la plus fréquente sur les systèmes Linux est le fichier /etc/passwd. Ce fichier standard contient les informations des comptes utilisateurs, est lisible par n'importe quel utilisateur, et constitue une preuve de concept parfaite pour confirmer une traversée réussie de l'arborescence. Les conséquences vont de la fuite d'informations (code source, fichiers de configuration, identifiants) à une compromission complète du serveur (si l'attaquant peut écrire des fichiers ou accéder à une logique applicative sensible).
Où trouver les vulnérabilités de parcours de répertoire ?
Les failles de parcours de répertoire se manifestent généralement dans les fonctionnalités qui traitent les opérations sur les fichiers. Voici les emplacements les plus courants à inspecter :
- Chargeurs d'images : Applications affichant des images basées sur un paramètre de nom de fichier (ex: images de produits, avatars, galeries).
- Fonctionnalités de téléchargement de fichiers : Tout point d'entrée qui permet à un utilisateur de télécharger un fichier en spécifiant son nom ou son chemin.
- Visionneuses de documents : Lecteurs PDF, générateurs de rapports ou toute fonction chargeant dynamiquement des documents.
- Moteurs de modèles : Systèmes qui chargent des modèles basés sur une entrée utilisateur.
- Gestionnaires de téléchargement de fichiers : Parfois, le nom du fichier lui-même peut être manipulé lors du processus de téléversement.
- Instructions d'inclusion/requête : Particulièrement dans les anciennes applications PHP où l'entrée utilisateur est passée à
include()ourequire().
L'essentiel est de rechercher tout paramètre qui semble faire référence à un fichier : filename, file, path, template, page, document, ou même des noms de paramètres personnalisés comme img, doc ou resource.
Tester le parcours de répertoire : 5 scénarios réels
Passons à la pratique. Je vais vous présenter cinq scénarios que j'ai rencontrés lors d'exercices sur la Web Security Academy de PortSwigger. Chaque scénario représente un mécanisme de défense différent et la manière de le contourner.
Scénario 1 : Le cas simple
Le premier scénario est le plus direct. L'application accepte un paramètre filename et l'utilise directement pour charger une image. Pas de filtre, pas de validation, juste une confiance totale dans l'entrée utilisateur.
Une requête vulnérable ressmeble à ceci :
GET /image?filename=product.jpg
Pour l'exploiter, il suffit de remplacer le nom du fichier par une séquence de parcours de répertoire :
GET /image?filename=../../../etc/passwd
La séquence ../ indique au serveur de remonter d'un répertoire. En enchaînant trois de ces séquences, nous naviguons depuis le répertoire des images, en passant par le répertoire racine web, jusqu'au répertoire /etc du système.
Découverte : En interceptant la requête d'image dans Burp Suite, j'ai noté le paramètre filename et l'ai immédiatement testé avec le payload de parcours classique. La réponse a retourné le contenu complet de /etc/passwd, sans aucune résistance.
Scénario 2 : Contournement par chemin absolu
Le deuxième scénario est plus délicat. L'application bloque complètement les séquences de parcours comme ../. Toute tentative de les utiliser entraîne une erreur ou un refus de la requête.
Mais la question est : si l'application bloque les chemins relatifs, qu'en est-il des chemins absolus ?
Plutôt que d'essayer de naviguer vers le haut dans les répertoires, nous pouvons simplement indiquer au serveur l'emplacement exact :
GET /image?filename=/etc/passwd
Cela a fonctionné. L'application était trop concentrée à bloquer ../ pour se soucier de valider les chemins absolus.
Découverte : Après que mon payload initial ../ ait été bloqué, j'ai essayé différentes variantes. Lorsque j'ai utilisé le chemin absolu /etc/passwd, l'application a docilement fourni le fichier. Cela m'a appris que les filtres sont souvent incomplets – ils bloquent une chose mais en oublient une autre.
Scénario 3 : Suppression non récursive
Le troisième scénario implique un filtre qui supprime la séquence ../ de l'entrée. À première vue, cela semble une défense solide. Mais le filtre a un défaut fatal : il ne s'exécute qu'une seule fois.
C'est-à-dire, si j'envoie ../../../etc/passwd, le filtre supprime les séquences ../, laissant etc/passwd, ce qui ne fonctionnera pas.
Mais si je les imbrique ? Et si j'envoie ....// au lieu de ../ ?
Lorsque le filtre supprime ../ de ....//, il reste à nouveau ../. Mon payload devient donc :
GET /image?filename=....//....//....//etc/passwd
Le filtre a supprimé les caractères intermédiaires, mais les caractères restants ont formé une séquence de parcours valide.
Découverte : Après avoir réalisé que le filtre supprimait ../, j'ai essayé différentes configurations. La méthode d'imbrication a fonctionné car le filtre n'était pas récursif – il ne scannait l'entrée qu'une seule fois et ne vérifiait pas ce qu'il restait après la suppression.
Scénario 4 : Double encodage URL
Le quatrième scénario est plus complexe. L'application bloque les séquences de parcours de répertoire, puis effectue un décodage URL sur l'entrée avant de l'utiliser.
C'est un schéma courant dans les applications web : décoder l'entrée, la valider, puis l'utiliser. Mais l'ordre est crucial.
Si l'application décode *après* la validation, je peux contourner le filtre en double-encodant mon payload. Voici comment :
- Normal :
../ - Encodé URL une fois :
%2e%2e%2f - Encodé URL deux fois :
%252e%252e%252f
Lorsque j'envoie la version doublement encodée, la validation voit %252e%252e%252f, qui ne ressemble pas à une séquence de parcours. Elle passe la validation. Ensuite, l'application décode une fois, ce qui la transforme en %2e%2e%2f. Enfin, lorsque l'application l'utilise, le serveur web la décode à nouveau, la transformant en ../.
Mon payload :
GET /image?filename=..%252f..%252f..%252fetc/passwd
Découverte : J'ai remarqué que mes séquences de parcours normales étaient bloquées, mais lorsque j'ai essayé l'encodage URL, le comportement a légèrement changé. Cela m'a indiqué que l'application effectuait une forme de décodage. J'ai ensuite tenté le double encodage, et cela a complètement contourné le filtre.
Scénario 5 : Contournement de la validation de chemin
Le cinquième scénario est le plus réaliste. L'application valide que le chemin fourni commence par un répertoire attendu : /var/www/images/.
C'est en fait une bonne pratique de sécurité, mais mal implémentée. L'application vérifie le préfixe, mais ne normalise pas ensuite le chemin.
Je peux donc satisfaire la validation en incluant le préfixe attendu, puis en traversant à partir de celui-ci :
GET /image?filename=/var/www/images/../../../etc/passwd
L'application voit le début /var/www/images/ et l'approuve. Mais lorsque le chemin est résolu, les séquences ../ naviguent depuis ce répertoire vers /etc.
Découverte : J'ai noté que l'application rejetait les chemins qui ne commençaient pas par /var/www/images/. J'ai donc inclus ce préfixe dans mon payload, puis j'y ai ajouté les séquences de parcours. La validation a réussi, et la traversée a fonctionné.
Scénario bonus : Contournement par octet nul (systèmes hérités)
Il existe une autre technique qui mérite d'être mentionnée, bien qu'elle ne fonctionne que sur les systèmes plus anciens. Certaines applications valident que le nom du fichier se termine par une extension spécifique, comme .png ou .jpg.
Sur les systèmes hérités (en particulier les anciennes versions de PHP), vous pouvez contourner cette restriction en utilisant un octet nul (%00). L'octet nul termine une chaîne de caractères dans les fonctions C sous-jacentes, de sorte que tout ce qui suit est ignoré.
Payload :
GET /image?filename=../../../etc/passwd%00.png
L'application voit le .png à la fin et l'approuve. Mais lors de la lecture réelle du fichier, l'octet nul tronque la chaîne à /etc/passwd.
Remarque : Cette technique n'est plus efficace sur les systèmes modernes, mais reste utile à connaître pour les applications plus anciennes.
Comment corriger les failles de parcours de répertoire
Maintenant que nous avons vu comment exploiter le parcours de répertoire, parlons de la manière de le corriger.
La meilleure solution : N'utilisez jamais directement l'entrée utilisateur dans les chemins de fichiers. Utilisez plutôt des identifiants ou des index mappés à des noms de fichiers côté serveur. Par exemple :
GET /image?id=123
Le serveur recherche l'ID 123 dans une base de données et récupère le nom de fichier correspondant. L'utilisateur ne contrôle jamais le chemin réel.
Si l'entrée utilisateur est impérative :
- Validez l'entrée par rapport à une liste blanche de fichiers autorisés.
- Normalisez le chemin (résolvez tous les
../et les liens symboliques). - Vérifiez que le chemin normalisé reste à l'intérieur du répertoire attendu.
- Utilisez une API de fichiers sécurisée qui empêche la traversée.
Voici un exemple conceptuel en Java :
import java.io.File;
import java.io.IOException;
public class UtilitaireFichierSecurise {
// Répertoire de base autorisé pour les opérations sur les fichiers
private static final String REPERTOIRE_BASE_FICHIERS = "/var/www/data_app/";
public static File obtenirFichierAvecSecurite(String cheminUtilisateur) throws IOException, SecurityException {
// Crée un objet File combinant le répertoire de base et l'entrée utilisateur
File fichierPotentiel = new File(REPERTOIRE_BASE_FICHIERS, cheminUtilisateur);
// Récupère le chemin canonique pour résoudre toutes les séquences "../" et les liens symboliques
String cheminCanonique = fichierPotentiel.getCanonicalPath();
// Vérifie que le chemin canonique résultant commence toujours par le répertoire de base sécurisé
if (!cheminCanonique.startsWith(REPERTOIRE_BASE_FICHIERS)) {
// Si le chemin sort du répertoire de base, c'est une tentative de traversée
throw new SecurityException("Accès à un chemin non autorisé détecté.");
}
// Le chemin est sûr, renvoie le fichier pour des opérations ultérieures
return fichierPotentiel;
}
// Exemple d'utilisation (non inclus dans la fonction réelle, juste pour illustration)
// public static void main(String[] args) {
// try {
// File fichierImage = obtenirFichierAvecSecurite("images/photo.jpg");
// System.out.println("Chemin sûr : " + fichierImage.getAbsolutePath());
// // Utilisation du fichier...
//
// // Tentative d'exploitation
// obtenirFichierAvecSecurite("../../../etc/passwd"); // Lancerait une SecurityException
// } catch (IOException | SecurityException e) {
// System.err.println("Erreur : " + e.getMessage());
// }
// }
}
Cette approche garantit que, quelles que soient les astuces utilisées par un attaquant, le chemin final doit impérativement rester dans le répertoire de base.
Réflexions finales
Le parcours de répertiore est une de ces vulnérabilités qui, malgré sa simplicité apparente, présente une infinité de variations dans le monde réel. Chaque application implémente ses propres filtres et validations, ce qui exige créativité et persévérance de la part de l'auditeur.
Le plus important : testez toujours de manière éthique. N'intervenez que sur les applications pour lesquelles vous avez l'autorisation, que ce soit via des programmes de bug bounty, des missions de test d'intrusion, ou des laboratoires d'entraînement comme la Web Security Academy de PortSwigger.