Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
harden-docker-seccomp — Atténuation Docker pour CVE-2026-31431 (« Copy Fail »). Inclut également des modèles Kubernetes. | Kitploit
Outils/GitHubGitHub/devstuff/harden-docker-seccomp
Sécurité de l'Infrastructure CloudOutils DéfensifsSécurité des ConteneursAnalyse des VulnérabilitésAudit de ConfigurationDevSecOps
GitHubdevstuff/harden-docker-seccomp

harden-docker-seccomp

Atténuation Docker pour CVE-2026-31431 (« Copy Fail »). Inclut également des modèles Kubernetes.

Voir le dépôt
21il y a 3 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

harden-docker-seccomp

Script idempotent pour bloquer la création de sockets AF_ALG pour tous les conteneurs Docker sur un hôte, en tant qu'atténuation de CVE-2026-31431 (« Copy Fail »).

Contexte

CVE-2026-31431 est une élévation de privilèges locale dans le modèle cryptographique authencesn du noyau Linux, présente dans les noyaux compilés entre 2017 et la disponibilité du correctif en amont (commit mainline a664bf3d603d). Un utilisateur non privilégié peut enchaîner une opération de socket AF_ALG avec splice() pour effectuer une écriture contrôlée de 4 octets dans le cache de pages de n'importe quel fichier lisible, ciblant un binaire setuid pour obtenir un shell root. Une preuve de concept Python de 732 octets exploite cela de manière fiable, sans courses ni offsets spécifiques aux distributions, sur chaque grande distribution Linux livrant un noyau affecté.

La première étape obligatoire de l'exploit est l'ouverture d'un socket AF_ALG (socket(AF_ALG, SOCK_SEQPACKET, 0)). Bloquer cet appel système via seccomp empêche l'exploitation même sur des noyaux non corrigés. Le profil seccomp par défaut intégré de Docker ne bloque pas , et n'est pas suffisant — les clusters testés ont montré que les pods admis sous PSS Restricted pouvaient toujours ouvrir des sockets .

AF_ALG
RuntimeDefault
AF_ALG

Voir l'avis du chercheur original sur https://copy.fail et l'avis CERT-EU sur https://cert.europa.eu/publications/security-advisories/2026-005/ pour tous les détails techniques et la disponibilité des correctifs par distribution.

Portée de cet outil

Ce script couvre la configuration globale du démon Docker Engine. Pour Kubernetes, voir la section Kubernetes ci-dessous. Pour les charges de travail bare-metal ou VM (non conteneurisées), désactivez plutôt le module noyau algif_aead :

root@kitploit:~
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true

Cette approche n'a aucun impact sur dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS ou SSH.

Comment cela fonctionne

  1. Extrait le profil seccomp intégré actif de Docker en inspectant le HostConfig.SecurityOpt d'un conteneur éphémère. Cela évite toute dépendance à une URL distante et garantit que le profil de base correspond à la version de Docker réellement installée. Une récupération GitHub depuis moby/profiles n'est utilisée comme solution de repli que si l'inspection du conteneur ne donne rien.

  2. Corrige le profil en supprimant socket de l'entrée de liste blanche de Docker et en le ré-ajoutant avec un filtre d'arguments qui autorise toutes les familles d'adresses sauf AF_ALG (valeur 38) en utilisant SCMP_CMP_NE. Tout le reste du comportement seccomp par défaut de Docker est préservé.

  3. Écrit le profil corrigé de manière atomique dans /etc/seccomp/docker-block-af-alg.json (fichier temporaire + renommage). Ignoré si le contenu sur disque est déjà identique.

  4. Met à jour /etc/docker/daemon.json pour définir "seccomp-profile" sur le chemin du profil corrigé. Le fichier original est sauvegardé dans daemon.json.bak lors de la première modification. Ignoré si déjà configuré correctement.

  5. Recharge dockerd via systemctl reload docker (SIGHUP — aucun redémarrage requis). Ignoré si aucun des deux fichiers n'a changé.

  6. Vérifie que le blocage est actif en exécutant une sonde dans un conteneur, indépendamment du fait que des modifications aient été apportées ou non aux étapes ci-dessus.

Le script est idempotent : l'exécuter plusieurs fois produit le même résultat et ne recharge Docker que lorsque quelque chose a réellement changé.

Remarque : les conteneurs --privileged contournent tous les profils seccomp, quelle que soit cette configuration. Auditez vos fichiers Compose et vos commandes d'exécution pour les conteneurs privilégiés séparément.

