Détection d'intrusion avec mtree(8) et /etc/security
Sur NetBSD, sauf modification de l'administrateur, ce dernier reçoit tous les matins un message le renseignant sur la sécurité de son système. Ce message est généré par le script /etc/security
(cf. security.conf(5)) et est lancé par /etc/daily
(cf /etc/daily et ses amis). Parmi les outils utilisés dans security
, se trouve mtree(8)
(sauf modification ie. sauf si check_mtree=NO
dans /etc/security.conf
, ce qui n'est pas le cas par défaut).
Introduction à mtree(8)
Notion de spécification
D'après la page de manuel de mtree(8)
(traduction approximative), le format du fichier de spécification est le suivant :
- les lignes commençant par un
#
sont des commentaires - une ligne commençant par
/set
indique des paramètres par défaut ; s'ensuivent les paramètresparam=value
; l'espace est séparateur - on peut supprimer des paramètres avec une ligne commençant par
/unset
; s'ensuivent les paramètresparam
; l'espace est séparateur - les lignes de spécifications de fichiers proprement dites ; elles consistent en :
- un chemin qui peut contenir les caractères spéciaux
[
,]
,?
et*
- les couples
param=value
sont séparés entre eux par des espaces par contre, il n'y a pas d'espace de part et d'autre du signe égal=
Le premier chemin doit être un répertoire nommé .
pour s'assurer que le mélange entre chemins relatifs et absolus sera consistant. De plus les répertoires intermédiaires doivent être mentionnés. Si deux lignes indiquent des paramètres différents pour un même chemin, la dernière prend le pas sur les précédentes (last match, voir aussi l'option -M
).
Un chemin contenant un /
sera considéré comme un chemin absolu même s'il n'est pas le premier caractère.
Tous les répertoires parents doivent exister.
Créer une spécification
$ mtree -c -K sha1 -p /usr/local > /tmp/local.tmp $ mtree -C -f /tmp/local.tmp > /tmp/local.mtree
-c
→ création,-C
→ reformatage avec sortie plus facile à parser,-K sha1,rmd160
→ on veut « aussi » (en plus des paramètres standard) les sommes de contrôles SHA1,-p /usr/local
→ le répertoire,-f …
→ la spécification.
Vérifier une arborescence
$ touch /usr/local/plop $ mtree -p /usr/local -f /tmp/local.mtree .: modification time (Tue Jul 19 02:27:40 2011, Tue Jul 19 13:22:06 2011) extra: plop
-p …
le répertoire à vérifier,-f …
le fichier de spécification.
Pour restaurer les droits et propriétés d'une arborescence, utiliser l'option -U
:
$ mtree -p /usr/local -f /tmp/local.mtree -U ...
Après restauration d'une sauvegarde, cela s'avère très pratique.
Mise en œuvre
Fichier de spécifications
Pour commencer, se souvenir que security
gère avec RCS les fichiers listés dans /etc/mtree/special
et /etc/mtree/special.local
(et /etc/changelist
). On ne veut pas voir certaines informations contenues dans ces fichiers transiter par courrier électronique, mêmes perdues dans un diff(1)
: mots de passe, clefs de chiffrement, etc.
tags=nodiff
pour toutes les lignes spécifiant des fichiers contenant des clefs de chiffrement et des mots de passe. Dès lors, aucun diff(1)
ne sera fait et ainsi le contenu n'apparaîtra pas en clair (dans un message électronique en clair ou un journal mais sécurisé).
Sur un système NetBSD 5.1, par défaut il y a dans /etc/mtree/special
:
./etc/ipsec.conf type=file mode=0600 optional tags=nodiff ./etc/master.passwd type=file mode=0600 tags=nodiff ./etc/ssh/ssh_host_dsa_key type=file mode=0600 optional tags=nodiff ./etc/ssh/ssh_host_key type=file mode=0600 optional tags=nodiff ./etc/ssh/ssh_host_rsa_key type=file mode=0600 optional tags=nodiff ./etc/racoon/psk.txt type=file mode=0600 optional tags=nodiff ./root/.ssh/id_dsa type=file mode=0600 optional tags=nodiff ./root/.ssh/id_rsa type=file mode=0600 optional tags=nodiff ./root/.ssh/identity type=file mode=0600 optional tags=nodiff
Soit un second fichier /usr/local/etc/exclude_diff
contenant par exemple :
/etc/openssl/private /usr/pkg/etc/httpd/ssl.key /root/.my.cnf
pour permettre d'ajouter sur les lignes idoines tags=nodiff
(avec grep -v -f …
et grep -f …
).
Le script suivant génère /etc/mtree/special.local
(adapter $check_dirs
) :
#!/bin/ksh # # $Id: gen_special_local.sh,v 1.18 2011/07/20 20:07:18 pc Exp pc $ export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/pkg/bin:/usr/pkg/sbin check_dirs="/etc /usr/pkg/etc /root /usr/local/etc \ /var/cron /var/at /var/db /var/spool/sockets /var/spool/clientmqueue /var/spool/mqueue /var/yp \ /var/www/htdocs/www/cgi-bin ..." tmp=/root/tmp umask 0077 mkdir -p ${tmp} # mtree(8) needs all parents dir. in specification function head_dir { dir=$(dirname ${1}) while [[ $(echo $dir | cut -d '/' -f 2) != "" ]]; do echo ".${dir} type=dir" dir=$(dirname $dir) done } grep 'tags=nodiff' /etc/mtree/special | awk '{ print $1 }' > ${tmp}/nodiff cat /usr/local/etc/exclude_diff >> ${tmp}/nodiff for d in ${check_dirs}; do special=$(echo ${d} | sed -e 's/^\///; s/\//_/g') mtree -c -K all,sha1 -X /usr/local/etc/exclude_all_patterns -p ${d} |\ mtree -C -K uname,gname,type,nlink,mode,sha1 -R time,size,flags |\ sed -e "s,^\.,.${d}," > ${tmp}/${special}.mtreeX \ && rm -f ${tmp}/${special}.tmp head_dir ${d} | sort > ${tmp}/${special}.mtree # diff grep -v -f ${tmp}/nodiff ${tmp}/${special}.mtreeX >> ${tmp}/${special}.mtree # nodiff grep -f $tmp/nodiff $tmp/${special}.mtreeX | \ sed -e 's/$/ tags=nodiff/' >> ${tmp}/${special}.mtree && rm -f ${tmp}/${special}.mtreeX done cat > ${tmp}/special.local <<EOF # $(date) # $(hostname) # / /set type=file . type=dir uname=root gname=wheel EOF cat ${tmp}/*.mtree >> ${tmp}/special.local && rm -f ${tmp}/*.mtree
L'administrateur système consciencieux chiffre et/ou signe les spécifications et surtout les enregistre sur une autre machine (avec la signature).
Signature
On signe le fichier en clair avec :
$ gpg --clearsign special.local
mais le fichier est alors modifié et n'est donc plus valide pour mtree(8)
; mieux vaut donc une signature détachée :
$ gpg -a -b special.local
Dans les deux cas, on le vérifie avec :
$ gpg --verify special.local.asc
Vérifier l'arborescence
$ sudo mtree -f /root/tmp/special.local |egrep -v "^(extra|missing):"
Pour une utilisation via /etc/daily
et /etc/security
:
- s'assurer que
check_mtree=YES
est présent dans/etc/security.conf
, - que le script est bien lancé par
cron(8)
, - que la sortie pourra bien être délivrée (MSA/MDA ou autre).
Dès qu'on doit gérer plusieurs machines, on a tout intérêt à lancer /etc/daily
à distance via SSH pour capturer la sortie sur les différents systèmes. La sortie du script security
est gérée et envoyée par courrier électronique dans daily
; commenter les quelques lignes kivonbien pour intégrer la sortie de security
et security.local
à l'ensemble. On n'a alors plus qu'un seul (gros) rapport à lire le matin.
Rien n'empêche non plus de chiffrer et/ou signer les rapports avant de les envoyer ou de les stocker.