Exécuter une commande root via php

Exécuter une commande root via php

22/12/2015 0 Par Vincent

Vous me suis retrouvé plusieurs fois confronté à ce problème : comment exécuter une commande « normalement » réserver à l’utilisateur root (ou un autre) via un script php.

Dans quel cas on peut avoir besoin de ça ? Tout simplement pour administrer un serveur dédié via une petite interface web toute simple, histoire de ne pas se connecter en SSH à chaque fois.

Le problème, c’est que de nombreuses solutions existent mais beaucoup sont « trop dangereuses » pour pouvoir être retenu :

  • Rendre apache / www-data propriétaire du service/serveur en question (MAUVAIS)
  • Donner à apache /www-data le droit d’exécuter des commandes via sudo (BOF BOF)
  • Utiliser un service système dédié à cette tache (LOURD pour juste un ou deux services)

J’ai trouvé une autre méthode qui me parait plutôt pas mal point de vue sécurité. Il s’agit en fait d’utiliser un petit code en C (binary wrapper) qui pourra exécuter soit :

  • La commande ou les commandes qu’il contient (donc compilés à l’intérieur)
  • Un script (que l’on peut donc modifier) mais qu’il faudra protéger en écriture (pour éviter aux petits malins de passer d’autres commandes à travers).

Le tout repose sur l’utilisation du suid bit pour l’attribution d’un droit d’exécution en tant qu’administrateur de la machine (plus d’info sur les droits : Permissions_UNIX)

Etape 1 : On réalise le script qui contiendra les actions à réaliser : php_shell.sh

#!/bin/sh
/sbin/service sshd restart

Etape 2 : On protège notre script (php_shell.sh) pour qu’il appartienne à root et qu’il ne soit modifiable que par lui-même :

chown root php_shell.sh
chmod u=rwx,go=xr php_shell.sh

Etape 3 : En C (pour faire simple, mais on pourrait utiliser un autre langage), on réalise le code qui va permettre d’exécuter en root nos fonctions contenu dans le php_shell.sh :

#include <stdlib.h>
  #include <sys/types.h>
  #include <unistd.h>

  int
  main (int argc, char *argv[])
  {
     setuid (0);

     /* WARNING: Only use an absolute path to the script to execute,
      *          a malicious user might fool the binary and execute
      *          arbitary commands if not.
      * */

     system ("/bin/sh /path/to/php_shell.sh");

     return 0;
   }

Etape 4 : On compile et protège notre code C (on en profite pour le rendre exécutable bien sur) :

gcc wrapper.c -o php_root
chown root php_root
chmod u=rwx,go=xr,+s php_root

Etape 5 : On utilise la fonction exec de php pour exécuter notre code compilé (dans l’exemple : php_root) comme ceci :

<?php exec('./php_root'); ?>

Remarque : le tour est joué. Quand apache traitera une page contenant ce code php, il exécutera php_root qui accordera des droits root aux commandes contenus dans php_shell.sh. Attention de bien respecter les limitations (droits) de chacun des fichiers. Cela constituerait une faille de sécurité béante si tout le monde peut intervenir sur le contenu du php_shell.sh. Pour plus de sécurité (mais moins de flexibilité), vous pouvez indiquer directement les commandes dans le code qui sera compilé (plus de modification par la suite sans recompiler à nouveau le code).