Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
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é.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
page_inject — CVE-2026-31431-killed page-cache exploit — exécution de code dans des conteneurs partageant la même couche d'image | Kitploit
Outils/GitHubGitHub/sgkdev/page_inject
Analyse des VulnérabilitésExploitationPost-ExploitationTests d'IntrusionRed TeamingÉvasion de ConteneurExploitation de Binaires
GitHubsgkdev/page_inject

page_inject

CVE-2026-31431-killed page-cache exploit — exécution de code dans des conteneurs partageant la même couche d'image

Voir le dépôt
741470il y a 4 moisVérifié par Kitploit

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

page_inject - Évasion inter-conteneurs AF_ALG aead

Exploitation inter-conteneurs de la vulnérabilité AF_ALG aead -- pivot depuis un conteneur compromis vers chaque conteneur frère partageant la même couche d'image libc.so.6.

Il s'agit d'une primitive d'évasion : elle s'exécute depuis l'intérieur d'un conteneur non privilégié que l'attaquant a déjà compromis, et exploite le bug d'écriture arbitraire de 4 octets lié à la rotation ESN authencesn d'AF_ALG (CVE-2026-31431) pour implanter un hook read() persistant dans les pages du cache de pages de libc.so.6. Comme Docker / containerd adossent les fichiers de la couche inférieure d'overlayfs à des inodes partagés, ces pages sont visibles par chaque conteneur frère instancié à partir de la même image -- le hook se déclenche aussi dans leurs processus, et l'attaquant obtient l'exécution de commandes dans chacun d'eux.

