Aller au contenu principal

L'attaque en 3 commandes : de simple utilisateur à root

Un administrateur a autorisé un agent à utiliser une seule commande, pensée comme inoffensive. Trois commandes plus tard, cet agent est root.

Petite vérification​

Avant de commencer, vérifiez si vous savez encore réaliser ces 3 actions très simples, sur la séance précédente consacrée à la vérification d'une fuite de mots de passe :

  1. calculer l'empreinte SHA-1 du texte azerty avec printf '%s' 'azerty' | sha1sum, et vérifier qu'elle commence bien par 9cf95
  2. citer la commande qui permet de saisir un mot de passe sans qu'il s'affiche à l'écran ni n'apparaisse dans l'historique du terminal
  3. expliquer pourquoi être absent de la base Pwned Passwords ne signifie pas qu'un mot de passe est sûr
📌 Réponse attendue

TP pour réfléchir et résoudre des problèmes​

Votre défi pour aujourd'hui consiste à obtenir un accès root sur un serveur, en exploitant une seule ligne de configuration mal écrite, puis à la corriger

info

La mairie de Verchamps et son serveur intranet sont fictifs, construits pour l'exercice. Toutes les manipulations se font dans votre propre VM Debian.

attention

Obtenir un accès root sur une machine sans y être autorisé est un accès frauduleux (article 323-1 du code pénal), comme vu lors de la séance sur l'accès physique. Ce TP se pratique uniquement sur votre propre VM.

Étape 1 — Reproduire la configuration d'origine, côté administrateur​

À la mairie de Verchamps, un agent administratif doit régulièrement vérifier l'espace disque disponible sur le serveur. Pour lui éviter de demander le mot de passe root à chaque fois, l'administrateur précédent lui a accordé un droit sudo qu'il pensait sans danger.

Dans votre VM, en tant qu'administrateur (votre compte habituel, avec les droits sudo complets), reproduisez cette configuration :

sudo adduser agent --disabled-password --gecos ""
echo 'agent ALL=(ALL) NOPASSWD: /usr/bin/find' | sudo tee /etc/sudoers.d/agent
sudo chmod 440 /etc/sudoers.d/agent
sudo visudo -c -f /etc/sudoers.d/agent
  1. À quoi sert l'option --disabled-password de adduser ? (pour cet exercice, vous passerez du compte administrateur au compte agent avec su -, sans mot de passe à saisir)
  2. Que permet la dernière ligne (visudo -c -f), et pourquoi est-ce une bonne habitude avant de faire confiance à un fichier de règles sudo ?
  3. Pourquoi placer cette règle dans un fichier séparé, /etc/sudoers.d/agent, plutôt que d'éditer directement /etc/sudoers ?
📌 Réponse attendue

Étape 2 — Se mettre dans la peau de l'agent​

Passez sur le compte de l'agent, et regardez ce qu'il peut faire avec sudo :

su - agent
whoami
id
sudo -l
  1. Que renvoie sudo -l ?
  2. Un agent qui lit cette ligne doit-il s'inquiéter ? Pourquoi find semble-t-il un choix anodin pour un administrateur pressé ?
📌 Réponse attendue

Étape 3 — L'attaque en 3 commandes​

find dispose d'une option, -exec, qui exécute une autre commande sur chaque résultat trouvé. Lancée avec les droits de root par sudo, cette option permet bien plus qu'une recherche :

sudo -l
sudo find /etc/passwd -exec /bin/sh \; -quit
whoami
  1. Que fait exactement la deuxième commande ? Décomposez le rôle de -exec /bin/sh \; et de -quit.
  2. Que répond whoami, et qu'est-ce que cela signifie ?
  3. L'agent a-t-il eu besoin de connaître le mot de passe root ou de deviner quoi que ce soit ?
📌 Réponse attendue

Étape 4 — Mesurer ce que permet ce shell root​

Depuis le shell root que vous venez d'obtenir, explorez un peu (sans rien modifier) :

