HSC
Network Security Consulting Agency Since 1989 - Specialized in Unix, Windows, TCP/IP and Internet
Text mode: access to the page content
Hervé Schauer Consultants
You are here: Home > Resources > Tips > Installation sécurisée d'un serveur POP3
Go to: HSC Trainings
Télécharger le catalogue des formations
Search:  
Version française
   Services   
o Skills & Expertise
o Consulting
o ISO 27001 services
o Audit & Assessment
o Penetration tests
o Vunerability assessment (TSAR)
o Forensics
o ARJEL
o Training courses
o E-learning
   Conferences   
o Agenda
o Past events
o Tutorials
   Resources   
o Thematic index
o Tips
o Lectures
o Courses
o Articles
o Tools (download)
o Vulnerability watch
   Company   
o Hervé Schauer
o Team
o Job opportunities
o Credentials
o History
o Partnerships
o Associations
   Press and
 communication
 
 
o HSC Newsletter
o Bulletin juridique HSC
o Press review
o Press releases
o Publications
   Contacts   
o How to reach us
o Specific inquiries
o Directions to our office
o Hotels near our office
|>|Installation sécurisée d'un serveur POP3  

by Renaud Deraison (30/11/2000)


Renaud Deraison est une personne que l'on ne présente plus, Nessus est aujourd'hui connu et reconnu partout. Renaud a souhaité participer aux brèves HSC, il est le bien-venu, nous apprécions la qualité de ce qu'il écrit. Merci Renaud d'autres suivront peut-être ton exemple.


Chrooter cucipop et le faire tourner en tant que non-root sous FreeBSD 3.1
--------------------------------------------------------------------------
               Par Renaud Deraison <deraison@nessus.org>



Ce document explique comment j'ai fait pour chrooter cucipop et le faire tourner
en tant qu'utilisateur n'ayant aucun privilège sous FreeBSD 3.1 (si ce n'est
le privilège de lire et écrire les mails de tout le monde)


. -2 Pourquoi ?
---------------

Parceque les daemon pop sont les meilleurs moyens d'administrer une machine
à distance après ssh. Régulièrement on y trouve des bugs, et ceux-ci font
toujours très mal. Alors autant réduire l'exposabilité d'une machine et
faire tourner cucipop avec le moins de privilèges possible.

De plus, la plupart des utilisateurs utilisent pop sans chiffrement. On ne veut
pas que leur mot de passe pop soit le meme que le mot de passe système, donc
on veut avoir deux bases de mots de passes différentes.

Enfin, je sais qu'il existe des serveurs POP qui font déjà tout ca.  J'avais
pas envie de les essayer, etant très content avec cucipop et d'un naturel
paresseux.

. -1 Ingrédients
----------------

	- Les sources de cucipop 1.31, que nous patcherons
	- Les sources de la libc de FreeBSD, que nous patcherons
	- GCC
	- Ce document
	- Un peu de temps et de patience. Eventuellement une
	  machine pour assurer le service pop pendant l'install
	
	- Les droits de root :) Toutes les commandes effectuées ici
	  doivent etre faites en tant que root.


0. Création d'un utilisateur
----------------------------

Mon daemon cucipop tourne en tant que "cucipop". Chez moi, ils sont de uid/gid
5002 (le numéro est important, on s'en servira tout à l'heure et c'est utilisé
dans le patch inclus dans ce document).

1. Création de la prison
------------------------

Je stocke toutes mes prisons dans /usr/local/chroots/ :
 

mkdir /usr/local/chroots/cucipop
cd /usr/local/chroots/cucipop

mkdir bin
mkdir dev
mkdir etc
mkdir tmp
chown cucipop tmp
chmod 0755 tmp
mkdir usr
mkdir var

Dans /bin, on mettra le binaire cucipop que nous allons créer plus tard.
Dans /dev, on veut créer le fichier spécial "null" :

