vsftpd 3.0.5 - Élevé - À distance - Reliquat de privilège - l'option deny_file manque .private/secret
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vsftpd-deny-file-brace-child
Classe : Reliquat de privilège Portée : Distante
vsftpd 3.0.5 - Chris Evans
L'exemple de la page de manuel (vsftpd.conf.5) est deny_file={*.mp3,*.mov,.private}. Les noms correspondants « ne devraient être accessibles d'aucune manière », y compris « le téléchargement, le changement de répertoire, l'affectation de quelque chose à l'intérieur du répertoire ». vsf_access_check_file (access.c:16-43) appelle vsf_filename_passes_filter sur le chemin client tel que fourni, puis str_locate_str du paramètre entier entre accolades. Le filtre correspond au dernier composant / préfixe ; le reliquat /secret échoue ; la sous-chaîne de {*.mp3,*.mov,.private} ne correspond pas.
CWD .private est refusé (le basename correspond). RETR .private/secret et RETR dir/.private réussissent. C'est ce « à l'intérieur du répertoire » que ce reliquat casse.
CVE-2015-1419 est un correctif public de distribution sur realpath/basename. La version officielle 3.0.5 ne l'a jamais intégré. La branche accolades de Debian correspond toujours au chemin complet, donc cette traversée d'enfant subsiste aussi sur les paquets de distribution corrigés. Ne pas re-déposer 2015-1419.
Ce reliquat est un oubli de liste de refus conditionné par la configuration. Ce n'est pas une RCE non authentifiée, pas une évasion de chroot, et pas une lecture de /etc de l'hôte.
| ID | pas encore de CVE |
| Classe | Reliquat de privilège |
| Portée | Distante (FTP authentifié) |
| CWE | CWE-863, CWE-22 |
| CVSS | Élevé : 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Produit | vsftpd (Chris Evans) |
| Affecté | vsftpd 3.0.5 archive officielle SHA-256 26b602ae454b0ba6d99ef44a09b6b9e0dfa7f67228106736df1f278c70bc91d3 |
| Auth | FTP authentifié USER/PASS (anonyme dans le labo). deny_file défini sur une liste entre accolades (non défini par défaut) |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1 uniquement. Anonyme en lecture seule. Fichier témoin. |
Qui : un utilisateur FTP authentifié (anonyme ftp dans le labo). UID de session après l'abandon habituel de vsftpd. deny_file est la politique supplémentaire censée retirer des capacités à cet UID. Les recettes d'utilisateurs virtuels citées par la page de manuel partagent guest_username, donc le DAC Unix ne les sépare pas. La version 3.0.5 standard avec tunable_deny_file NULL n'est pas ce reliquat.
| Méthode + cible | Privilège |
|---|---|
RETR .private/secret avec deny_file={*.mp3,*.mov,.private} documenté entre accolades | handle_retr str_open d'un fichier dont le nom de répertoire figure sur la liste de refus, en tant qu'uid de session. Labo : 150/226, 37 octets, corps VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS |
RETR dir/.private | même cible. Un fichier nommé .private sous un autre répertoire (must_match_at_current_pos rejette une correspondance à l'index > 0). Labo : 150/226, corps DIRDOT-VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS |
vsf_access_check_file ; le labo était en lecture seule)| Méthode + cible | Privilège |
|---|---|
STOR / APPE le même chemin quand write_enable=YES | handle_upload_common crée / écrase en tant qu'uid de session |
DELE / RNTO le même chemin | str_unlink / renommage d'un nom que la liste de refus était censée bloquer |
| Méthode + cible | Privilège |
|---|---|
LIST .private/x (ou LIST à l'intérieur de l'arborescence refusée) | handle_dir_common vérifie l'accès sur l'argument complet (échec), puis str_opendir du préfixe .private après la séparation sur le slash. Noms uniquement. Le DAC Unix s'applique toujours |
| Méthode + cible | Résultat |
|---|---|
CWD .private | 550 Permission denied. Le basename .private correspond aux accolades |
RETR song.mp3 | 550. *.mp3 est un motif de dernier composant et correspond bien |
CWD .private lui-même (le basename correspond)hide_file (basename issu de readdir ; le RETR d'un nom masqué est documenté comme intentionnel)/etc de l'hôte depuis un chroothttp_enable désactivé par défaut ; un GET en mode FTP tue la session)deny_file=.private sans accolades est sauvé par le repli sur sous-chaîne (str_locate_str de .private dans .private/secret)J'ai épinglé la version officielle de vsftpd 3.0.5 (SHA-256 26b602ae...c91d3) plutôt qu'un miroir GitHub ou une arborescence Debian/Fedora. Dix-neuf recherches dans le code source. Le démon compilé par défaut n'a aucun reliquat Critique/Élevé non publié. Celui-ci nécessite que l'opérateur copie l'exemple entre accolades de la page de manuel.
vsf_filename_passes_filter (ls.c) gère * / ? / {,} non imbriqués et ne fait un travail utile que sur un motif de dernier composant. Pour le nom .private/secret face à {*.mp3,*.mov,.private} :
*.mp3, *.mov, .private sont comparées au début de .private/secret. Le reliquat /secret échoue sauf si le jeton était *.{*.mp3,*.mov,.private} et ne trouve rien.Fausse piste déjà publique : CVE-2015-1419 est un correctif realpath propre aux distributions. Le Changelog officiel ne contient aucun correctif de ce type. Même la branche accolades de Debian copie le chemin normalisé complet, donc les enfants passent toujours.
cd lab
./run.sh
Contrôle loopback 127.0.0.1:18710, PASV 18711-18718. Projet Compose vsftpd-deny-file-brace-child. Archive officielle 3.0.5, anonyme en lecture seule, deny_file={*.mp3,*.mov,.private}. Témoin VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS. Dernière ligne :
SUCCESS vsftpd-deny-file-brace-child cwd-dotprivate=550 retr-child=yes retr-dir-dotprivate=yes mp3=550 VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS
Faire correspondre les alternatives entre accolades à chaque composant du chemin, ou appliquer realpath / basename avant le filtre (avec les réserves habituelles sur les liens symboliques). L'exemple documenté devrait réellement refuser les enfants.
Le canal de réception du fournisseur est [email protected] (vsftpd). Ne pas ouvrir d'issue GitHub publique sur un miroir vsftpd.