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
Outils/GitHubGitHub/starscow/copy-fail-cve-2026-31431-kubernetes-poc
Escalade de PrivilègesAnalyse des VulnérabilitésExploitationApprentissage et ÉducationÉvasion de Conteneur
GitHubstarscow/copy-fail-cve-2026-31431-kubernetes-poc

Copy-Fail-CVE-2026-31431-Kubernetes-PoC

Preuve de concept démontrant une évasion de conteneur sur Kubernetes via la corruption du cache de pages du noyau CVE-2026-31431, permettant l'exécution de code au niveau du nœud depuis un conteneur non privilégié.

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
Voir le dépôt
il y a 4 moisPas encore vérifié

Copy Fail (CVE-2026-31431) — Preuve de concept d'évasion de conteneur Kubernetes

Une preuve de concept démontrant comment un conteneur totalement non privilégié peut atteindre une exécution de code au niveau du nœud sur Kubernetes en exploitant le bug de corruption du cache de pages du noyau Linux CVE-2026-31431 via les couches d'images conteneur partagées.

Avertissement : Ce dépôt est publié à des fins éducatives et défensives uniquement. Utilisez-le exclusivement sur des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation explicite de test.

Contexte

CVE-2026-31431 (« Copy Fail ») est une vulnérabilité du noyau Linux dans le chemin Copy-on-Write (CoW) du cache de pages. Une course AF_ALG splice permet à un processus non privilégié de corrompre les pages du cache de pages d'un fichier en lecture seule. La corruption persiste dans le cache de pages du noyau et est visible par chaque processus qui lit ou exécute ensuite le fichier — y compris les processus d'autres conteneurs ou de l'hôte.

Pour tous les détails sur la vulnérabilité d'origine, voir copy.fail.

Comment ça fonctionne

La chaîne d'attaque comporte trois étapes : corruption du cache de pages, propagation inter-conteneurs et exécution privilégiée.

1. Corruption du cache de pages via la course AF_ALG splice

Le sous-système AF_ALG (crypto) du noyau expose une interface basée sur les sockets pour les opérations cryptographiques de l'espace utilisateur. L'exploit abuse d'une condition de course dans la façon dont le noyau gère splice() depuis un fichier vers un socket AF_ALG :

  1. Ouvrir le binaire cible (par ex. /usr/sbin/ipset) en lecture seule.
  2. Créer un socket AF_ALG AEAD lié à authesn(hmac(sha256),cbc(aes)).
  3. Envoyer un petit morceau de charge utile à travers le socket AF_ALG avec MSG_MORE, indiquant au noyau d'attendre plus de données.
  4. splice() le contenu du fichier cible depuis un fd → pipe → socket AF_ALG.
  5. En raison du bug CoW, le noyau écrit les octets de la charge utile de l'attaquant dans les pages du cache de pages du fichier cible au lieu de les isoler correctement.

L'exploit répète cette opération pour chaque fenêtre de 4 octets jusqu'à ce que toutes les pages en cache du binaire cible soient écrasées avec une charge utile personnalisée.

Aucune permission d'écriture sur le fichier n'est nécessaire. Le fichier sur disque est inchangé — seul le cache de pages en mémoire est corrompu.

2. Propagation inter-conteneurs via le partage de couches d'images

Les runtimes de conteneurs (containerd, CRI-O) utilisent des systèmes de fichiers overlay. Lorsque deux conteneurs partagent la même couche d'image, le noyau sert leurs lectures de fichiers depuis les mêmes pages du cache de pages.

Cette image PoC est construite FROM registry.k8s.io/kube-proxy:v1.35.2. Le DaemonSet kube-proxy sur chaque nœud Kubernetes utilise exactement la même couche de base. Par conséquent, /usr/sbin/ipset dans les deux conteneurs correspond au même ensemble de pages du cache de pages.