Prérequis

  • Python 3.12+
  • Docker Engine (pas Docker Desktop) exécuté sur l'hôte
  • CLI docker dans le PATH
  • curl dans le PATH (solution de repli uniquement)
  • systemctl (hôte systemd)
  • Root / sudo pour les écritures dans /etc/seccomp et /etc/docker, et pour systemctl reload docker

Utilisation

root@kitploit:~
# Appliquer l'atténuation et vérifier (utilisation normale)
sudo python3 harden-docker-seccomp.py

# Afficher ce qui changerait sans rien écrire ni recharger Docker
sudo python3 harden-docker-seccomp.py --dry-run

# Ré-exécuter uniquement la vérification du conteneur (aucune modification de configuration)
python3 harden-docker-seccomp.py --verify-only

# Sortie verbeuse
sudo python3 harden-docker-seccomp.py --verbose

Sortie attendue (première exécution)

root@kitploit:~
INFO Written: /etc/seccomp/docker-block-af-alg.json
INFO Updated: /etc/docker/daemon.json
INFO Reloading Docker daemon (SIGHUP)…
INFO Docker daemon reloaded.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

Sortie attendue (exécutions suivantes)

root@kitploit:~
INFO Profile unchanged: /etc/seccomp/docker-block-af-alg.json
INFO daemon.json already configured correctly.
INFO No changes — Docker daemon reload not required.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

Codes de sortie

CodeSignification
0Succès — l'atténuation est active
1Script non exécuté en root (lors du patch), ou erreur irrécupérable
2Échec de la vérification — AF_ALG n'est pas bloqué

Kubernetes

Les pods Kubernetes partagent le noyau de l'hôte, donc la même primitive de socket AF_ALG est accessible depuis n'importe quel pod sur un nœud affecté. Le seccomp RuntimeDefault n'est pas suffisant — les clusters testés ont montré que les pods admis sous PSS Restricted pouvaient toujours ouvrir des sockets AF_ALG. Un profil Localhost avec une règle de refus explicite est requis.

L'atténuation nécessite deux choses : le JSON du profil présent sur le système de fichiers de chaque nœud, et chaque spécification de pod le référençant. Les sections ci-dessous couvrent les deux, y compris comment injecter le profil globalement sans modifier les spécifications de pods individuelles.

Étape 1 — Distribuer le profil sur chaque nœud

Le kubelet résout les profils seccomp Localhost par rapport à sa racine seccomp, qui par défaut est /var/lib/kubelet/seccomp. Le profil doit exister à ce chemin sur chaque nœud pouvant planifier une charge de travail.

Appliquez la ConfigMap et le DaemonSet de ce dépôt :

root@kitploit:~
kubectl apply -f templates/configmap-seccomp-profile.yaml
kubectl apply -f templates/daemonset-distribute-profile.yaml

Le DaemonSet exécute un conteneur init qui copie le profil depuis la ConfigMap vers la racine seccomp du kubelet du nœud, puis stationne un conteneur pause minimal pour que le pod reste visible pour la surveillance de santé. Il tolère toutes les taints afin de s'exécuter également sur les nœuds du plan de contrôle.

Racine seccomp kubelet non standard : RKE2 utilise /var/lib/rancher/rke2/agent/kubelet/seccomp. Remplacez le chemin en définissant NODE_SECCOMP_ROOT dans l'environnement du conteneur init du DaemonSet avant l'application.

Vérifiez que le fichier est présent sur un nœud :

root@kitploit:~
kubectl -n kube-system exec -it \
  $(kubectl -n kube-system get pod -l app.kubernetes.io/name=distribute-af-alg-seccomp \
    -o jsonpath='{.items[0].metadata.name}') -- \
  cat /var/lib/kubelet/seccomp/block-af-alg.json

Étape 2 — Injecter le profil dans chaque pod (aucune modification de spécification de pod requise)

Plutôt que de modifier les spécifications de pods individuelles ou les charts Helm, utilisez un webhook d'admission mutant pour injecter seccompProfile automatiquement au moment de l'admission. Deux options sont fournies : Kyverno et OPA Gatekeeper.

Les deux approches n'injectent le profil que lorsqu'un pod n'en déclare pas déjà un, donc les pods avec des profils explicites sont laissés intacts.

Important : Les pods existants en cours d'exécution ne sont pas mutés rétroactivement. Après avoir appliqué la politique, redémarrez vos déploiements pour prendre en compte le profil injecté :

root@kitploit:~
kubectl rollout restart deployment -A

Option A — Kyverno