Modèle de menace

  • L'attaquant dispose d'un accès shell à un seul conteneur (appelons-le victim) sur un hôte qui exécute d'autres conteneurs (siblings) à partir de la même image que victim.
  • victim s'exécute avec la posture Docker/k8s par défaut : uid non privilégié dans l'espace de noms utilisateur du conteneur, profil seccomp par défaut, profil AppArmor par défaut, aucune capacité spéciale, aucun montage bind de l'hôte.
  • victim dispose uniquement de :
    • un accès en lecture à sa propre libc (/usr/lib/x86_64-linux-gnu/libc.so.6 ou là où la distribution l'installe)
    • la famille d'appels système standard socket(AF_ALG, ...)
    • les appels système standards splice / vmsplice
    • un accès en écriture à un répertoire qu'il peut chmod +x (par exemple /tmp)
  • Le noyau doit être vulnérable à CVE-2026-31431 (toute compilation algif_aead + authencesn antérieure au correctif de réversion en amont).

C'est tout. Aucune CAP_* spéciale, aucun accès au système de fichiers de l'hôte. L'attaquant dépose un binaire autonome lié statiquement dans le conteneur, l'exécute, et la corruption du cache de pages -- et donc le hook -- devient visible pour chaque conteneur frère.

Comment l'exploitation s'enchaîne

  1. Identité des pages du cache de pages. Dans un conteneur overlayfs, /usr/lib/.../libc.so.6 est servi par l'inode ext4 de la couche inférieure de l'image. Chaque conteneur démarré à partir de la même image partage cet inode sous-jacent, et le cache de pages du noyau est indexé par l'inode sous-jacent -- pas par l'overlay ni par l'espace de noms. Une simple écriture de 4 octets dans une page du cache de pages est donc visible par tous les processus des conteneurs frères qui ont cette page mmapée.

  2. La vulnérabilité AF_ALG aead transforme une telle écriture en plusieurs. algif_aead chaîne l'iovec RX utilisateur avec les octets authsize de fin du SGL TX splicé, et la rotation ESN d'authencesn dépose 4 octets du champ seq_high de l'AAD à dst[assoclen + cryptlen] -- soit le premier octet de cette queue étrangère chaînée. La page splicée est une page du cache de pages d'un fichier auquel l'attaquant n'a qu'un accès en lecture, mais le chiffreur y copie quand même des octets, sans comptabilité de pages sales. (Voir crypto/algif_aead.c et crypto/authencesn.c pour les mécanismes sous-jacents.)

  3. Amorçage d'une primitive appelable. La première chose que fait page_inject est d'amorcer Zone A -- une ré-implémentation encodée en asm du même manège AF_ALG (write_cache.asm), placée dans la cavité .text de la libc. Cela fait de l'écriture de 4 octets un simple call depuis n'importe quelle future charge utile de hook, sans configuration de socket à chaque appel.

  4. Installation du hook. L'injecteur écrit ensuite Zone C (zone_c.asm) dans la cavité .text de la libc et patch les 7 à 12 premiers octets de read() avec un saut E9 disp32 vers elle. Les octets déplacés du prologue sont émulés fidèlement dans le chemin rapide de Zone C (trois prologues glibc différents sont reconnus -- voir « Gestion du prologue de read() » ci-dessous). Le hook est désormais actif dans le cache de pages de la libc.

  5. Propagation du hook. Chaque conteneur frère exécute des processus qui appellent read() constamment (démons de journalisation, healthchecks, cat /etc/hostname, n'importe quoi). Au premier appel de ce type dans un conteneur frère, le prologue détourné saute dans Zone C, qui :

    • appelle stat("/") sur l'inode racine du conteneur (un ID stable par espace de noms) et l'utilise comme clé de slot du conteneur,
    • parcourt la table de slots pour trouver une entrée existante avec cette clé,
    • si elle est absente, enregistre la clé et fork() un enfant de boucle de commandes de longue durée qui interroge la zone CMD à la recherche d'ordres,
    • revient à read()+N afin que l'appelant n'y voie que du feu. Le processus frère d'origine continue de s'exécuter. Dès lors, l'attaquant dispose d'un démon dans ce conteneur.
  6. Canal de commande. L'attaquant utilise le même binaire page_inject en mode --shell pour écrire des commandes dans la zone CMD de la région de slots. L'enfant hook de chaque conteneur frère enregistré interroge, fork /bin/sh -c <cmd>, capture stdout/stderr dans la zone OUTPUT, signale la fin, puis reprend son interrogation. Le shell affiche la sortie. Comme chaque écriture CMD/OUTPUT passe également par la primitive de la vulnérabilité, aucun privilège spécial n'est nécessaire.

  7. Désinstallation du hook. Une fois l'opération terminée, unhook restaure les octets d'origine du prologue de read() et met la table de slots à zéro ; les enfants hooks voient un slot vide à leur prochaine itération et s'arrêtent d'eux-mêmes. Les modifications du cache de pages elles-mêmes sont propres (le noyau n'a jamais marqué les pages modifiées comme sales), donc une fois que chaque conteneur ayant la libc mmapée est arrêté, un drop_caches rétablit intégralement le cache -- aucune artefact sur disque ne subsiste.

Compilation

L'injecteur est compilé à l'extérieur du conteneur victime -- généralement sur la machine de développement de l'attaquant -- car la plupart des images de conteneurs de production ne fournissent pas de compilateur. Un environnement de développement Linux x86_64 standard avec gcc (prenant en charge la liaison -static) et nasm suffit.

make            # assembles .asm sources via gen_arrays.sh, links static page_inject
make shellcode  # also produces inspectable .bin flat binaries
make clean      # removes generated files and the binary

Le résultat est un unique ELF statique (./page_inject) qui s'exécute sur tout noyau Linux x86_64 moderne.

Livraison et utilisation (depuis le conteneur victime)

Une fois que l'attaquant a un shell sur victim, il téléverse le binaire dans un répertoire accessible en écriture (généralement /tmp) :

# inside the compromised container, attacker session
victim$ ./page_inject

Sans argument, page_inject utilise par défaut /usr/lib/x86_64-linux-gnu/libc.so.6 (l'emplacement Debian/Ubuntu post-merge). Pour les autres distributions, la libc se trouve à un autre chemin ; on peut soit la passer explicitement, soit utiliser --root / pour analyser la table de correspondance intégrée depuis la racine du conteneur :

# Fedora / Rocky / CentOS
victim$ ./page_inject /usr/lib64/libc.so.6

# Arch
victim$ ./page_inject /usr/lib/libc.so.6

# Auto-detect, regardless of distro:
victim$ ./page_inject --root /

Les deux invocations font la même chose : parser l'ELF de la libc du conteneur, installer le hook dans son cache de pages, surveiller la table de slots pendant ~30 s pendant que les conteneurs frères s'enregistrent, et exécuter un id ponctuel contre le premier frère enregistré à titre de vérification.

Après le bootstrap, on bascule dans le shell de commande pour piloter n'importe quel frère enregistré :

Télécharger l’outil