id
wc -l /etc/shadow
head -c 200 /etc/shadow
  1. Qu'est-ce que /etc/shadow, et pourquoi un simple agent ne devrait-il jamais pouvoir le lire ?
  2. En quoi la règle accordée à l'étape 1 contredit-elle le principe du moindre privilège ?
  3. Quittez ce shell (exit), puis la session de l'agent (exit à nouveau), pour revenir à votre compte administrateur. Que constatez-vous si vous relancez sudo -l depuis ce compte administrateur ?
📌 Réponse attendue

Étape 5 — Corriger avec un droit limité à la tâche réelle​

Remplacez la règle par un accès strictement limité à la tâche de l'agent : un script dédié, qui ne fait que ce qui est attendu, sans option dangereuse ni argument libre.

sudo tee /usr/local/sbin/verifier-espace-disque.sh > /dev/null <<'EOF'
#!/bin/sh
du -sh /var/log /var/www 2>/dev/null
EOF
sudo chmod 750 /usr/local/sbin/verifier-espace-disque.sh
sudo chown root:root /usr/local/sbin/verifier-espace-disque.sh
sudo rm /etc/sudoers.d/agent
echo 'agent ALL=(ALL) NOPASSWD: /usr/local/sbin/verifier-espace-disque.sh ""' | sudo tee /etc/sudoers.d/agent
sudo chmod 440 /etc/sudoers.d/agent
sudo visudo -c -f /etc/sudoers.d/agent
  1. Pourquoi ce script, plutôt qu'un binaire généraliste comme find, réduit-il le risque ?
  2. À quoi sert les guillemets vides ("") à la fin de la ligne sudoers ?
  3. Pourquoi chown root:root et chmod 750 sur le script, alors que l'agent doit pouvoir l'exécuter via sudo ?
📌 Réponse attendue

Étape 6 — Vérifier que la faille est corrigée​

Reconnectez-vous sur le compte de l'agent, et tentez de rejouer l'attaque :