2. Création des devices (null et log)
-------------------------------------
cd /usr/local/chroots/cucipop/dev
mknod c 2 2 null
chmod 0666 null

On édite /etc/rc.conf pour que notre serveur syslogd ouvre une socket
dans /usr/local/chroots/cucipop/dev/log :

dans /etc/rc.conf, je rajoute/modifie la ligne syslogd_flags : 
syslogd_flags="-l /usr/local/chroots/cucipop/dev/log"


3. Remplissage de /etc
----------------------

J'ai besoin de remplir le /etc de ma prison. Je prend les fichiers suivants
dans le vrai /etc :
	group
	master.passwd
	passwd
	popusers
	pwd.db
	shells
	spwd.db

(on notera que là c'est pas une bonne chose parcequ'on reprend les mots
de passe du systeme. Je ferais une autre breve qui explique comment modifier
la commande 'passwd' sous FreeBSD pour gérer plusieurs bases de mots de passe).

Je rend ces fichiers lisibles à tous (ce qui défait l'interet de /etc/spwd.db, 
je le concède. On pourrait ruser en rendant ces fichiers lisibles
par le groupe cucipop seulement, mais ne rentrons pas trop dans les détails) :

	chgrp cucipop /usr/local/chroots/cucipop/etc/*
	chmod 0640 /usr/local/chroots/cucipop/etc/*

Dans ce meme etc, je créé un dossier "mail", qui appartient à l'utilisateur et 
au group cucipop :

	mkdir mail
	chown cucipop.cucipop mail
	chmod 0755 mail/

cucipop y creera son vpop.db par la suite.

4. Remplissage de /usr
----------------------

Je recopie les fichiers suivants dans /usr/local/chroots/cucipop/usr
(je suis en FreeBSD 3.1, ca peut changer selon votre système - faites
un ldd sur l'executable de votre cucipop pour savoir ce dont vous avez
besoin).


mkdir /usr/local/chroots/cucipop/usr/lib
cp /usr/lib/libcrypt.so.2  /usr/local/chroots/cucipop/usr/lib
cp /usr/lib/libmd.so.2 /usr/local/chroots/cucipop/usr/lib
cp /usr/lib/libskey.so.2 /usr/local/chroots/cucipop/usr/lib
cp /usr/lib/libutil.so.2 /usr/local/chroots/cucipop/usr/lib

(on notera que je ne recopie PAS la libc, parceque par défaut elle
ne laisse pas un utilisateur non-root accéder à /etc/spwd.db)

Je continue :
mkdir /usr/local/chroots/cucipop/usr/libexec
cp /usr/libexec/ld-elf.so.1 /usr/local/chroots/cucipop/usr/libexec


5. Remplissage de /var
----------------------

Autrefois, votre mail s'entassait dans /var/mail. On le change de là mais
on met un symlink pour que les autres programmes du système continuent
de fonctionner. On utilise tar pour préserver les permissions :

(on arrete notre MTA avant - ie: postfix stop)
tar -cpf - /var/mail | tar -xpf - -C /usr/local/chroots/cucipop
rm -rf /var/mail
ln -s /usr/local/chroots/cucipop/mail /var/mail
(on redemarre notre MTA)

Cucipop va avoir besoin d'écrire dans ce dossier (pour le locking) :

chown cucipop.cuciop /usr/local/chroots/cucipop/var/mail
chmod 0775 /usr/local/chroots/cucipop/var/mail

On créé de plus les dossiers dont cucipop aura besoin :

mkdir /usr/local/chroots/cucipop/var/spool
mkdir /usr/local/chroots/cucipop/var/spool/cucipop
chown cucipop.cucipop  /usr/local/chroots/cucipop/var/spool/cucipop
chmod 0755 /usr/local/chroots/cucipop/var/spool/cucipop
mkdir /usr/local/chroots/cucipop/var/run
chown cucipop.cucipop /usr/local/chroots/cucipop/var/run 
chmod 0755  /usr/local/chroots/cucipop/var/run


6. Modification de la libc
--------------------------

La libc de FreeBSD utilise /etc/spwd.db si et seulement si notre uid est nul. 
Il faut donc changer ce comportement pour que notre daemon cucipop puisse
utiliser les mots de passes du système.

Dans /usr/src/sys/lib/libc/gen/getpwent.c, je modifie la fonction
__initdb, pour changer :

if(!geteuid()) p = _PATH_SMP_DB;

en :

if((!geteuid())||(geteuid() == 5002))p = _PATH_SMP_DB;


(on notera bien que 5002 c'est l'uid de mon utilisateur cucipop).

Je recompile et j'installe cette libc dans /usr/local/chroots/cucipop/usr/lib
(et PAS dans /usr/lib). Une fois cette manipulation faite, je restaure
le fichier getpwent.c dans son état original pour éviter des erreurs
à l'avenir.


7. Modification de cucipop
--------------------------

Je télécharge cucipop 1.31 sur ftp.cuci.nl, dans /pub, et j'y applique
les patches suivants (un mélange de patches maison et de patches venant du port
FreeBSD) :

----- COUPER ICI -----
diff -urN cucipop-1.31/Makefile cucipop-1.31.patched/Makefile
--- cucipop-1.31/Makefile	Thu Nov 30 02:02:21 2000
+++ cucipop-1.31.patched/Makefile	Sat Sep 30 14:18:45 2000
@@ -1,30 +1,30 @@
 #$Id: cucipop.tip,v 1.1 2000/11/30 09:44:28 aubert Exp $
 
-BASENAME= /usr
+BASENAME= $(PREFIX)
 
-GCC_WARNINGS = -O2 -pedantic -Wreturn-type -Wunused -Wformat \
- -Wpointer-arith -Wconversion -Waggregate-return \
+#CC_WARNINGS = -O2 -pedantic -Wreturn-type -Wunused -Wformat \
+# -Wpointer-arith -Wconversion -Waggregate-return \
  #-Wimplicit -Wshadow #-Wuninitialized
 
 #
 # Omit USE_DB if you don't have the -ldb2 library (Berkeley DB, v2.x)
 # WARNING: bulletins are not remembered to have been deleted without USE_DB
 
-CFLAGS	= -O #-DUSE_DB #$(GCC_WARNINGS)
-LDFLAGS = -lcrypt #-ldb2
+#CFLAGS	= -O -DUSE_DB #$(GCC_WARNINGS)
+LDFLAGS += -lcrypt -lmd
 
 # If you change this, edit config.h as well
-CUCIPOPLIB=/var/lib/cucipop
+CUCIPOPLIB=/var/spool/cucipop
 CUCIPOPBULLETINS=$(CUCIPOPLIB)/bulletins
 
 O=o
 
-BINDIR=$(BASENAME)/sbin
+BINDIR=$(BASENAME)/libexec
 MANDIR=$(BASENAME)/man/man8
 
-INSTALL=install -o root -m
-BINPERM=02755 -s -g mail
-REGPERM=0644
+INSTALL=install -c -o bin -m
+BINPERM=02555 -s -g mail
+REGPERM=0444
 
 #
 # When compiling without APOP support, the md5 library can be omitted.
@@ -32,11 +32,11 @@
 MD5_OBJ=md5/md5c.$(O)
 
 OBJS=cucipop.$(O) authenticate.$(O) atotime.$(O) locking.$(O) xcreat.$(O) \
-	dbops.$(O) hsort.$(O) simplecrypt.$(O) $(MD5_OBJ)
+	dbops.$(O) hsort.$(O) simplecrypt.$(O)
 
-BINS=cucipop makevpopdb
+BINS=cucipop# makevpopdb
 
-MANS=cucipop.8 makevpopdb.8
+MANS=cucipop.8
 
 all: $(BINS)
 
@@ -70,8 +70,8 @@
 install: $(BINS) $(MANS)
 	$(INSTALL) $(BINPERM) $(BINS) $(BINDIR)
 	$(INSTALL) $(REGPERM) $(MANS) $(MANDIR)
-	mkdir $(CUCIPOPLIB) 2>/dev/null; exit 0
-	mkdir $(CUCIPOPBULLETINS) 2>/dev/null; exit 0
+	mkdir -p $(CUCIPOPLIB) 2>/dev/null; exit 0
+	mkdir -p $(CUCIPOPBULLETINS) 2>/dev/null; exit 0
 	@for a in $(BINS); do ls -l $(BINDIR)/$$a; done
 	@for a in $(MANS); do ls -l $(MANDIR)/$$a; done
 
diff -urN cucipop-1.31/authenticate.c cucipop-1.31.patched/authenticate.c
--- cucipop-1.31/authenticate.c	Wed May 13 18:57:39 1998
+++ cucipop-1.31.patched/authenticate.c	Sat Sep 30 14:18:45 2000
@@ -44,7 +44,7 @@
 #define VIRTUALUSER	"vpop"
 
 #ifndef MAILSPOOLDIR
-#define MAILSPOOLDIR	"/var/spool/mail/"	     /* watch the trailing / */
+#define MAILSPOOLDIR	"/var/mail/"	     /* watch the trailing / */
 #endif
 #ifndef MAILSPOOLHASH
 #define MAILSPOOLHASH	0      /* 2 would deliver to /var/spool/mail/b/a/bar */
