13. Permissions avancées#
La gestion des permissions sous Linux dépasse largement le modèle rwx de base appris en introduction. Ce chapitre explore les mécanismes complémentaires : bits spéciaux SUID/SGID/sticky, listes de contrôle d’accès POSIX, capabilities du noyau, attributs étendus et umask. La maîtrise de ces outils est indispensable pour sécuriser un système en production.
Rappel du modèle DAC#
Le contrôle d’accès discrétionnaire (DAC, Discretionary Access Control) est le modèle de base de Linux. Chaque fichier appartient à un propriétaire (UID) et à un groupe (GID). Les permissions sont définies pour trois catégories : le propriétaire (u), le groupe (g), les autres (o).
Bits de permission#
Chaque catégorie dispose de trois bits : lecture (r = 4), écriture (w = 2), exécution (x = 1).
-rwxr-x--- 1 alice devs 4096 mars 10 14:32 script.sh
Décomposition :
-: type régulier (d = répertoire, l = lien symbolique, c = char device…)rwx: propriétaire peut lire, écrire, exécuterr-x: groupe peut lire et exécuter---: les autres n’ont aucun droit
En octal, cette permission s’écrit 750 : 7 = rwx, 5 = r-x, 0 = ---.
UID/GID effectifs#
Lors de l’exécution d’un processus, le noyau maintient plusieurs identités :
Identité |
Description |
|---|---|
UID réel |
L’utilisateur qui a lancé le processus |
UID effectif |
L’identité utilisée pour les vérifications d’accès |
UID sauvegardé |
Copie de l’UID effectif avant un changement temporaire |
UID de système de fichiers |
Utilisé spécifiquement pour les accès aux fichiers |
Normalement, UID réel = UID effectif. Les bits spéciaux (SUID/SGID) modifient ce comportement.
Vérification des permissions#
Le noyau effectue la vérification dans l’ordre suivant :
Si l’UID effectif du processus est 0 (root) → accès accordé (presque toujours)
Si l’UID effectif correspond au propriétaire → bits du propriétaire appliqués
Si le GID effectif correspond au groupe → bits du groupe appliqués
Sinon → bits « autres » appliqués
Important
La vérification s’arrête à la première correspondance. Si un fichier appartient à alice avec les permissions ---rwxrwx, alice elle-même n’a aucun droit, même si elle fait partie du groupe.
SUID, SGID et sticky bit#
Ces trois bits occupent un quatrième octet dans la représentation octale des permissions.
SUID (Set User ID) — bit 4000#
Quand le bit SUID est positionné sur un exécutable, le processus s’exécute avec l’UID effectif du propriétaire du fichier, non de l’utilisateur qui le lance.
# Afficher les permissions de /usr/bin/passwd
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59976 janv. 25 2023 /usr/bin/passwd
Le s en position exécution du propriétaire indique le SUID. Quand alice exécute passwd, le processus tourne avec l’UID 0 (root), ce qui lui permet de modifier /etc/shadow.
Positionner le SUID :
chmod u+s /chemin/executable
# ou en octal :
chmod 4755 /chemin/executable
Cas d’usage légitimes :
/usr/bin/passwd— modification du mot de passe (accès à/etc/shadow)/usr/bin/sudo— élévation de privilèges contrôlée/usr/bin/ping— accès aux raw sockets (sur anciens systèmes)/usr/bin/su— changement d’identité
Dangers du SUID :
Un binaire SUID root mal écrit est un vecteur d’escalade de privilèges
Les scripts shell avec SUID sont ignorés par le noyau Linux (sécurité)
Tout fichier SUID root trouvé dans
/tmpou des répertoires utilisateur est suspect
Avertissement
Ne jamais positionner le bit SUID sur des interprètes (bash, python, perl) ou des éditeurs de texte. Cela offrirait immédiatement un accès root à quiconque peut exécuter le fichier.
SGID (Set Group ID) — bit 2000#
Sur un exécutable : le processus s’exécute avec le GID effectif du groupe propriétaire.
ls -l /usr/bin/write
-rwxr-sr-x 1 root tty 14328 avril 3 2022 /usr/bin/write
Le s en position exécution du groupe indique le SGID.
Sur un répertoire : tous les fichiers créés dans ce répertoire héritent du groupe du répertoire, quel que soit le groupe primaire de l’utilisateur créateur.
# Créer un répertoire partagé pour l'équipe devs
mkdir /srv/projet
chown root:devs /srv/projet
chmod 2775 /srv/projet
# Tout fichier créé aura le groupe devs
C’est le mécanisme fondamental des répertoires partagés en entreprise.
Sticky bit — bit 1000#
Sur un répertoire : un utilisateur ne peut supprimer ou renommer que ses propres fichiers, même s’il a le droit d’écriture sur le répertoire.
ls -ld /tmp
drwxrwxrwt 18 root root 4096 mars 24 09:15 /tmp
Le t final indique le sticky bit. Sans lui, n’importe quel utilisateur pourrait supprimer les fichiers des autres dans /tmp.
Positionner le sticky bit :
chmod +t /repertoire/partage
# ou en octal :
chmod 1777 /tmp
Note
Sur les anciens systèmes Unix, le sticky bit sur les exécutables conservait le programme en mémoire swap. Ce comportement est obsolète sous Linux moderne.
ACL POSIX#
Les ACL (Access Control Lists) POSIX permettent de définir des permissions pour des utilisateurs ou groupes supplémentaires, au-delà du modèle propriétaire/groupe/autres.
Prérequis#
Le système de fichiers doit être monté avec l’option acl (activée par défaut sur ext4 et XFS depuis le noyau 2.6).
# Vérifier le support ACL
tune2fs -l /dev/sda1 | grep "Default mount options"
Default mount options: user_xattr acl
Consulter les ACL — getfacl#
getfacl /srv/projet/rapport.txt
# file: srv/projet/rapport.txt
# owner: alice
# group: devs
user::rw-
user:bob:r--
user:charlie:rw-
group::r--
group:admins:rw-
mask::rw-
other::---
Modifier les ACL — setfacl#
# Donner les droits r-x à l'utilisateur bob
setfacl -m u:bob:rx /srv/projet/script.sh
# Donner les droits rw- au groupe audit
setfacl -m g:audit:rw /srv/projet/rapport.txt
# Supprimer l'ACL d'un utilisateur
setfacl -x u:bob /srv/projet/script.sh
# Supprimer toutes les ACL d'un fichier
setfacl -b /srv/projet/fichier.txt
Masque ACL#
Le masque (mask) est l”union maximale des droits accordés aux utilisateurs nommés, groupes nommés et au groupe propriétaire. Il agit comme un plafond.
# Réduire le masque à r-- (lecture seule pour tous les ACL)
setfacl -m mask::r-- /srv/projet/rapport.txt
Important
Quand chmod est utilisé sur un fichier avec ACL, il modifie le masque ACL (pas les entrées individuelles). Les droits du propriétaire et des « autres » sont toujours modifiés directement.
ACL par défaut sur les répertoires#
Les ACL par défaut s’appliquent aux nouveaux fichiers et sous-répertoires créés dans un répertoire.
# Définir une ACL par défaut : bob a toujours r-x sur les nouveaux fichiers
setfacl -d -m u:bob:rx /srv/projet/
# Vérifier
getfacl /srv/projet/
# file: srv/projet/
# owner: root
# group: devs
user::rwx
group::rwx
other::---
default:user::rwx
default:user:bob:r-x
default:group::rwx
default:mask::rwx
default:other::---
Interaction avec ls#
La présence d’ACL est signalée par un + après les permissions dans ls -l :
ls -l /srv/projet/rapport.txt
-rw-rw----+ 1 alice devs 2048 mars 24 10:00 rapport.txt
Capabilities Linux#
Les capabilities fragmentent les privilèges root en unités granulaires. Au lieu de donner tous les droits root à un programme, on lui accorde seulement les capabilities dont il a besoin.
Ensembles de capabilities#
Chaque thread possède cinq ensembles de capabilities :
Ensemble |
Description |
|---|---|
Permitted |
Capabilities que le thread peut activer |
Effective |
Capabilities actuellement actives (vérifiées par le noyau) |
Inheritable |
Capabilities transmissibles aux processus fils via |
Bounding |
Limite supérieure pour les capabilities héritables |
Ambient |
Capabilities héritées par les programmes non-SUID sans capabilities fichier |
Capabilities importantes#
Capability |
Usage |
|---|---|
|
Écouter sur un port < 1024 sans être root |
|
Utiliser des raw sockets (ping, tcpdump) |
|
Nombreuses opérations système (mount, sethostname…) |
|
Contourner les vérifications de permissions DAC |
|
Changer d’UID arbitrairement |
|
Changer le propriétaire d’un fichier |
|
Utiliser ptrace sur n’importe quel processus |
|
Envoyer des signaux à n’importe quel processus |
|
Configuration réseau avancée |
Avertissement
CAP_SYS_ADMIN est surnommée « la nouvelle root ». Elle englobe des dizaines d’opérations privilégiées. L’accorder est presque équivalent à accorder root.
Lire les capabilities — getcap#
# Capabilities d'un fichier
getcap /usr/bin/ping
/usr/bin/ping cap_net_raw=ep
La notation =ep signifie : la capability est dans les ensembles effective et permitted du fichier.
# Lister toutes les capabilities du système
getcap -r / 2>/dev/null
Modifier les capabilities — setcap#
# Permettre à nginx de s'attacher au port 443 sans root
setcap cap_net_bind_service=ep /usr/sbin/nginx
# Supprimer toutes les capabilities d'un fichier
setcap -r /usr/sbin/nginx
# Vérifier les capabilities d'un processus en cours
cat /proc/$(pgrep nginx | head -1)/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000000400
CapEff: 0000000000000400
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
Les valeurs sont des bitmasks hexadécimaux. L’outil capsh --decode=0x0400 les traduit en noms lisibles.
Remplacement du SUID#
Au lieu du bit SUID root sur ping :
# Ancienne méthode (SUID root)
chmod u+s /usr/bin/ping
# Méthode moderne (capability ciblée)
chmod u-s /usr/bin/ping
setcap cap_net_raw=ep /usr/bin/ping
Attributs étendus#
Les attributs étendus (xattr) permettent d’associer des métadonnées supplémentaires aux fichiers, en dehors du modèle de permissions standard.
Attributs chattr/lsattr#
Le système chattr/lsattr utilise des attributs spécifiques au système de fichiers (ext2/ext3/ext4) :
# Voir les attributs d'un fichier
lsattr /etc/passwd
----i--------e-- /etc/passwd
# Rendre un fichier immuable (root uniquement)
chattr +i /etc/resolv.conf
# Rendre un fichier append-only
chattr +a /var/log/audit/audit.log
# Retirer l'attribut immuable
chattr -i /etc/resolv.conf
Attributs importants#
Attribut |
Flag |
Description |
|---|---|---|
Immutable |
|
Aucune modification, suppression, renommage ou lien possible — même root |
Append-only |
|
Écriture en mode ajout uniquement (idéal pour les logs) |
No-dump |
|
Exclu des sauvegardes |
Secure delete |
|
Écrasement sécurisé lors de la suppression (fiabilité dépend du SSD/HDD) |
Synchronous |
|
Écriture synchrone immédiate sur disque |
No-atime |
|
Pas de mise à jour de l’atime (performance) |
Note
L’attribut +i protège même contre root. Pour modifier un fichier immutable, il faut d’abord retirer l’attribut avec chattr -i. Cela en fait un outil de protection contre les modifications accidentelles ou les attaques par ransomware sur les fichiers critiques.
Attributs étendus génériques (xattr)#
# Lire les xattr d'un fichier
getfattr -d /srv/projet/document.pdf
# Définir un xattr personnalisé (namespace user.*)
setfattr -n user.classification -v "confidentiel" /srv/projet/document.pdf
# Lire un xattr spécifique
getfattr -n user.classification /srv/projet/document.pdf
# file: srv/projet/document.pdf
user.classification="confidentiel"
umask#
L’umask est un masque de bits qui soustrait des permissions lors de la création de nouveaux fichiers et répertoires.
Principe de calcul#
La permission effective est : permission_maximale & ~umask
Fichiers : permission maximale =
666(pas d’exécution par défaut)Répertoires : permission maximale =
777
Avec umask 022 :
Fichier créé :
666 & ~022 = 666 & 755 = 644→rw-r--r--Répertoire créé :
777 & ~022 = 777 & 755 = 755→rwxr-xr-x
Avec umask 027 :
Fichier créé :
666 & ~027 = 640→rw-r-----Répertoire créé :
777 & ~027 = 750→rwxr-x---
Consulter et modifier l’umask#
# Voir l'umask courant
umask
# 0022
# Voir l'umask en notation symbolique
umask -S
# u=rwx,g=rx,o=rx
# Modifier l'umask pour la session
umask 027
Configuration persistante#
# Pour tous les utilisateurs (Debian/Ubuntu)
# /etc/profile ou /etc/profile.d/umask.sh
umask 022
# Pour un utilisateur spécifique
# ~/.bashrc ou ~/.profile
umask 027
umask via PAM#
# /etc/pam.d/common-session (Debian)
session optional pam_umask.so umask=027
# /etc/login.defs
UMASK 027
umask pour les services systemd#
# Dans l'unité systemd du service
[Service]
UMask=0027
Tip
Pour les services qui créent des fichiers sensibles (clés, tokens), utilisez umask 0077. Les fichiers seront en 600 et les répertoires en 700, inaccessibles aux autres utilisateurs.
Audit des permissions#
Trouver les fichiers SUID/SGID#
# Tous les fichiers SUID
find / -perm -4000 -type f 2>/dev/null
# Tous les fichiers SGID
find / -perm -2000 -type f 2>/dev/null
# SUID ou SGID
find / -perm /6000 -type f 2>/dev/null
# SUID root uniquement (les plus dangereux)
find / -user root -perm -4000 -type f 2>/dev/null
Détecter les permissions dangereuses#
# Fichiers world-writable (hors /tmp et /proc)
find / -perm -0002 -type f ! -path "/proc/*" ! -path "/tmp/*" 2>/dev/null
# Fichiers sans propriétaire (UID/GID non existant)
find / -nouser -o -nogroup 2>/dev/null
# Répertoires world-writable sans sticky bit
find / -type d -perm -0002 ! -perm -1000 ! -path "/proc/*" 2>/dev/null
Vérifier les capabilities non-standard#
# Lister toutes les capabilities sur le système
getcap -r / 2>/dev/null | grep -v "^/usr/bin/ping\|^/usr/bin/traceroute"
Démonstrations Python#
Lecture des permissions avec le module stat#
import os
import stat
import pwd
import grp
def afficher_permissions(chemin):
"""Affiche les permissions détaillées d'un fichier."""
try:
s = os.stat(chemin)
except PermissionError:
print(f"{chemin} : accès refusé")
return
except FileNotFoundError:
print(f"{chemin} : fichier introuvable")
return
mode = s.st_mode
perm_octal = oct(stat.S_IMODE(mode))
# Reconstruction rwx
def bits_rwx(m):
return (
("r" if m & 0o400 else "-") +
("w" if m & 0o200 else "-") +
("x" if m & 0o100 else "-") +
("r" if m & 0o040 else "-") +
("w" if m & 0o020 else "-") +
("x" if m & 0o010 else "-") +
("r" if m & 0o004 else "-") +
("w" if m & 0o002 else "-") +
("x" if m & 0o001 else "-")
)
# Bits spéciaux
suid = "SUID " if mode & stat.S_ISUID else ""
sgid = "SGID " if mode & stat.S_ISGID else ""
sticky = "Sticky" if mode & stat.S_ISVTX else ""
specials = (suid + sgid + sticky).strip() or "—"
try:
proprietaire = pwd.getpwuid(s.st_uid).pw_name
except KeyError:
proprietaire = str(s.st_uid)
try:
groupe = grp.getgrgid(s.st_gid).gr_name
except KeyError:
groupe = str(s.st_gid)
type_fichier = {
stat.S_IFREG: "fichier régulier",
stat.S_IFDIR: "répertoire",
stat.S_IFLNK: "lien symbolique",
stat.S_IFCHR: "char device",
stat.S_IFBLK: "block device",
stat.S_IFIFO: "FIFO",
stat.S_IFSOCK: "socket",
}.get(stat.S_IFMT(mode), "inconnu")
print(f"Fichier : {chemin}")
print(f"Type : {type_fichier}")
print(f"Octal : {perm_octal}")
print(f"rwx : {bits_rwx(mode)}")
print(f"Propriétaire: {proprietaire} (uid={s.st_uid})")
print(f"Groupe : {groupe} (gid={s.st_gid})")
print(f"Bits spéciaux: {specials}")
print(f"Taille : {s.st_size} octets")
print()
for fichier in ["/etc/passwd", "/etc/shadow", "/tmp"]:
afficher_permissions(fichier)
Fichier : /etc/passwd
Type : fichier régulier
Octal : 0o644
rwx : rw-r--r--
Propriétaire: root (uid=0)
Groupe : root (gid=0)
Bits spéciaux: —
Taille : 2663 octets
Fichier : /etc/shadow
Type : fichier régulier
Octal : 0o640
rwx : rw-r-----
Propriétaire: root (uid=0)
Groupe : shadow (gid=42)
Bits spéciaux: —
Taille : 1216 octets
Fichier : /tmp
Type : répertoire
Octal : 0o1777
rwx : rwxrwxrwx
Propriétaire: root (uid=0)
Groupe : root (gid=0)
Bits spéciaux: Sticky
Taille : 620 octets
Heatmap des permissions#
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import seaborn as sns
sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)
# Fichiers représentatifs avec leurs permissions en octal
fichiers = [
("/etc/passwd", 0o644),
("/etc/shadow", 0o640),
("/etc/sudoers", 0o440),
("/bin/bash", 0o755),
("/usr/bin/passwd", 0o4755), # SUID
("/usr/bin/sudo", 0o4111), # SUID
("/tmp", 0o1777), # Sticky
("/var/log/syslog", 0o640),
("/home/alice/.ssh", 0o700),
("/srv/partage", 0o2775), # SGID
]
categories = ["u:r", "u:w", "u:x", "g:r", "g:w", "g:x", "o:r", "o:w", "o:x"]
noms = [f[0].split("/")[-1] or f[0] for f in fichiers]
noms[6] = "/tmp"
noms[8] = ".ssh"
matrice = np.zeros((len(fichiers), 9), dtype=float)
for i, (_, perm) in enumerate(fichiers):
bits = perm & 0o777
for j, bit in enumerate([0o400, 0o200, 0o100, 0o040, 0o020, 0o010, 0o004, 0o002, 0o001]):
matrice[i, j] = 1.0 if (bits & bit) else 0.0
# Marquer les bits spéciaux en valeur différente
for i, (_, perm) in enumerate(fichiers):
if perm & 0o4000: # SUID
matrice[i, 2] = 2.0
if perm & 0o2000: # SGID
matrice[i, 5] = 2.0
if perm & 0o1000: # Sticky
matrice[i, 8] = 3.0
fig, ax = plt.subplots(figsize=(11, 6))
from matplotlib.colors import ListedColormap
cmap = ListedColormap(["#f0f0f0", "#4c9be8", "#e84c4c", "#f0c040"])
im = ax.imshow(matrice, cmap=cmap, aspect="auto", vmin=0, vmax=3)
ax.set_xticks(range(9))
ax.set_xticklabels(categories, fontsize=10)
ax.set_yticks(range(len(fichiers)))
ax.set_yticklabels(noms, fontsize=9)
for i in range(len(fichiers)):
for j in range(9):
val = matrice[i, j]
if val > 0:
label = {1.0: "✓", 2.0: "S", 3.0: "T"}.get(val, "")
couleur = "white" if val >= 2 else "#333333"
ax.text(j, i, label, ha="center", va="center", fontsize=9, color=couleur, fontweight="bold")
ax.set_title("Matrice des permissions — fichiers système représentatifs", fontsize=13, pad=14)
ax.set_xlabel("Bits de permission", fontsize=10)
ax.set_ylabel("Fichier", fontsize=10)
legende = [
mpatches.Patch(facecolor="#f0f0f0", edgecolor="gray", label="Pas de droit"),
mpatches.Patch(facecolor="#4c9be8", label="Droit actif"),
mpatches.Patch(facecolor="#e84c4c", label="SUID/SGID"),
mpatches.Patch(facecolor="#f0c040", label="Sticky bit"),
]
ax.legend(handles=legende, loc="upper right", bbox_to_anchor=(1.18, 1.0), fontsize=9)
plt.show()
Simulation d’audit SUID#
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)
# Liste simulée de fichiers SUID avec métadonnées
audit_suid = [
{"fichier": "/usr/bin/passwd", "proprio": "root", "taille": 59976, "legitime": True, "risque": 2},
{"fichier": "/usr/bin/sudo", "proprio": "root", "taille": 166056, "legitime": True, "risque": 2},
{"fichier": "/usr/bin/su", "proprio": "root", "taille": 67816, "legitime": True, "risque": 2},
{"fichier": "/usr/bin/newgrp", "proprio": "root", "taille": 39648, "legitime": True, "risque": 1},
{"fichier": "/usr/bin/chfn", "proprio": "root", "taille": 72712, "legitime": True, "risque": 1},
{"fichier": "/usr/bin/mount", "proprio": "root", "taille": 122784, "legitime": True, "risque": 2},
{"fichier": "/usr/bin/umount", "proprio": "root", "taille": 88408, "legitime": True, "risque": 1},
{"fichier": "/usr/sbin/pppd", "proprio": "root", "taille": 440664, "legitime": True, "risque": 2},
# Fichiers suspects simulés
{"fichier": "/tmp/.hidden/shell", "proprio": "root", "taille": 1234, "legitime": False, "risque": 5},
{"fichier": "/home/bob/backdoor", "proprio": "root", "taille": 8192, "legitime": False, "risque": 5},
{"fichier": "/opt/custom/helper", "proprio": "root", "taille": 12288, "legitime": False, "risque": 4},
]
df = pd.DataFrame(audit_suid)
# --- Affichage textuel ---
print("=== Rapport d'audit SUID ===\n")
print(f"Total fichiers SUID trouvés : {len(df)}")
print(f" Légitimes : {df['legitime'].sum()}")
print(f" Suspects : {(~df['legitime']).sum()}\n")
print("Fichiers suspects :")
suspects = df[~df["legitime"]][["fichier", "proprio", "taille", "risque"]]
print(suspects.to_string(index=False))
# --- Visualisation ---
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
# Graphique 1 : distribution des niveaux de risque
couleurs_risque = {1: "#4caf50", 2: "#ff9800", 3: "#ff5722", 4: "#d32f2f", 5: "#7b1fa2"}
comptes = df["risque"].value_counts().sort_index()
bars = axes[0].bar(
[f"Niveau {r}" for r in comptes.index],
comptes.values,
color=[couleurs_risque[r] for r in comptes.index],
edgecolor="white", linewidth=1.2
)
axes[0].set_title("Distribution des niveaux de risque\n(fichiers SUID)", fontsize=11)
axes[0].set_ylabel("Nombre de fichiers")
axes[0].set_xlabel("Niveau de risque")
for bar, val in zip(bars, comptes.values):
axes[0].text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.05,
str(val), ha="center", va="bottom", fontsize=10, fontweight="bold")
# Graphique 2 : scatter taille vs risque, coloré par légitimité
couleurs_pt = df["legitime"].map({True: "#4c9be8", False: "#e84c4c"})
axes[1].scatter(df["taille"] / 1024, df["risque"],
c=couleurs_pt, s=100, alpha=0.8, edgecolors="white", linewidth=0.8)
for _, row in df.iterrows():
nom_court = row["fichier"].split("/")[-1]
axes[1].annotate(nom_court, (row["taille"] / 1024, row["risque"]),
textcoords="offset points", xytext=(5, 3), fontsize=7, alpha=0.85)
axes[1].set_title("Taille vs niveau de risque\n(fichiers SUID)", fontsize=11)
axes[1].set_xlabel("Taille (Ko)")
axes[1].set_ylabel("Niveau de risque")
axes[1].set_yticks(range(1, 6))
import matplotlib.patches as mpatches
legende = [
mpatches.Patch(color="#4c9be8", label="Légitime"),
mpatches.Patch(color="#e84c4c", label="Suspect"),
]
axes[1].legend(handles=legende, fontsize=9)
plt.suptitle("Audit des fichiers SUID — résultats simulés", fontsize=13, y=1.01)
plt.show()
=== Rapport d'audit SUID ===
Total fichiers SUID trouvés : 11
Légitimes : 8
Suspects : 3
Fichiers suspects :
fichier proprio taille risque
/tmp/.hidden/shell root 1234 5
/home/bob/backdoor root 8192 5
/opt/custom/helper root 12288 4
Résumé#
Ce chapitre a couvert les mécanismes de contrôle d’accès avancés de Linux :
Modèle DAC et bits spéciaux
Le modèle rwx/UID/GID reste la base : les permissions sont vérifiées via l’UID effectif du processus
SUID (4000) et SGID (2000) modifient l’identité effective lors de l’exécution ou l’héritage de groupe dans les répertoires
Le sticky bit (1000) protège les fichiers dans les répertoires partagés
ACL POSIX
getfacl/setfaclpermettent des permissions granulaires par utilisateur ou groupe supplémentaireLe masque ACL est le plafond effectif des permissions ACL
Les ACL par défaut propagent les règles aux nouveaux fichiers
Capabilities
Remplacement moderne du bit SUID : chaque privilege est accordé individuellement
Cinq ensembles (permitted, effective, inheritable, bounding, ambient) contrôlent la propagation
getcap/setcappour inspecter et modifier
Attributs étendus
chattr +i(immutable) et+a(append-only) sont des protections complémentaires aux permissions standardRésistent même aux actions de root
umask
Masque appliqué lors de la création :
permission_max & ~umaskConfigurable par shell, PAM ou unité systemd
Audit
find -perm -4000/2000pour détecter les SUID/SGIDgetcap -r /pour inventorier les capabilitiesLes fichiers SUID hors des chemins système standards sont systématiquement suspects