
Lab Docker reproductible + exploit raw-socket pour CVE-2015-3306 (ProFTPD mod_copy copie arbitraire de fichiers avant authentification) — un exercice d'apprentissage du patch-diffing
Un laboratoire entièrement reproductible et un exploit écrit à la main pour CVE-2015-3306 — conçu comme un exercice d'apprentissage en recherche de vulnérabilités : analyse de correctifs, déclenchement manuel et développement d'exploit par socket brute.
Le module mod_copy de ProFTPD implémente la paire de commandes SITE CPFR / SITE CPTO,
qui copie des fichiers côté serveur sans transférer de données au client.
Dans la version 1.3.5, aucun des deux gestionnaires ne vérifiait si la session était authentifiée. Le module supposait simplement « personne n'enverra de commandes SITE avant de se connecter » — une hypothèse erronée qui est devenue une CVE. Tout client non authentifié pouvait copier n'importe quel fichier lisible par le processus serveur vers n'importe quel emplacement accessible en écriture par celui-ci.
Le correctif (commit 212d54271f, publié dans la version 1.3.5a) fait deux choses :
copy_cpfr et copy_cpto :
authenticated = 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 — auparavant, le module ne pouvait même pas
être désactivé dans les builds qui l'incluaient.Le diff unifié complet se trouve dans patch.diff. Lire les correctifs est
la compétence clé : le correctif vous indique où se trouvait la blessure.
Le Dockerfile compile ProFTPD 1.3.5 (la dernière version vulnérable) à partir de
l'archive source officielle avec mod_copy activé :
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 dans proftpd.conf épingle le canal de données — l'architecture
à deux canaux de FTP (contrôle + données dynamiques) est la raison pour laquelle les
mappages de conteneurs naïfs échouent : le port de contrôle fonctionne, le port de données non.
exploit.py utilise des sockets brutes — pas de ftplib, car les bibliothèques masquent
le protocole, et masquer le protocole est exactement ce contre quoi nous luttons :
SITE CPFR /etc/segredo.txt -> 350 (aucun USER/PASS envoyé : c'est LE bug)
SITE CPTO /home/ftp/... -> 250 (copie arbitraire effectuée)
USER ftp / PASS ... -> 230 (la connexion n'est que le chemin d'exfiltration)
PASV / RETR -> 150 -> 226 (drapeau capturé)
DELE -> 250 (nettoyage : aucun IOC laissé derrière)
AllowOverwrite, mappages de ports) détermine l'impact final.time.time_ns(), pas time.time()), et aucune dépendance
à un état résiduel.RETR répond deux fois : 150,
puis 226. Videz les deux avant la commande suivante.-d10) vous indique exactement
quelle vérification a été déclenchée.Pour l'éducation et une utilisation en laboratoire autorisée uniquement. Exécuter cela contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation écrite de test est illégal.