diff -urN cucipop-1.31/config.h cucipop-1.31.patched/config.h
--- cucipop-1.31/config.h	Tue May 12 23:09:14 1998
+++ cucipop-1.31.patched/config.h	Sat Sep 30 14:18:45 2000
@@ -3,7 +3,7 @@
 #define USEdot_lock	/**/
 /*#define USEfcntl_lock /**/	    /* to test which combinations make sense */
 /*#define USElockf	/**/	      /* run the lockingtest program part of */
-/*#define USEflock	/**/		/* the procmail installation process */
+#define USEflock	/**/		/* the procmail installation process */
 
 /*#define SHADOW_PASSWD /**/		  /* shadow password library support */
 
@@ -84,6 +84,6 @@
 #define MAXBULLETINS	64
 #define MAXSTATEAGE	8388608				       /* > 3 months */
 #define MEMORY_CACHE	(64*1024)
-#define CUCIPOP_LIB	"/var/lib/cucipop"
+#define CUCIPOP_LIB	"/var/spool/cucipop"
 #define STATE_DB	"state.db"
 #define BULLETINS_PATH	CUCIPOP_LIB"/bulletins"
diff -urN cucipop-1.31/cucipop.8 cucipop-1.31.patched/cucipop.8
--- cucipop-1.31/cucipop.8	Mon May 11 18:35:19 1998
+++ cucipop-1.31.patched/cucipop.8	Sat Sep 30 14:18:47 2000
@@ -48,12 +48,12 @@
 .SH NAME
 cucipop \- Cubic Circle POP3 daemon
 .SH SYNOPSIS