su - agent
sudo -l
sudo /usr/local/sbin/verifier-espace-disque.sh
sudo /usr/local/sbin/verifier-espace-disque.sh -exec /bin/sh \;
  1. Que montre sudo -l à présent ?
  2. La troisième commande fonctionne-t-elle comme avant ? Que se passe-t-il ?
  3. L'agent peut-il encore accomplir sa tâche d'origine (vérifier l'espace disque) ?
📌 Réponse attendue

Restitution orale​

Un étudiant (ou un binôme) vient présenter à la classe l'attaque réalisée (étapes 2 à 4) et la correction apportée (étapes 5 et 6).

  • Durée : 5 minutes de présentation + 2 à 3 minutes de questions.
  • Qui passe : un(e) étudiant(e) (ou un binôme) désigné(e) par l'enseignant.
  • Support : le travail réalisé pendant le TP, aucune préparation supplémentaire n'est nécessaire.
  • Ce qui est attendu :
    • rappeler la règle sudo d'origine et pourquoi elle semblait inoffensive ;
    • présenter les 3 commandes de l'attaque et la correction apportée ;
    • répondre aux questions de la classe.
astuce

Cet exercice entraîne à l'oral technique court exigé par plusieurs épreuves du BTS (notamment E5 et E6) : clarté, structure, capacité à répondre à l'improviste.

📌 Une solution

Notions théoriques​

Vous venez d'obtenir un accès root à partir d'un seul droit sudo mal écrit. Reste à comprendre pourquoi cette règle était dangereuse, et comment en écrire une qui ne le soit pas.

Comment fonctionne une règle sudo​

Une règle sudoers autorise un utilisateur (ou un groupe) à exécuter une commande précise, avec les droits d'un autre utilisateur (souvent root), éventuellement sans redemander de mot de passe (NOPASSWD). Sa syntaxe générale est :

utilisateur hôte=(utilisateur_cible) NOPASSWD: /chemin/de/la/commande arguments
info

Quand aucun argument n'est précisé après le chemin de la commande, la règle autorise cette commande avec n'importe quel argument. C'est documenté dans le manuel de sudoers, et c'est précisément ce qui a rendu la règle de ce TP exploitable.

Pourquoi find (et d'autres) permettent d'obtenir un shell​

De nombreux programmes standards, pensés pour un usage précis, offrent une fonctionnalité annexe capable de lancer un autre programme :

CommandeFonctionnalité détournéeExemple
findExécuter une commande sur chaque résultatfind . -exec /bin/sh \; -quit
vimExécuter une commande shell depuis l'éditeurvim -c ':!sh'
lessLancer un shell depuis le visualiseur de pagesless /etc/hosts puis !sh
awkExécuter une commande système depuis un scriptawk 'BEGIN {system("/bin/sh")}'
python3Lancer un sous-processus interactifpython3 -c 'import os; os.system("/bin/sh")'

Le projet communautaire GTFOBins recense ces détournements pour un très grand nombre de programmes Unix standards. Accorder un droit sudo sur l'un d'eux, même pour un usage qui semble anodin, revient souvent à accorder un accès root complet.

attention

Ce n'est pas une faille du programme find lui-même : c'est une fonctionnalité documentée, utile dans d'autres contextes. Le problème vient uniquement de la combinaison avec sudo et NOPASSWD, sans restriction d'arguments.

Écrire une règle sudo plus sûre​

Mauvaise pratiqueBonne pratique
Autoriser un binaire généraliste (find, vim, awk...)Autoriser un script dédié, qui ne fait qu'une seule tâche
Ne préciser aucun argumentPréciser les arguments exacts attendus, ou "" pour n'en accepter aucun
Laisser le script modifiable par l'utilisateur autoriséLe rendre appartenant à root, en lecture seule pour les autres
Modifier /etc/sudoers directementPasser par /etc/sudoers.d/, un fichier par règle
Faire confiance à une modification sans vérificationToujours vérifier la syntaxe avec visudo -c avant de l'activer

Cette approche illustre, de façon concrète, le principe du moindre privilège : donner uniquement l'accès strictement nécessaire à la tâche, jamais plus, même quand un accès plus large semblerait simplifier les choses à court terme.

Pour aller plus loin

Une future séance (« Audit des comptes et des droits ») reprendra cette logique pour l'ensemble des comptes d'un serveur : qui a accès à quoi, et pourquoi. Une autre séance posera ce même principe du côté de la défense, cette fois sans angle offensif.


Test de mémorisation/compréhension​


Que montre la commande sudo -l ?


Pourquoi la règle agent ALL=(ALL) NOPASSWD: /usr/bin/find autorise-t-elle find avec n'importe quel argument ?


Dans sudo find /etc/passwd -exec /bin/sh \; -quit, à quoi sert l'option -exec /bin/sh ?


Pourquoi le shell obtenu par find -exec /bin/sh a-t-il les droits de root ?


Quel principe de sécurité la règle sudo d'origine contredit-elle ?


Qu'apporte le remplacement de find par un script dédié, autorisé sans argument ?


Que signifient les guillemets vides à la fin d'une règle sudoers, comme dans .../script.sh "" ?


Pourquoi ce TP ne se pratique-t-il que sur sa propre VM ?



Bonnes pratiques​

  • Ne jamais accorder de droit sudo sur un binaire généraliste (find, vim, less, awk...) sans en vérifier les détournements possibles sur GTFOBins.
  • Préciser toujours les arguments acceptés dans une règle sudoers, ou "" pour n'en accepter aucun.
  • Préférer un script dédié, qui ne fait qu'une seule tâche, à un accès root sur un outil généraliste.
  • Vérifier la syntaxe avec visudo -c avant de faire confiance à une nouvelle règle sudoers.
  • Appliquer le principe du moindre privilège : donner l'accès strictement nécessaire à la tâche, jamais plus.
  • Ne réaliser cette manipulation que sur sa propre machine ou avec une autorisation écrite : sur celle d'autrui, c'est un délit.