Lorsque le conteneur PoC non privilégié corrompt le cache de pages d'ipset, la corruption est immédiatement visible par le conteneur kube-proxy privilégié sur le même nœud — sans aucune communication inter-conteneurs.

3. Exécution privilégiée par kube-proxy

kube-proxy s'exécute en tant que DaemonSet privilégié avec hostNetwork: true. Il invoque périodiquement /usr/sbin/ipset pour gérer les règles iptables/ipset. Lorsqu'il exécute ensuite ipset, le noyau charge les pages corrompues du cache de pages, exécutant la charge utile de l'attaquant avec tous les privilèges de kube-proxy :

  • Root complet sur le nœud
  • Toutes les capacités
  • Accès aux namespaces de l'hôte

La charge utile de cette PoC (payload/payload.c) monte simplement le système de fichiers racine de l'hôte et écrit un fichier marqueur dans /root/res comme preuve d'exécution de code au niveau du nœud.

Diagramme du flux d'attaque

root@kitploit:~
┌──────────────────────────┐     ┌──────────────────────────┐
│   Conteneur PoC          │     │   Conteneur kube-proxy   │
│   (non privilégié)       │     │   (privilégié)           │
│                          │     │                          │
│  1. Ouvre /usr/sbin/ipset│     │                          │
│     (lecture seule)      │     │                          │
│                          │     │                          │
│  2. Course AF_ALG splice │     │                          │
│     corrompt le cache    │     │                          │
│     de pages             │     │                          │
│          │               │     │                          │
└──────────┼───────────────┘     └──────────────────────────┘
           │                                  │
           ▼                                  │
  ┌─────────────────────┐                     │
  │  Cache de pages du  │                     │
  │  noyau              │                     │
  │  /usr/sbin/ipset    │◄────────────────────┘
  │  (CORROMPU)         │     3. kube-proxy exécute ipset
  │  contient les octets│        → charge les pages corrompues
  │  de la charge utile │        → la charge utile s'exécute en root
  │  de l'attaquant     │           sur l'hôte
  └─────────────────────┘

Structure du dépôt

root@kitploit:~
.
├── cmd/copyfail/main.go          # Point d'entrée ; intègre la charge utile compilée
├── internal/
│   ├── exploit/
│   │   ├── exploit.go            # Exploit principal : boucle de course AF_ALG splice
│   │   └── patch.go              # Divise la charge utile en fenêtres de patch de 4 octets
│   └── alg/
│       └── alg.go                # Abstraction du socket AF_ALG AEAD
├── payload/
│   ├── payload.c                 # Charge utile de validation (monte le fs hôte, écrit le marqueur)
│   └── nolibc/                   # Mini libc du noyau pour charges utiles statiques sans dépendances
├── deploy/
│   └── poc.yaml                  # Manifeste de déploiement Kubernetes
├── Dockerfile                    # Construit FROM kube-proxy pour partager les couches d'images
├── Makefile                      # Orchestration de compilation
└── docs/                         # Preuves de validation d'ACK (Alibaba Cloud)

Prérequis

  • Go 1.25+
  • Un compilateur croisé pour la charge utile nolibc (défaut : x86_64-linux-gnu-gcc)
  • Docker / Buildx
  • Un cluster Kubernetes exécutant kube-proxy en tant que DaemonSet avec imagePullPolicy: IfNotPresent (par défaut)
  • Noyau Linux antérieur au correctif CVE-2026-31431

Compilation

root@kitploit:~
# Compiler la charge utile + le binaire Go
make build

# Compiler l'image Docker
make docker-build

# Compiler et pousser vers GHCR
make docker-push IMAGE=ghcr.io/<vous>/copy-fail-poc TAG=latest

Pour les cibles arm64 :

root@kitploit:~
make build CC=aarch64-linux-gnu-gcc GOARCH=arm64

Utilisation

Déployer la PoC

root@kitploit:~
kubectl apply -f deploy/poc.yaml