-.B /usr/sbin/cucipop
+.B !!PREFIX!!/libexec/cucipop
 .RB [ \-qaYdPUSDAT ]
 .RB [ "\-E \fIage\fP" ]
 .RB [ "\-p \fIport\fP" ]
 .br
-.B /usr/sbin/cucipop
+.B !!PREFIX!!/libexec/cucipop
 .B \-v
 .ad
 .SH DESCRIPTION
@@ -132,12 +132,12 @@
 .IR port .
 .SH EXAMPLES
 Typically
-.I pop-3
+.I pop3
 service is defined in
 .BR services (5)
 as follows:
 .Sx 1
-pop-3           110/tcp
+pop3           110/tcp
 .Ex
 In order to start cucipop from within
 .BR inetd (8),
@@ -145,16 +145,16 @@
 .BR inetd.conf (5)
 would be suitable:
 .Sx 1
-pop-3   stream  tcp     nowait  root    /usr/sbin/cucipop cucipop -Y
+pop3   stream  tcp     nowait  root    /usr/sbin/cucipop cucipop -Y
 .Ex
 If your site gets many hits from popclients, it would be preferable
 to start cucipop standalone as in:
 .Sx 1
-/usr/sbin/cucipop -Y
+!!PREFIX!!/libexec/cucipop -Y
 .Ex
 Your typical BOFH setting would be:
 .Sx 1
