<p class="spip">Suite à une discussion sur IRC, je me suis remis à m’amuser avec le protocole FTP.
J’en profite pour faire un topo rapide.</p>

<h2>C’est quoi FTP</h2>
<p class="spip">Comme son nom l’indique, FTP (File Transfer protocol) est un protocole de transport de fichiers. Il fonctionne en TCP contrairement à d’autres protocoles comme le TFTP qui fonctionnent en UDP.</p>

<p class="spip">Mais FTP, outre d’être difficile à administrer (pour le firewall notamment), est peu sécurisé. Nous verrons par la suite les limites de ce protocole. Il est a noter que la plupart des serveurs FTP actuels (et heureusement) permettent de limiter les problèmes.</p>

<h2>Comment fonctionne FTP</h2>
<p class="spip">FTP fonctionne sur deux canaux. Un canal pour les commandes et l’autre canal pour les données.</p>

<p class="spip">Nous supposons que nous avons :
<br /></p>
<li> un serveur FTP avec comme ip 192.168.0.1 sur le port 21. Le nom d’utilisateur est gnunux avec comme mot de passe : motdepasse.
<br /><li> le premier client, appelé victime, a pour ip 192.168.0.2
<br /><li> le deuxième client, appelé attaquant, a pour ip 192.168.0.3
<p class="spip">Sur le client, nous allons nous connecter sur le serveur ftp avec telnet :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>victime$ telnet 192.168.0.1 21<br />
Trying 192.168.0.1...<br />
Connected to 192.168.0.1.<br />
Escape character is '^]'.<br />
220 ProFTPD 1.2.8 Server (ProFTPD Default Installation) [gnunux.gnunux.info]<br />
</code></div>
<p class="spip">Commençons pour nous identifier :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>USER gnunux<br />
331 Password required for gnunux.<br />
</code></div>
<p class="spip">Comme indiqué, il faut mettre son mot de passe :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>PASS motdepasse<br />
230 User gnunux logged in.<br />
</code></div>
<p class="spip">Nous voilà connecté sur le serveur ! Nous pouvons maintenant découvrir les commandes de base en faisant "HELP". Par exemple "PWD" nous donne le répertoire courant, "SYST" nous donne le type de système.</p>

<p class="spip">Maintenant passons aux choses sérieuses. Pour l’instant nous sommes restés dans le canal commande.</p>

<p class="spip">FTP fonctionne en mode passif ou en mode actif. Dans le premier cas, le serveur ouvre un port non privilégié (supérieur à 1023) en attendant que le client se connecte sur le canal de donnée. Dans le deuxième cas, le client ouvre un port en attendant que le serveur se connecte depuis le port 20. Etudions dans la pratique ce que cela donne.</p>

<h3>mode passif</h3>
<p class="spip">En mode passif, faisons :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>PASV<br />
227 Entering Passive Mode (192,168,0,1,6,130).<br />
</code></div>
<p class="spip">Ici nous avons l’ip du serveur (192.168.0.1) et le port 6,130 (c’est bien des "," et non des "."). Pour calculer le port, il faut faire : 6x256+130 (donc 1666).</p>

<p class="spip">Depuis une autre console :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>victime$ telnet 192.168.0.1 1666<br />
Trying 192.168.0.1...<br />
Connected to 192.168.0.1.<br />
Escape character is '^]'.<br />
</code></div>
<p class="spip">Le telnet est en attente. Il faut demander au serveur de transmettre des données depuis le canal de commande :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>LIST<br />
150 Opening ASCII mode data connection for file list<br />
226 Transfer complete.<br />
</code></div>
<p class="spip">Dans la fenêtre du canal de donnée nous avons la liste des fichiers des répertoires courant qui s’affiche :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>drwx------   2 gnunux   users        4096 Nov 13 20:02 Amis<br />
-rw-------   1 gnunux   users       37035 Nov 24 11:28 Autre<br />
drwx------   4 gnunux   users        4096 Nov 13 19:35 Contact<br />
drwx------   4 gnunux   users        4096 Jan  1 23:05 Lettre<br />
drwx------   4 gnunux   users        4096 Jan  1 23:05 Liste<br />
drwx------   2 gnunux   users        4096 Jan  1 23:05 Travail<br />
Connection closed by foreign host.<br />
</code></div>
<h3>mode actif</h3>
<p class="spip">Choisissons un port supérieur à 1023 au hazard ... disons 1867</p>

<p class="spip">Sur le client écoutons sur ce port avec netcat :
<code class='spip_code' dir='ltr'>victime$ nc -l -p 1867
</code></p>

<p class="spip">Enfin calculons les valeurs utilisées pour définir le port :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>victime$ echo "1867/256" |bc<br />
7<br />
victime$ echo "1867%256" |bc<br />
75<br />
</code></div>
<p class="spip">Le port 1867 est donc 7,75.</p>

