vsftpd 3.0.5 - Hoch - Remote - Privilege leftover - brace deny_file misses .private/secret
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vsftpd-deny-file-brace-child
Klasse: Privilegien-Überbleibsel Reichweite: Remote
vsftpd 3.0.5 - Chris Evans
Das Beispiel in der Manpage (vsftpd.conf.5) lautet deny_file={*.mp3,*.mov,.private}. Passende Namen „sollten in keiner Weise zugänglich sein", einschließlich „Download, Wechsel in das Verzeichnis, Beeinflussung von etwas innerhalb des Verzeichnisses". vsf_access_check_file (access.c:16-43) ruft vsf_filename_passes_filter auf den übergebenen Client-Pfad auf und dann str_locate_str des gesamten Brace-Tunables. Der Filter gleicht die letzte Komponente / das Präfix ab; das übrig bleibende /secret schlägt fehl; die Teilzeichenkette von {*.mp3,*.mov,.private} wird nicht gefunden.
CWD .private wird verweigert (Basename trifft). RETR .private/secret und RETR dir/.private gelingen. Genau dieses „innerhalb des Verzeichnisses" bricht dieses Überbleibsel.
CVE-2015-1419 ist ein öffentlicher Distro-realpath/Basename-Patch. Das offizielle 3.0.5 hat ihn nie übernommen. Debian's Brace-Zweig gleicht weiterhin den vollständigen Pfad ab, sodass dieser Child-Walk auch auf gepatchten Distro-Paketen bestehen bleibt. 2015-1419 nicht erneut melden.
Dieses Überbleibsel ist ein konfigurationsgesteuerter Deny-List-Fehlschlag. Es ist kein Unauth-RCE, kein Chroot-Ausbruch und kein Host-/etc-Read.
| ID | noch keine CVE |
| Klasse | Privilegien-Überbleibsel |
| Reichweite | Remote (authentifiziertes FTP) |
| CWE | CWE-863, CWE-22 |
| CVSS | Hoch: 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Produkt | vsftpd (Chris Evans) |
| Betroffen | vsftpd 3.0.5 offizielles Tarball SHA-256 26b602ae454b0ba6d99ef44a09b6b9e0dfa7f67228106736df1f278c70bc91d3 |
| Auth | authentifiziertes FTP USER/PASS (anonym im Lab). deny_file auf eine Brace-Liste gesetzt (standardmäßig nicht gesetzt) |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1. Anonym schreibgeschützt. Witness-Datei. |
Wer: ein authentifizierter FTP-Benutzer (anonym ftp im Lab). Session-UID nach dem üblichen vsftpd-Drop. deny_file ist die zusätzliche Richtlinie, die dieser UID eigentlich Fähigkeiten entziehen sollte. Virtual-User-Rezepte, die die Manpage nennt, teilen guest_username, sodass Unix-DAC sie nicht trennt. Stock 3.0.5 mit tunable_deny_file NULL ist nicht dieses Überbleibsel.
| Methode + Sink | Privileg |
|---|---|
RETR .private/secret mit dokumentiertem Brace deny_file={*.mp3,*.mov,.private} | handle_retr str_open einer Datei, deren Verzeichnisname auf der Deny-Liste steht, als Session-UID. Lab: 150/226, 37 Bytes, Body VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS |
RETR dir/.private | gleicher Sink. Eine Datei namens .private unter einem anderen Verzeichnis (must_match_at_current_pos lehnt einen Treffer bei Index > 0 ab). Lab: 150/226, Body DIRDOT-VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS |
vsf_access_check_file-Gate; Lab war schreibgeschützt)| Methode + Sink | Privileg |
|---|---|
STOR / APPE desselben Pfads bei write_enable=YES | handle_upload_common Erstellen / Überschreiben als Session-UID |
DELE / RNTO desselben Pfads | str_unlink / Umbenennen eines Namens, den die Denylist stoppen sollte |
| Methode + Sink | Privileg |
|---|---|
LIST .private/x (oder LIST innerhalb des verweigerten Baums) | handle_dir_common prüft den vollständigen Parameter auf Zugriff (Fehlschlag), dann str_opendir des .private-Präfixes nach dem Slash-Split. Nur Namen. Unix-DAC gilt weiterhin |
| Methode + Sink | Ergebnis |
|---|---|
CWD .private | 550 Permission denied. Basename .private trifft das Brace |
RETR song.mp3 | 550. *.mp3 ist ein Last-Component-Muster und trifft zu |
CWD .private selbst (Basename trifft)hide_file LIST-Verbergen des Dirents (Basename aus readdir; RETR eines verborgenen Namens ist dokumentiert beabsichtigt)/etc aus einem Chroothttp_enable standardmäßig aus; FTP-Mode GET beendet die Session)deny_file=.private wird durch den Substring-Fallback gerettet (str_locate_str von .private in .private/secret)Ich habe offizielles vsftpd 3.0.5 (SHA-256 26b602ae...c91d3) gepinnt statt eines GitHub-Mirrors oder eines Debian/Fedora-Baums. Neunzehn Quellcode-Suchen. Der standardmäßig kompilierte Daemon hat kein unveröffentlichtes Critical/High-Überbleibsel. Dieses erfordert, dass der Betreiber das Brace-Beispiel aus der Manpage kopiert.
vsf_filename_passes_filter (ls.c) gleicht * / ? / nicht verschachtelte {,} ab und leistet nur bei einem Last-Component-Muster nützliche Arbeit. Für den Namen .private/secret gegen {*.mp3,*.mov,.private}:
*.mp3, *.mov, .private werden am Anfang von .private/secret abgeglichen. Das übrig bleibende /secret schlägt fehl, es sei denn, das Token war *.{*.mp3,*.mov,.private} und findet nichts.Bereits öffentliche Fehlspur: CVE-2015-1419 ist ein reiner Distro-realpath. Das offizielle Changelog enthält keinen solchen Fix. Selbst Debian's Brace-Zweig kopiert den vollständigen normalisierten Pfad, sodass Kinder weiterhin durchlaufen.
cd lab
./run.sh
Loopback-Control 127.0.0.1:18710, PASV 18711-18718. Compose-Projekt vsftpd-deny-file-brace-child. Offizielles 3.0.5-Tarball, anonym schreibgeschützt, deny_file={*.mp3,*.mov,.private}. Witness VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS. Letzte Zeile:
SUCCESS vsftpd-deny-file-brace-child cwd-dotprivate=550 retr-child=yes retr-dir-dotprivate=yes mp3=550 VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS
Brace-Alternativen gegen jede Pfadkomponente abgleichen oder realpath / Basename vor dem Filter (mit den üblichen Symlink-Vorbehalten). Das dokumentierte Beispiel sollte Kinder tatsächlich verweigern.
Vendor-Intake ist [email protected] (vsftpd). Kein öffentliches GitHub-Issue auf irgendeinem vsftpd-Mirror öffnen.
Abraxas Labs - abraxaslabs.tech - github.com/abraxas - @abraxas_null - [email protected]