Ce modèle utilise l'API MutatingPolicy (policies.kyverno.io/v1), qui a atteint la disponibilité générale dans Kyverno 1.17. L'API héritée ClusterPolicy (kyverno.io/v1) a été dépréciée dans Kyverno 1.17 (janvier 2026) et est prévue pour suppression dans 1.20 (octobre 2026) ; ne l'utilisez pas pour de nouvelles politiques.

L'expression CEL matchConditions vérifie que seccompProfile est absent avant de muter, donc les pods qui déclarent déjà un profil sont laissés intacts.

root@kitploit:~
# Installer Kyverno (si pas déjà présent)
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace

# Appliquer la politique
kubectl apply -f templates/kyverno-mutate-seccomp.yaml

Vérifiez qu'un nouveau pod reçoit le profil injecté :

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# Attendu : {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

Voir templates/kyverno-mutate-seccomp.yaml.

Option B — OPA Gatekeeper

Le CRD de mutation Assign de Gatekeeper utilise une condition pathTests pour injecter le profil uniquement lorsque spec.securityContext.seccompProfile n'existe pas déjà. La mutation est stable depuis Gatekeeper 3.10+ ; aucun indicateur de fonctionnalité n'est requis.

root@kitploit:~
# Installer Gatekeeper (si pas déjà présent)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper \
  --create-namespace

# Appliquer la mutation
kubectl apply -f templates/gatekeeper-assign-seccomp.yaml

Vérifiez :

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# Attendu : {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

Voir templates/gatekeeper-assign-seccomp.yaml.

Gatekeeper vs. Kyverno : L'approche Assign opère au niveau du champ et nécessite que le webhook de mutation de Gatekeeper soit activé. Le MutatingPolicy de Kyverno avec un matchCondition CEL gère le conditionnel en ligne. Les deux atteignent le même résultat — préférez celui qui est déjà déployé dans votre cluster.

Ce que cela ne couvre pas

Les pods avec hostPID: true, hostNetwork: true, ou securityContext.privileged: true ont un accès élevé que seccomp seul ne contient pas entièrement. Auditez ces charges de travail séparément et supprimez les privilèges lorsque c'est possible.

Notes de conception des modèles

La ConfigMap comme source de vérité. Le JSON du profil réside dans configmap-seccomp-profile.yaml plutôt que d'être intégré dans le DaemonSet ou dupliqué entre les fichiers. Le DaemonSet le monte et le copie sur le nœud. Mettre à jour le profil signifie modifier une ConfigMap et redémarrer les pods du DaemonSet — aucun autre fichier ne change.

Le DaemonSet utilise la priorité system-node-critical. Cela garantit que le pod de distribution n'est pas expulsé avant que les charges de travail qu'il protège ne soient planifiées, ce qui laisserait les nœuds avec un fichier de profil manquant et des pods bloqués dans CreateContainerError.

Gatekeeper exclut kube-system et gatekeeper-system. Injecter un profil Localhost dans des pods système qui peuvent précéder l'installation du DaemonSet risque une référence de profil cassée si le fichier n'est pas encore présent sur le nœud. La politique Kyverno n'a pas besoin de cette exclusion car Kyverno gère l'ordre des webhooks plus gracieusement, mais des règles exclude peuvent être ajoutées là aussi si nécessaire.

Injection conditionnelle, pas de remplacement. À la fois le matchCondition CEL du MutatingPolicy Kyverno et le test de chemin MustNotExist de Gatekeeper signifient que la politique d'admission n'agit que lorsqu'un pod n'a pas de seccompProfile existant. Les charges de travail qui déclarent déjà leur propre profil — y compris celles qui ont légitimement besoin de AF_ALG via une liste blanche personnalisée — sont laissées intactes.

Références

  • https://copy.fail — Avis du chercheur original (Xint)
  • https://cert.europa.eu/publications/security-advisories/2026-005/ — Avis CERT-EU
  • https://www.cve.org/CVERecord?id=CVE-2026-31431 — Enregistrement CVE
  • https://security-tracker.debian.org/tracker/CVE-2026-31431 — Suivi de sécurité Debian
  • https://docs.docker.com/engine/security/seccomp/ — Documentation seccomp Docker
  • https://github.com/moby/profiles — Profil seccomp par défaut canonique Docker
  • https://kyverno.io/docs/kyverno-policies/ — Documentation des politiques Kyverno
  • https://open-policy-agent.github.io/gatekeeper/website/docs/mutation/ — Documentation de mutation Gatekeeper

Oui, Claude a fait la plupart du travail, voici la conversation

https://gist.github.com/devstuff/3ff3ca0139e2a2da7f1ee5875802f76f

Télécharger l’outil