<p class="spip">Passons donc en mode actif :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>PORT 192,168,0,2,7,75<br />
200 PORT command successful<br />
LIST<br />
150 Opening ASCII mode data connection for file list<br />
</code></div>
<p class="spip">Vous pouvez voir que la liste des répertoires est affichée dans la console contenant netcat.</p>

<h2>Usurpation du canal de donnée</h2>
<p class="spip">Il est facile de constater qu’aucun mécanisme ne permet de s’identifier sur le canal des données. Le serveur se contente de répondre à la première personne qui s’y connecte.</p>

<p class="spip">Il est facile de récuperer des données d’une session d’une autre personne.</p>

<p class="spip">Pour la suite, nous allons utiliser un petit script que j’ai écrit :</p>

<dl class='spip_document_130 spip_documents spip_documents_center' >
<dt><a href="http://download.tuxfamily.org/assocoagul/drupal-files/spip/ftp_passif.py.gz" title='GZ - 709 octets' type="application/x-gzip"><img src='dist/vignettes/gz.png' width='52' height='52' alt='GZ - 709 octets' /></a><dt>
<dt class='spip_doc_titre' style='width:120px;'><strong>ftp_passif.py.gz</strong></dt>
<dd class='spip_doc_descriptif' style='width:120px;'>Script python de ma composition à décompresser (gunzip ftp_passif.py.gz) et à rendre exécutable (chmod +x ftp_passif.py).</dd>
</dl>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>victime$ ./ftp_passif.py<br />
<br />
Dans une autre console, tape :<br />
telnet 192.168.0.1 1818<br />
</code></div>
<p class="spip">Comme indiqué dans une autre console, il suffit de taper "telnet 192.168.0.1 1818" pour voir le contenu du répertoire.</p>

<p class="spip">Refaire l’expérience mais en faisant le telnet sur le deuxième client :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>attaquant$ telnet 192.168.0.1 1818<br />
Trying 192.168.0.1...<br />
Connected to 192.168.0.1.<br />
Escape character is '^]'.<br />
drwx------   2 gnunux   users        4096 Nov 13 20:02 Amis<br />
-rw-------   1 gnunux   users       37035 Nov 24 11:28 Autre<br />
drwx------   4 gnunux   users        4096 Nov 13 19:35 Contact<br />
drwx------   4 gnunux   users        4096 Jan  1 23:05 Lettre<br />
drwx------   4 gnunux   users        4096 Jan  1 23:05 Liste<br />
drwx------   2 gnunux   users        4096 Jan  1 23:05 Travail<br />
</code></div>
<h2>Le rebond FTP (ou bounce FTP)</h2>
<p class="spip">Le rebond FTP est une technique de test de port d’une machine tiers en utilisant le protocole FTP.</p>

<p class="spip">Le principe est d’ouvrir, en mode actif, une connexion sur un port spécifique d’un autre machine (avec la commande PORT). Si le port est ouvert, le serveur FTP considérera que les données ont été transmis. Sinon une erreur sera retournée.</p>

<p class="spip">Pour la suite, nous allons utiliser un petit script que j’ai écrit :</p>
<dl class='spip_document_129 spip_documents spip_documents_center' >
<dt><a href="http://download.tuxfamily.org/assocoagul/drupal-files/spip/ftp_actif.py.gz" title='GZ - 659 octets' type="application/x-gzip"><img src='dist/vignettes/gz.png' width='52' height='52' alt='GZ - 659 octets' /></a><dt>
<dt class='spip_doc_titre' style='width:120px;'><strong>ftp_actif.py.gz</strong></dt>
<dd class='spip_doc_descriptif' style='width:120px;'>Script python de ma composition à décompresser (gunzip ftp_actif.py.gz) et à rendre exécutable (chmod +x ftp_actif.py).</dd>
</dl>
<p class="spip">Sur le premier client faire :
<code class='spip_code' dir='ltr'>victime$ nc -l -p 1982
</code></p>

<p class="spip">et dans une autre console :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>victime$ ./ftp_actif.py 192.168.0.2 1982<br />
port ouvert<br />
</code></div>
<p class="spip">Sur un port fermé nous aurons :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>victime$ ./ftp_actif.py 192.168.0.2 1983<br />
port ferme<br />
</code></div>
<p class="spip">Attention, il est très rare que les serveurs FTP acceptent des ports privilégiés (inférieur a 1024) comme port de destination.</p>

<p class="spip">Maintenant si nous modifions l’ip, il est possible de s’assurer qu’un port est ouvert ou non.
Sur le premier client, faire :</p>

<p class="spip"><code class='spip_code' dir='ltr'>victime$ nc -l -p 1672
</code></p>

<p class="spip">et sur le deuxième client :</p>
<div style='text-align: left;' class='spip_code' dir='ltr'><code>./ftp_actif.py 192.168.0.3 1672<br />
port ouvert.<br />
</code></div>
<h2>Se protéger</h2>
<p class="spip">Avec proftpd, il suffit de mettre l’option "AllowForeignAddress" à "off".</p>