Skip to Content

Jouons avec FTP

Suite à une discussion sur IRC, je me suis remis à m’amuser avec le protocole FTP.
J’en profite pour faire un topo rapide.

C’est quoi FTP

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.

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.

Comment fonctionne FTP

FTP fonctionne sur deux canaux. Un canal pour les commandes et l’autre canal pour les données.

Nous supposons que nous avons :

  •  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.
  •  le premier client, appelé victime, a pour ip 192.168.0.2
  •  le deuxième client, appelé attaquant, a pour ip 192.168.0.3

    Sur le client, nous allons nous connecter sur le serveur ftp avec telnet :

    victime$ telnet 192.168.0.1 21
    Trying 192.168.0.1...
    Connected to 192.168.0.1.
    Escape character is '^]'.
    220 ProFTPD 1.2.8 Server (ProFTPD Default Installation) [gnunux.gnunux.info]

    Commençons pour nous identifier :

    USER gnunux
    331 Password required for gnunux.

    Comme indiqué, il faut mettre son mot de passe :

    PASS motdepasse
    230 User gnunux logged in.

    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.

    Maintenant passons aux choses sérieuses. Pour l’instant nous sommes restés dans le canal commande.

    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.

    mode passif

    En mode passif, faisons :

    PASV
    227 Entering Passive Mode (192,168,0,1,6,130).

    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).

    Depuis une autre console :

    victime$ telnet 192.168.0.1 1666
    Trying 192.168.0.1...
    Connected to 192.168.0.1.
    Escape character is '^]'.

    Le telnet est en attente. Il faut demander au serveur de transmettre des données depuis le canal de commande :

    LIST
    150 Opening ASCII mode data connection for file list
    226 Transfer complete.

    Dans la fenêtre du canal de donnée nous avons la liste des fichiers des répertoires courant qui s’affiche :

    drwx------   2 gnunux   users        4096 Nov 13 20:02 Amis
    -rw-------   1 gnunux   users       37035 Nov 24 11:28 Autre
    drwx------   4 gnunux   users        4096 Nov 13 19:35 Contact
    drwx------   4 gnunux   users        4096 Jan  1 23:05 Lettre
    drwx------   4 gnunux   users        4096 Jan  1 23:05 Liste
    drwx------   2 gnunux   users        4096 Jan  1 23:05 Travail
    Connection closed by foreign host.

    mode actif

    Choisissons un port supérieur à 1023 au hazard ... disons 1867

    Sur le client écoutons sur ce port avec netcat :
    victime$ nc -l -p 1867

    Enfin calculons les valeurs utilisées pour définir le port :

    victime$ echo "1867/256" |bc
    7
    victime$ echo "1867%256" |bc
    75

    Le port 1867 est donc 7,75.

    Passons donc en mode actif :

    PORT 192,168,0,2,7,75
    200 PORT command successful
    LIST
    150 Opening ASCII mode data connection for file list

    Vous pouvez voir que la liste des répertoires est affichée dans la console contenant netcat.

    Usurpation du canal de donnée

    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.

    Il est facile de récuperer des données d’une session d’une autre personne.

    Pour la suite, nous allons utiliser un petit script que j’ai écrit :

    GZ - 709 octets
    ftp_passif.py.gz
    Script python de ma composition à décompresser (gunzip ftp_passif.py.gz) et à rendre exécutable (chmod +x ftp_passif.py).
    victime$ ./ftp_passif.py

    Dans une autre console, tape :
    telnet 192.168.0.1 1818

    Comme indiqué dans une autre console, il suffit de taper "telnet 192.168.0.1 1818" pour voir le contenu du répertoire.

    Refaire l’expérience mais en faisant le telnet sur le deuxième client :

    attaquant$ telnet 192.168.0.1 1818
    Trying 192.168.0.1...
    Connected to 192.168.0.1.
    Escape character is '^]'.
    drwx------   2 gnunux   users        4096 Nov 13 20:02 Amis
    -rw-------   1 gnunux   users       37035 Nov 24 11:28 Autre
    drwx------   4 gnunux   users        4096 Nov 13 19:35 Contact
    drwx------   4 gnunux   users        4096 Jan  1 23:05 Lettre
    drwx------   4 gnunux   users        4096 Jan  1 23:05 Liste
    drwx------   2 gnunux   users        4096 Jan  1 23:05 Travail

    Le rebond FTP (ou bounce FTP)

    Le rebond FTP est une technique de test de port d’une machine tiers en utilisant le protocole FTP.

    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.

    Pour la suite, nous allons utiliser un petit script que j’ai écrit :

    GZ - 659 octets
    ftp_actif.py.gz
    Script python de ma composition à décompresser (gunzip ftp_actif.py.gz) et à rendre exécutable (chmod +x ftp_actif.py).

    Sur le premier client faire :
    victime$ nc -l -p 1982

    et dans une autre console :

    victime$ ./ftp_actif.py 192.168.0.2 1982
    port ouvert

    Sur un port fermé nous aurons :

    victime$ ./ftp_actif.py 192.168.0.2 1983
    port ferme

    Attention, il est très rare que les serveurs FTP acceptent des ports privilégiés (inférieur a 1024) comme port de destination.

    Maintenant si nous modifions l’ip, il est possible de s’assurer qu’un port est ouvert ou non.
    Sur le premier client, faire :

    victime$ nc -l -p 1672

    et sur le deuxième client :

    ./ftp_actif.py 192.168.0.3 1672
    port ouvert.

    Se protéger

    Avec proftpd, il suffit de mettre l’option "AllowForeignAddress" à "off".

  • Fichier attachéTaille
    ftp_actif.py.gz659 octets
    ftp_passif.py.gz709 octets

    Commentaires

    > Jouons avec FTP

    J’ai résolu le problème avec gzip ;)

    > Jouons avec FTP

    Il serait bien si on pouvait mettre en attachement de fichier python :/