Sections du handbook

Durcir le noyau et le réseau avec sysctl

Revu le

Les paramètres dynamiques du noyau décident comment l'hôte route les paquets et expose sa propre mémoire. Resserrez-les pour que la pile réseau et le noyau cessent d'aider un attaquant, et rendez le changement persistant au redémarrage.

La menace : un noyau réglé pour la connectivité, pas pour la sécurité

Un noyau Linux est livré avec des paramètres dynamiques (les clés sysctl sous /proc/sys) dont les valeurs par défaut privilégient la connectivité et le débogage au détriment de la sécurité, si bien que l'hôte devient complice de l'attaquant. Avec le routage IP activé, un serveur compromis devient un routeur qui fait transiter du trafic vers des réseaux qu'il ne devrait jamais relier. Accepter les redirections ICMP permet à n'importe quel hôte du segment de réécrire votre table de routage et de réaliser une attaque de l'homme du milieu. Les paquets à routage par la source laissent un émetteur distant imposer le chemin de retour et contourner le filtrage. Sans filtrage par chemin inverse, les adresses sources usurpées entrent sans obstacle. Côté local, un espace d'adressage non randomisé (ASLR désactivé) rend les exploits de corruption mémoire fiables, des pointeurs noyau fuités dans dmesg//proc livrent les adresses pour vaincre le KASLR, et un périmètre ptrace ouvert laisse un processus lire la mémoire d'un autre pour moissonner identifiants et jetons.

Pourquoi le durcir

Ce sont des réglages d'une ligne à l'impact démesuré : chaque défaut faible est une primitive que l'attaquant enchaîne vers un pivot, un détournement de route, une inondation usurpée ou un exploit fiable. Sur un serveur classique (qui n'est pas un routeur), les durcir ne coûte presque rien en exploitation tout en supprimant des classes entières d'exploitation avant même qu'un contrôle applicatif n'entre en jeu. C'est la couche de défense en profondeur la moins chère, et le jeu ci-dessous se rattache à CIS et ANSSI BP-028 : R8 (mémoire et ASLR), R9 (noyau), R11 (Yama/ptrace), R12 (IPv4), R13 (IPv6), R14 (système de fichiers) et R23 (kexec).

Runtime contre persistant : la distinction qui décide la note

sysctl a deux visages, et la différence est exactement l'axe du verdict qualifié :

Action Commande Persistance
Lire la valeur vivante sysctl -n net.ipv4.ip_forward sans objet
Régler à chaud sysctl -w net.ipv4.ip_forward=0 perdu au reboot
Rendre persistant un fichier dans /etc/sysctl.d/ puis sysctl --system survit au reboot

Pour durcir, on écrit toujours un fichier dans /etc/sysctl.d/ ; -w ne sert qu'au test. Précédence : à nom de fichier identique, le répertoire gagne (/etc > /run > /usr/lib) ; à noms différents, le nom le plus grand en ordre lexical l'emporte, donc un préfixe 99- est lu en dernier et prime sur les défauts de la distribution ; sysctl --system lit /etc/sysctl.conf tout à la fin. Une valeur peut être vivante mais non persistante (posée avec -w, perdue au reboot) ou écrite mais non appliquée (fichier édité, sysctl --system jamais lancé) : seule la relecture de /proc/sys prouve l'état courant.

Ce que Pavois audite : la valeur effective dans /proc/sys

