
Reproduzierbares Docker-Labor + Raw-Socket-Exploit für CVE-2015-3306 (ProFTPD mod_copy Pre-Auth beliebiges Dateikopieren) — eine Lernübung zum Patch-Diffing
Ein vollständig reproduzierbares Labor und ein handgeschriebener Exploit für CVE-2015-3306 — aufgebaut als Lernübung in Schwachstellenforschung: Patch-Diffing, manuelles Auslösen und Raw-Socket-Exploit-Entwicklung.
Das mod_copy-Modul von ProFTPD implementiert das SITE CPFR / SITE CPTO-
Befehlspaar, das Dateien serverseitig kopiert, ohne
Daten an den Client zu übertragen.
In Version 1.3.5 prüfte keiner der beiden Handler, ob die Sitzung authentifiziert war. Das Modul ging einfach davon aus, „niemand wird SITE-Befehle vor dem Login senden" — eine kaputte Annahme, die zu einer CVE wurde. Jeder nicht authentifizierte Client konnte jede für den Serverprozess lesbare Datei an jeden für ihn beschreibbaren Ort kopieren.
Der Fix (Commit 212d54271f, veröffentlicht in 1.3.5a) tut zwei Dinge:
copy_cpfr und hinzu:
copy_cptoauthenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
if (authenticated == NULL || *authenticated == FALSE) {
pr_response_add_err(R_530, _("Please login with USER and PASS"));
errno = EPERM;
return PR_ERROR(cmd);
}
CopyEngine on|off-Direktive hinzu — zuvor konnte das Modul in
Builds, die es auslieferten, nicht einmal deaktiviert werden.Der vollständige Unified-Diff befindet sich in patch.diff. Das Lesen von Patches
ist die Fähigkeit: Der Fix verrät dir, wo die Wunde war.
Das Dockerfile kompiliert ProFTPD 1.3.5 (die letzte verwundbare Version) aus
dem offiziellen Quell-Tarball mit aktiviertem mod_copy:
docker build -t proftpd-135 .
docker run -d --name lab135 -p 127.0.0.1:2121:21 -p 127.0.0.1:30000-30010:30000-30010 proftpd-135
docker exec lab135 chmod 777 /home/ftp
PassivePorts in proftpd.conf fixiert den Datenkanal — die Zwei-Kanal-Architektur
von FTP (Steuerkanal + dynamischer Datenkanal) ist der Grund, warum naive
Container-Mappings scheitern: Der Steuerport funktioniert, der Datenport nicht.
exploit.py verwendet Raw-Sockets — kein ftplib, weil Bibliotheken das
Protokoll verbergen, und das Verbergen des Protokolls ist genau das, wogegen wir kämpfen:
SITE CPFR /etc/segredo.txt -> 350 (kein USER/PASS gesendet: das IST der Bug)
SITE CPTO /home/ftp/... -> 250 (beliebige Kopie ausgeführt)
USER ftp / PASS ... -> 230 (Login ist nur der Exfiltrationspfad)
PASV / RETR -> 150 -> 226 (Flag erbeutet)
DELE -> 250 (Bereinigung: keine IOCs hinterlassen)
AllowOverwrite, Port-Mappings) entscheidet über die endgültige Auswirkung.time.time_ns(), nicht time.time()), und keine Abhängigkeit
von hinterlassenem Zustand.RETR antwortet zweimal: 150,
dann 226. Beide abwarten, bevor der nächste Befehl kommt.-d10) genau,
welche Prüfung ausgelöst wurde.Nur für Bildungszwecke und autorisierte Labornutzung. Die Ausführung gegen Systeme, die du nicht besitzt oder für die du keine schriftliche Testgenehmigung hast, ist illegal.