-/usr/sbin/cucipop -YaSE 6w
+!!PREFIX!!/libexec/cucipop -YaSE 6w
 .Ex
 .SH FILES
 .TP 2.3i
@@ -166,25 +166,25 @@
 .BR makevpopdb (8)
 man page on how this file is created
 .TP
-.B /var/lib/cucipop/state.db
+.B !!PREFIX!!/lib/cucipop/state.db
 AI state information and bulletin history
 .TP
-.B "/var/lib/cucipop/bulletins/\fInn\fP"
+.B "!!PREFIX!!/lib/cucipop/bulletins/\fInn\fP"
 .B 00
 through
 .B 63
 optional bulletin files in regular mailbox format
 .TP
-.B /var/spool/mail/$LOGNAME
+.B /var/mail/$LOGNAME
 system mailbox
 .TP
-.B /var/spool/mail/virtual.dom.ain/$LOGNAME
+.B /var/mail/virtual.dom.ain/$LOGNAME
 virtual host system mailbox
 .TP
-.B /var/spool/mail/$LOGNAME.lock
+.B /var/mail/$LOGNAME.lock
 lockfile for the system mailbox
 .TP
-.B /var/spool/mail/virtual.dom.ain/$LOGNAME.lock
+.B /var/mail/virtual.dom.ain/$LOGNAME.lock
 lockfile for the virtual host system mailbox
 .TP
 .B _????`hostname`
diff -urN cucipop-1.31/cucipop.c cucipop-1.31.patched/cucipop.c
--- cucipop-1.31/cucipop.c	Wed May 13 18:57:39 1998
+++ cucipop-1.31.patched/cucipop.c	Sat Sep 30 15:07:12 2000
@@ -238,6 +238,7 @@
 
 static const auth_identity*transmogrify(const auth_identity*pass)
 { initappdb();opendb();
+  return pass;
   return setuid(auth_whatuid(pass))?(auth_identity*)0:pass;
 }
 
@@ -520,6 +521,7 @@
   if(!(fmbox=fp=fopen(mailbox=auth_mailboxname((auth_identity*)pass),"r+b")))
    { if(errno==ENOENT)
 	goto nomailbox;					 /* no mailbox found */
+	fprintf(sockout, "-ERR cuci: no mailbox %s (%s)\n", mailbox, strerror(errno));
      return 0;
    }
   ungetc(fgetc(fp),fp);					      /* prime atime */
@@ -725,6 +727,12 @@
 	   return EX_OSFILE;
 	 }
 	fclose(stderr);
+	initgroups("cucipop", 5002);
+	setuid(5002);
+        seteuid(5002); 
+        setgid(5002);
+        setegid(5002);
+
 	if(fork()>0)
 	   return EXIT_SUCCESS;
 	setsid();listen(serverfd,LISTEN_BACKLOG);
diff -urN cucipop-1.31/locking.h cucipop-1.31.patched/locking.h
--- cucipop-1.31/locking.h	Wed Dec 18 12:52:06 1996
+++ cucipop-1.31.patched/locking.h	Sat Sep 30 14:54:05 2000
@@ -16,3 +16,12 @@
 #ifndef USEfcntl_lock
 #define NOfcntl_lock
 #endif