Pavois lit la valeur effective, en cours d'exécution, pas ce qu'un fichier prétend. Chaque contrôle s'appuie sur la ressource kernel_parameter d'InSpec, qui lit l'arborescence vivante /proc/sys ; il voit donc l'état réellement résolu du noyau après application de chaque /etc/sysctl.conf, drop-in /etc/sysctl.d/*.conf, argument de la ligne de commande noyau et sysctl -w à chaud, si bien qu'un fichier édité mais jamais appliqué (pas de sysctl --system) n'est jamais lu comme conforme. (Les checks sysctl du SSG lisent aussi /proc/sys, donc les deux attrapent la dérive runtime ici ; l'avantage est le modèle de preuve cohérent, pas sysctl lui-même.) Le domaine porte des dizaines de vérifications : routage désactivé, filtrage par chemin inverse activé, redirections ICMP ignorées et non émises, routage par la source refusé, journalisation des martiens, rejet des echo broadcast et des erreurs ICMP fallacieuses, SYN cookies, ASLR = 2, kptr_restrict = 2, dmesg_restrict, et yama.ptrace_scope >= 1, chacune rattachée à CIS, ANSSI BP-028 et d'autres pour qu'un seul audit produise un rapport selon la norme choisie.

Les paramètres de durcissement

Paramètre Valeur durcie Ferme
net.ipv4.ip_forward 0 hôte utilisé comme routeur ou pivot
net.ipv4.conf.all.accept_redirects 0 détournement de route par redirection ICMP
net.ipv4.conf.all.send_redirects 0 fuite de routes vers le segment
net.ipv4.conf.all.accept_source_route 0 chemin de retour imposé par l'attaquant
net.ipv4.conf.all.rp_filter 1 usurpation d'adresse source
net.ipv4.conf.all.log_martians 1 trafic à adresse impossible silencieux
net.ipv4.tcp_syncookies 1 déni de service par inondation SYN
net.ipv6.conf.all.accept_ra 0 annonces de routeur IPv6 malveillantes
kernel.randomize_va_space 2 exploits mémoire fiables
kernel.kptr_restrict 2 contournement du KASLR par pointeurs fuités
kernel.dmesg_restrict 1 fuite d'information par les journaux noyau
kernel.yama.ptrace_scope 1 un processus lisant la mémoire d'un autre
kernel.unprivileged_bpf_disabled 1 surface eBPF ouverte aux non-privilégiés
kernel.kexec_load_disabled 1 chargement à chaud d'un noyau de remplacement
fs.protected_symlinks 1 attaques TOCTOU par lien symbolique
fs.suid_dumpable 0 core dumps de programmes setuid

Comment vérifier et opérer sysctl ?

Capturez d'abord une baseline (les défauts varient selon la distribution), puis relisez les valeurs vivantes avec sysctl net.ipv4.conf.all.rp_filter kernel.kptr_restrict. Pour une preuve concrète, kptr_restrict = 2 met à zéro les adresses des symboles dans head -2 /proc/kallsyms, même pour root. Appliquez un fichier de durcissement avec sysctl --system. Attention à la limite des conteneurs : kernel.* et fs.* sont en lecture seule dans un conteneur non privilégié (permission denied) ; seuls net.* et un sous-ensemble IPC namespacé sont modifiables, donc le durcissement noyau complet se fait sur l'hôte ou une VM, dont les conteneurs héritent.

Exceptions et pièges

  • ip_forward = 0 coupe le routage. Un routeur, une passerelle NAT, un nœud Kubernetes ou un hôte Docker ont besoin de ip_forward = 1. Ne durcissez ce paramètre que sur un serveur applicatif simple.
  • rp_filter = 1 (strict) casse le routage asymétrique et les hôtes multi-homés (utilisez 2, mode lâche). Le noyau applique max(conf.all, conf.<iface>), donc all = 0 ne désactive pas le filtrage si une interface a une valeur plus haute, et default ne s'applique qu'aux interfaces créées ensuite. CIS et ANSSI veulent 1 ; systemd/Debian retiennent souvent 2 exprès.
  • accept_ra = 0 suppose une IPv6 configurée statiquement ; gardez-le activé là où les préfixes arrivent par Router Advertisement.
  • Désactiver IPv6 peut empêcher sshd ou Postfix en écoute sur ::1 de démarrer (posez AddressFamily inet / inet_protocols = ipv4).
  • Yama doit être chargé pour que kernel.yama.ptrace_scope existe (cat /sys/kernel/security/lsm).
  • NetworkManager et systemd-networkd posent leurs valeurs par interface après systemd-sysctl : corrigez un réglage par interface côté gestionnaire réseau, pas en empilant des fichiers sysctl.
  • Testez sur une VM ou via une console hors bande : un mauvais réglage réseau appliqué à distance peut vous couper l'accès.

FAQ

Pourquoi Pavois lit-il /proc/sys plutôt que les fichiers sysctl ? Parce que seule la valeur vivante est ce que le noyau applique. Un fichier présent mais jamais appliqué (pas de sysctl --system) ne change rien, et Pavois audite l'état effectif.

Une valeur est correcte maintenant mais la page échoue après un redémarrage. Pourquoi ? Elle a été posée avec sysctl -w (runtime seulement). Rendez-la persistante dans /etc/sysctl.d/ pour qu'elle survive au reboot. C'est la distinction runtime contre persistant que capture le verdict qualifié.

Puis-je durcir le noyau depuis un conteneur ? Pas pour kernel.* ni fs.* (lecture seule) ; seulement net.* et l'IPC namespacé. Durcissez l'hôte ou la VM, et le conteneur en hérite.