Durcir le système de fichiers
L’essentiel du durcissement du système de fichiers consiste à décider, par montage, lequel de trois pouvoirs un répertoire a le droit d’accorder: exécuter un binaire, honorer son bit setuid et le laisser être un nœud de périphérique.
Le défaut, defaults, accorde les trois partout, ce qui est commode et faux pour les répertoires où les utilisateurs et les démons peuvent écrire.
Le reste, c’est séparer les partitions pour qu’une ne puisse affamer les autres, activer les protections de liens du noyau et garder un œil sur quels fichiers portent le setuid.
Rien d’exotique et le gain est que des catégories entières d’escalade locale n’ont plus où atterrir.
Options de montage : retirer ce dont le répertoire n’a pas besoin
Les trois options qu’il vaut la peine de retirer sont noexec (rien ne s’exécute d’ici), nosuid (les bits setuid et setgid sont ignorés) et nodev (les nœuds de périphérique ne sont pas honorés).
Un répertoire de travail en écriture n’a besoin d’aucun de ces pouvoirs, donc un fstab sensé les retire précisément des endroits où un attaquant aime déposer une charge:
# /etc/fstab — les montages pertinents pour la sécurité
/tmp /tmp ext4 defaults,nosuid,nodev,noexec 0 2
/var/tmp /var/tmp ext4 defaults,nosuid,nodev,noexec,bind 0 2
/dev/shm /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0
/home /home ext4 defaults,nosuid,nodev 0 2
/var /var ext4 defaults,nosuid,nodev 0 2
/tmp, /var/tmp et /dev/shm sont accessibles en écriture à tous par conception, donc ils reçoivent les trois: une charge déposée là ne peut pas être exécutée, ne peut pas gagner du privilège par un bit setuid et ne peut pas être un nœud de périphérique dérobé.
/home et /var gardent exec (utilisateurs et démons y exécutent légitimement des choses) mais perdent nosuid et nodev, parce qu’aucun home d’utilisateur n’a à détenir un binaire setuid-root ni un fichier de périphérique.
La réserve honnête, c’est que noexec est de la défense en profondeur, pas un mur.
Il arrête ./charge, mais un interpréteur lit un script comme de la donnée, donc python /tmp/x.py ou sh /tmp/x.sh tourne quand même et un attaquant assez déterminé a memfd et d’autres astuces.
noexec élève le coût et bloque le dépôt-et-lance paresseux; il ne rend pas /tmp sûr à ignorer.
Traitez-le comme une couche parmi plusieurs et il gagne sa place.
Séparer les partitions pour qu’une ne coule pas le navire
Un système de fichiers racine plat et unique signifie que tout ce qui remplit un répertoire remplit tout: des logs emballés dans /var/log, un utilisateur qui remplit /home, un flot de fichiers temporaires dans /tmp, tous finissent de la même façon, un / plein où le système ne peut plus écrire et où les services tombent.
Des partitions séparées (ou des volumes LVM ou des sous-volumes) pour /tmp, /var, /var/log et /home contiennent cela: un /var/log plein est un problème de journalisation, pas une machine morte.
La séparation est aussi ce qui rend possibles les options par montage ci-dessus, puisqu’on ne peut poser noexec sur /tmp que si /tmp est son propre montage.
Activer les protections de liens du noyau
Les attaques par symlink et hardlink sont anciennes et marchent encore là où les protections sont coupées.
La classique est un TOCTOU: un programme privilégié vérifie /tmp/userfile, un attaquant l’échange contre un symlink vers /etc/passwd entre la vérification et l’écriture et le programme écrit à travers le lien en tant que root.
La variante hardlink garde un lien lisible vers un fichier sensible qui survit à son remplacement.
Le noyau ferme les deux et les distributions modernes les activent, mais il vaut la peine de l’affirmer plutôt que de le supposer:
# /etc/sysctl.d/filesystem.conf
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
protected_symlinks fait que le noyau refuse de suivre un symlink dans un répertoire sticky accessible en écriture à tous sauf si le suiveur possède le lien ou le répertoire, c’est-à-dire exactement le TOCTOU de /tmp; les autres étendent la même idée aux hardlinks, aux FIFO et aux fichiers réguliers dans ces répertoires.
Cela ne coûte rien et ferme une porte vieille de décennies.
Auditer le setuid et préférer les capabilities
Chaque binaire setuid-root est un petit programme privilégié qui tourne en root au nom d’un utilisateur non privilégié, ce qui fait de leur ensemble une surface d’attaque qu’il vaut la peine de connaître par cœur. Énumérez-le et questionnez tout ce qui surprend:
find / -xdev -perm -4000 -type f 2>/dev/null
La liste devrait être courte et ennuyeuse: sudo, su, passwd, mount, ping sur les systèmes anciens, quelques autres.
Tout le reste, surtout un interpréteur ou un outil recopié, est un constat.
Là où un programme a besoin d’un privilège précis plutôt que de tout root, une capability de fichier (par exemple cap_net_raw sur un outil à la ping) vaut strictement mieux que setuid-root, parce qu’elle accorde le seul pouvoir au lieu du compte entier.
Retirer un bit setuid inutile (chmod u-s) est l’une des réductions de risque les moins chères d’une machine.
Immuable là où ça aide
Pour les fichiers qui ne devraient jamais changer après le provisioning, l’attribut immuable est un fil-piège et un frein bon marché: même root ne peut modifier ni supprimer un fichier marqué i sans d’abord retirer le marqueur, ce qui arrête un script négligent et ralentit un attaquant soigneux.
chattr +i /etc/passwd /etc/shadow /etc/ssh/sshd_config
Ce n’est pas une frontière forte, puisqu’un attaquant déjà root peut faire chattr -i d’abord, mais cela transforme un écrasement silencieux en une action à deux temps qu’une règle d’audit peut attraper et cela prévient une quantité surprenante de dégâts accidentels.
Où atterrir
Donnez à /tmp, /var/tmp et /dev/shm leurs propres montages en nosuid,nodev,noexec et à /home et /var en nosuid,nodev, en vous rappelant que noexec est une couche et non un mur.
Séparez les partitions qui peuvent être remplies pour qu’une ne puisse abattre la racine, ce qui est aussi ce qui permet de poser ces options.
Affirmez les protections de liens du noyau plutôt que de faire confiance au défaut.
Connaissez votre inventaire setuid par cœur et retirez ou remplacez ce qui n’a rien à y faire, en préférant les capabilities de fichier au setuid-root.
Et marquez comme immuable la poignée de fichiers qui ne devraient jamais changer, comme un frein et un fil-piège plutôt qu’un mur.
Le thème est le même d’un bout à l’autre: un répertoire en écriture devrait contenir de la donnée, pas des pouvoirs.