+
+
+#undef USEfcntl_lock
+#undef USElockf
+#undef USEflock
+#undef USEdot_lock
+
+#define USEflock
+
diff -urN cucipop-1.31/xcreat.c cucipop-1.31.patched/xcreat.c
--- cucipop-1.31/xcreat.c	Sat May  2 02:56:54 1998
+++ cucipop-1.31.patched/xcreat.c	Sat Sep 30 14:18:45 2000
@@ -22,7 +22,7 @@
 /*#define NOuname		      /* uncomment if uname is not available */
 /*#define NOstrpbrk		    /* uncomment if strpbrk is not available */
 /*#define strchr(s,c) index(s,c)     /* uncomment if strchr is not available */
-#define const			      /* can be undefined for ANSI compilers */
+/*#define const			      /* can be undefined for ANSI compilers */
 
 #include <unistd.h>			/* open() close() link() unlink()
 					   getpid() */


----- FIN DES PATCHS ----


Je compile mon binaire (make), et je l'installe dans 
/usr/local/chroots/cucipop/bin


8. Rendre les mails lisibles à cucipop
--------------------------------------

Bon avec tout ca, on est presque prets, mais le problème c'est que
cucipop ne peut pas lire les mails qui sont dans
/usr/local/chroots/cucipop/var/mail/, puisque ceux-ci sont en mode
0600.

L'astuce consiste donc à faire appartenir tout le contenu de 
/var/mail au groupe cucipop. Le problème c'est que souvent, certains
MTA vont remettre les mails en mode 0600. On a donc besoin de mettre
en place un cronjob qui va restaurer nos permissions toutes les minutes :

mkdir /var/scripts
cat << _EOF_ > /var/scripts/cucipop
#!/bin/sh

# on remet le contenu de /etc en lecture au groupe :
cd /usr/local/chroots/cucipop/etc/ && chmod g+r *

# on remet les mails en mode 0660 
cd /usr/local/chroots/cucipop/var/mail/ && chgrp cucipop * && chmod 0660 *
_EOF_
chmod 0755 /var/scripts/cucipop


Il ne nous reste plus qu'a mettre en place le cronjob. En tant que root, je
fait :
crontab -e

Je rajoute :
*/5	*	*	*	*	/var/scripts/cucipop

Je sauve et je quitte.


9. Script de démmarrage
-----------------------

Il ne me reste plus qu'a écrire un script de démarrage :

cd /usr/local/etc/rc.d
cat << _EOF_ > cucipop.sh
#!/bin/sh
/usr/sbin/chroot /usr/local/chroots/cucipop /bin/cucipop -Ya && echo -n ' cucipop'
_EOF_


10. C'est fini (?)
------------------

Voila, il ne me reste plus qu'a lancer cucipop (en tant que root) en faisant
/usr/local/etc/rc.d/cucipop.sh

Le patch qu'on lui a appliqué le force a faire un set[e][gu]id(5002), ce qui 
le fait tourner en tant que 'cucipop' :

ps aux|grep cucipop
cucipop    28239  0.0  0.2   820  116  ??  Is   30Sep00   0:36.46 /bin/cucipop 
cucipop    90567  0.0  0.0     0    0  ??  Z    -         0:00.00  (cucipop)


Je recommande d'installer sslwrap pour chiffrer la communication client <->
serveur, mais ca risque d'etre off-topic.

11. Conclusion
--------------

Faire tourner un serveur pop en tant que non-root implique un certain compromis
au niveau de la sécurité locale (les mails passent en mode 0660), mais
permet de mieux dormir la nuit. Une intrusion par ce biais restera hélas
une expérience pénible, mais aux conséquences relativement limitées.



Bientot :


	- cucipop et sslwrap en 10mn
	- comment faire tourner CVS chrooté
	- comment faire tourner dhcpcd chrooté
	- comment faire tourner squid chrooté
	- comment faire tourner ftpd chrooté
	- comment gérer les bases de mots de passe de tout ce petit monde





Last modified on 30 Mars 2006 at 19:18:59 CET - webmaster@hsc.fr
Mentions légales - Information on this server - © 1989-2013 Hervé Schauer Consultants