Le Deployment crée un seul pod non privilégié. Il :

  1. Exécute /bin/copyfail -target /usr/sbin/ipset pour corrompre le cache de pages.
  2. Dort indéfiniment pour que le pod reste actif à des fins d'observation.

Vérifier l'évasion

Après que kube-proxy exécute ensuite ipset (cela se produit généralement en quelques secondes en raison de sa boucle de réconciliation, ou lors de son prochain redémarrage), vérifiez le nœud :

root@kitploit:~
# SSH dans le nœud, ou utilisez un pod de débogage privilégié
cat /root/res
# Sortie attendue : [*] success

La présence de /root/res sur le système de fichiers de l'hôte prouve que le code fourni par l'attaquant s'est exécuté avec des privilèges au niveau du nœud — écrit depuis le contexte du conteneur privilégié de kube-proxy.

Nettoyage

root@kitploit:~
kubectl delete -f deploy/poc.yaml

# Sur le(s) nœud(s) affecté(s), supprimez le marqueur et redémarrez kube-proxy :
rm -f /root/res
systemctl restart kubelet   # ou supprimez le pod kube-proxy pour forcer un re-tirage

Pourquoi kube-proxy + ipset ?

kube-proxy est une cible idéale car il est :

  1. Présent sur chaque nœud — s'exécute en tant que DaemonSet.
  2. Hautement privilégié — privileged: true, hostNetwork: true.
  3. Fournit ipset dans son image — ipset est un binaire setuid utilisé pour la gestion iptables.
  4. Utilise imagePullPolicy: IfNotPresent — une fois que l'image de l'attaquant est tirée et partage la même couche de base, les pages du répertoire inférieur overlay sont partagées.

Tout DaemonSet privilégié dont l'image contient un binaire prévisible pourrait être ciblé de la même manière.

Personnalisation de la charge utile

La charge utile par défaut (payload/payload.c) est un programme de validation uniquement qui écrit un fichier marqueur. Pour construire une charge utile personnalisée :

  1. Modifiez payload/payload.c. Le programme est compilé contre nolibc (la bibliothèque C minimale du noyau) pour un binaire statique sans dépendances.
  2. Exécutez make payload pour compiler en croisé.
  3. La charge utile compilée est intégrée dans le binaire Go via //go:embed.

Versions affectées

  • Noyau Linux : Toutes les versions antérieures au correctif CVE-2026-31431.
  • Kubernetes : Toute version utilisant un noyau de nœud non corrigé. La vulnérabilité se trouve dans le noyau, pas dans Kubernetes lui-même. Kubernetes fournit simplement le contexte d'exécution (couches d'images partagées + DaemonSets privilégiés) qui élève l'impact d'une corruption locale du cache de pages à une évasion complète de conteneur.

Atténuation

  • Corrigez le noyau. C'est le correctif définitif.
  • Activez l'isolation des couches d'images. Certains runtimes prennent en charge des instantanés de systèmes de fichiers par conteneur qui empêchent le partage du cache de pages.
  • Utilisez des systèmes de fichiers racine en lecture seule pour kube-proxy (n'atténue pas complètement, mais limite les capacités de la charge utile).
  • Restreignez l'ordonnancement des pods pour empêcher les charges de travail non fiables d'atterrir sur des nœuds exécutant des DaemonSets privilégiés avec des images de base partagées.

Crédits

  • Découverte et divulgation de CVE-2026-31431 : Theori / Xint
  • Charge utile C multiplateforme : Tony Gies (LGPL-2.1-or-later OU MIT)
  • nolibc : Tests du noyau Linux (tools/include/nolibc/)

Licence

Le code d'exploit Go de ce dépôt est fourni tel quel à des fins de recherche.

La charge utile (payload/payload.c) est dérivée de copy-fail-c et est sous double licence LGPL-2.1-or-later OU MIT. Voir LICENSE-LGPL et LICENSE-MIT.

Télécharger l’outil