Nous allons voir ici comment monter un serveur ftp anonyme que nous sécuriserons en le chrootant et en utilisant les possibilités de restriction par ip source de xinetd et de tcpd.
Introduction :Pourquoi avoir choisi OpenBSD pour monter ce serveur ftp? Cet article décrit l'installation et la configuration d'un serveur ftp avec plusieurs moyens de le sécuriser. Il essaie d'avoir une portée générale et j'espère qu'après lecture de cet article et des pages de manuel auxquelles il fait référence, vous serez capable d'installer de la même manière n'importe quel démon ftp sous n'importe quel OS Unix-like. Cependant, afin de donner des exemples plus précis, la référence à un OS particulier devient pratiquement incontournable. Aussi cet article se concentrant sur l'aspect sécurité, le choix d'OpenBSD, réputé dans ce domaine me semble particulièrement adapté.
Comme annoncé en introduction, nous allons chrooter le démon ftp et tout
ce qui l'accompagne dans une racine différente de celle du système de la
machine. Ainsi si par malheur une faille dans le démon permettait à une
personne mal intentionnée de s'introduire sur la machine,celle-ci se
retrouverait cloisonnée dans le dossier dans lequel est chrooté le service et
dans lequel nous aurons pris soin de ne laisser que le strict
minimum afin que le hacker potentiel ne dispose pas des commandes
nécessaires pour nuire.
Créons donc une arborescence, c'est à dire un ensemble de dossiers, pour
accueillir la racine dans laquelle tournera le notre démon ftp. Choisissons
par exemple d'enfermer ce service dans le répertoire /jail/ftp/ créons donc ce
répertoire :
# mkdir /jail
# mkdir /jail/ftp
Nous devons ensuite créer dans ce dossier les répertoires nécessaires au bon fonctionnement des démons, à savoir dev/ pour les fichier périphériques virtuels, etc/ pour les fichier de configuration, lib/ pour les bibliothèques partagées, usr/ pour loger les démon et leurs bibliothèques propres dans 3 sous répertoires usr/sbin/, usr/lib/ et usr/share/ et enfin var/ avec le sous répertoire log pour mettre les fichiers de traces. Et oui, ceux ci ne pourront pas être inclus avec les autres log dus système car nos démons ne pourront pas y accéder! Tous ces répertoires seront créés à l'aide de la commande mkdir comme ci-dessus.
Vous me direz, cela est l'arborescence traditionnelle de n'importe quel système Unix, et vous n'auriez pas tord! Peut-être penseriez-vous "pourquoi ne pas la modifier pour tenter de déconcerter un pirate éventuel? Car un pirate éventuel ne se laissera pas si facilement avoir! Si ces changement peuvent permettre de gagner quelques minutes, ils n'empêcheront pas l'attaque et auras en contrepartie un surcroît de travail colossal de mise en place et de maintenance par la suite. Le chroot ne vise pas à cacher le mode d'administration en le rendant plus obscure mais permet de cloisonner le service et donc ses utilisateurs dans un environnement restreint avec un nombre de commandes limité.
Ceci suppose que les trois démons dont nous avons besoin (xinetd, tcpd, vsftpd)
soient installés sur votre système. Vous connaissez bien sur la commande cp
et savez l'utilisez. Vous connaissez également whereis
qui permet de
localiser un fichier binaire dans le PATH . Vous avez alors entre les mains
tous les éléments pour réaliser cette étape de cette manière.
# whereis xinetd
xinetd: /usr/sbin/xinetd /etc/xinetd.d /etc/xinetd.conf /usr/man/man8/xinetd.8.gz
/usr/share/man/man8/xinetd.8.gz
# cp /usr/sbin/xinetd /jail/ftp/usr/sbin
Cette méthode présente sur une machine dédiée l'avantage de ne pouvoir installer au
niveau système que le strict minimum*. Les démons n'existeront alors
que dans l'environnement chrooté.
*NB : pour limiter encore ce qui est installé sur le système, les démons peuvent être
compilés sur une autre machine avec le CFLAGS approprié à la machine hôte.
Là on fait vraiment dans le classique : On récupère l'archive source, on la décompresse, on exécute le configure et make. On copie ensuite le binaire dans /jail/ftp/usr/sbin. Dans la console cela donne :
# tar xvzf xinetd-VERSION.tar.gz
# cd xinetd-version
# ./configure
# make
# cp ./xinetd/xinetd /jail/ftp/usr/sbin
Peut-être me demanderez-vous pourquoi ne pas exécuter ./configure --prefix=/jail/ftp/usr/ puis make install ? pour la simple et bonne raison que cela copierait des binaires, des bibliothèques, des pages mans... dont le démon n'a nul besoin pour fonctionner et qui sont potentiellement autant de failles de sécurité. Il est vrai qu'il a peu de chose et de risque dans ce cas mais la méthode pour chrooter un service peut-être généralisée.
Ça se complique ? En fait, pas tellement.
La procédure ressemble. Là encore, décompresser l'archive source. Mais là, pas de
configure, éditez le Make-file à la main pour préciser un REAL_DAEMON_DIR valide.
taper ensuite make sys-type où sys-type représente le noyau de votre système
d'exploitation. Copier ensuite de même le binaire.
C'est le plus simple de la bande car un make dans le dossier obtenu après avoir décompressé les sources suffit. Copier ensuite le binaire. Précisez tout de même auparavant quelques options dans builddefs.h; nous utiliseront ici particulièrement tcp_wrapper (n'oubliez pas de le définir).
ldd est votre amie. ldd est une commande qui permet de lister les librairies partagées nécessaires au fonctionnement d'un binaire. Faites donc :
# ldd /jail/ftp/usr/sbin/xinetd
# ldd /jail/ftp/usr/sbin/tcpd
# ldd /jail/ftp/usr/sbin/vsftpd
Copier ensuite la liste de bibliothèques donnée depuis /lib dans /jail/ftp/lib
Si cela suffisait ce serait bien simple! Malheureusement ce n'est pas le cas. En
effet si vous essayer d'entrer dans le chroot et d'y lancer xinetd vous vous
heurterez à des problèmes. Il à besoin d'autres bibliothèques non listées par ldd et
de périphériques qu'il va falloir reconstruire!
Pour voir tout cela, on utilise la commande strace qui montre tous les appels
systèmes engendrés par une commande, et vous verrez, il y en a beaucoup! Si vous
voulez retrouvez ça par vous même, ne vous privez pas, mais là je vous aide et vous
dit tout :
xinetd et tcpd ont besoin des libnss, des périphériques tty, null et urandom, des
libwrap.so (à copier depuis les sources compilées de tcpd dans /jail/ftp/usr/lib) et
enfin des ld.so.cache. En pratique cela donne:
# cp /lib/libnns* /jail/ftp/lib/
# mknod /jail/ftp/dev/null c 1 3
# mknod /jail/ftp/dev/tty c 5 0
# mknod /jail/ftp/dev/urandom 1 9
# cp /etc/ld.so.cache /jail/ftp/etc/
Les serveurs ftp sont nombreux, pourquoi s'attarder particulièrement sur vsftpd ? Parce qu'il s'appelle vsftpd comme Very Secure FTP Daemon et que sont suggère la sécurité, mise en avant dans cet article ? Pas seulement, un nom ne suffit pas encore doit-il être justifié. Voici quelques atouts dont dispose vsftpd :
2 possibilité s'offrent à vous :
C'est cette deuxième possibilité que nous aborderons car elle semble plus claire,
même lorsque xinetd n'a qu'un service à gérer.
notre fichier etc/xinetd.conf ressemblera donc à :
défauts
{
instances = 200
log_type = FILE /var/log/xinetd.log
log_on_success = HOST PID
log_on_failure = HOST
}
includedir /etc/xinetd.d/
service ftp
{
flags = REUSE NAMEINARGS
socket_type = stream
wait = no
protocol = tcp
user = root
server = /usr/sbin/tcpd
server_args = vsftpd
nice = 0
disable = no
bind = 192.168.0.10
port = 21
log_type = FILE /var/log/xinetd/vsftpd.log
log_on_success = PID HOST DURATION
log_on_failure = HOST
}
Je vous invite vivement à consulter la page man de xinetd.conf pour connaître le détail des options disponible et adapter cette configuration à vos besoin. A nouveau, n'oubliez pas de créer le fichier de log.
La configuration de tcpd passe par l'écriture des fichiers etc/hosts.allow et hosts.deny mais pas seulement. N'oubliez pas que notre
environnement chrooter sera complètement isolé du reste du système. Il vous faudra donc recréer les fichier etc/passwd, etc/group etc/hosts
etc/localtime etc/nsswitch.conf etc/resolv.conf etc/services. Pour ces derniers, il suffira de les copier depuis /etc en prenant soin de
les épurer.
Voyons la configuration de hosts.allow (ou hosts.deny) et les possibilité qu'elle apporte. Basiquement cela ressemble à :
SERVICE:SOURCE:OPTION
vsftpd:ALL:ALLOW
vsftpd:.mon-reseau.local:setenv VSFTPD_LOAD_CONF /etc/vsftpd.d/vsftpd_local.conf:ALLOW
vsftpd:ALL EXEPT .mon-reseau.local:setenv VSFTPD_LOAD_CONF /etc/vsftpd.d/vsftpd_generic.conf:ALLOW
La encore, la lecture de la page man de tcpd et de hosts._access hosts.allow/deny est recommandée pour adapter ces configuration à vos besoins.
créez autant de fichier de configuration que rendus nécessaire par votre fichier hosts.allow. Vous pouvez utilisez le fichier donné en exemple dans les sources comme base. Les options sont trop nombreuses et suffisamment explicitées dans vsftpd.conf.5 pour que je ne les détaille pas ici. J'attire cependant votre attention sur quelques point pour que cela fonctionne:
Un simple script de démarrage fera l'affaire, en voici un exemple :
#!/bin/sh
JAIL=/jail/ftp # le répertoire dans lequel tout sera chrooté
DAEMON=/usr/sbin/xinetd
SERVER=/usr/sbin/vsftpd
case "$1" in
start)
/bin/chroot $JAIL $DAEMON
;;
stop)
$SERVER | awk {print $NF} | killall
$DAEMON | awk {print $NF} | killall
;;
restart)
$0 stop
$0 start
;;
reload)
$DAEMON | awk {print $NF} | killall -HUP
;;
*)
echo 'Usage : {start|stop|restart|reload}'
exit 1
;;
esac
exit 0
Pour lancer automatiquement le service au démarrage, rendez ce script exécutable et ajoutez dans /etc/rc.local
:
if [ -x /chemin/vers/le/script ]; then
/chemin/vers/le/script
fi
N'oubliez pas également de désactiver le super-démon-internet du système dans /etc/rc.conf .
Le ftp est un protocole un peut particulier à filtrer dans la mesure où il peut fonctionner selon 2 modes :
Compte tenu de ces informations, nous devrions être capable de filtrer ce qui arrive sur la machine. Pour des raisons pratiques, je
recommande d'avoir une interface (physique ou virtuelle) dédiée au ftp.
Voyons ce que nus allons mettre dans notre /et/pf.conf pour que seul les accès ftp soient acceptés. Nous utiliseront la faculté de PF
Paquet Filter à suivre l'état des connections.
ftp_if = "le1"
sys_if = "xl0"
set if-bound
scrub in all
block in all
antispoof for all inet
pass out quick all keep state
pass quick on lo0 all
pass in on $ftp_if inet proto tcp from any to ($ftp_if) port 21 flags S/SA keep state
pass in on $sys_if inet proto tcp from any to ($sys_if) port 22 flags S/SA keep state
pass in inet proto icmp keep state