2009-02-17 7 views
24

Je dois exécuter un script bash en tant que root (sudo sans mot de passe ou su pas viable) et comme vous ne pouvez pas définir un script sous Linux, j'ai pensé appeler il d'un exécutable et de faire il setuid:Appel d'un script à partir d'une racine setuid C - le script ne s'exécute pas en tant que root

$ cat wrapper.c 
int main(void) 
{ 
     system("/bin/bash ./should_run_as_root.sh"); 
} 
$ gcc -o wrapper wrapper.c 
$ sudo chown root wrapper 
$ sudo chmod ug+s wrapper 
$ ll wrapper 
-rwsr-sr-x 1 root users 6667 2009-02-17 11:11 wrapper 
$ 

Cela fonctionne - comme dans fonctionne correctement le script - mais le script est exécuté en tant que l'utilisateur qui exécute « ./wrapper ».

Pourquoi? Et comment mettre en œuvre correctement cela?

Merci!

+2

Pour le raisonnement derrière les réponses ci-dessous, voir 'man system', et http://stackoverflow.com/questions/1051370/why-do-i-need-setuid0-within-a-setuid-root-c- program-that-calls-an-administrati –

Répondre

38

Depuis le bit suid sur executables ne modifie l'UID effectif (EUID) l'exécutable fonctionnera comme, et non l'UID réel (RUID) qui getuid() rendements, et en plus de la restriction suid scripts interprété (tout début exécutable avec "#!"), certains obus comme bash comme une mesure de sécurité supplémentaire va remettre l'EUID au RUID dans ce cas, vous devrez utiliser l'appel setuid(0) dans le code C avant d'exécuter le script.

Voir les man pages du setuid, seteuid, getuid et geteuid pour apprendre la sémantique exacte des UIDs réelles et efficaces.

(AVERTISSEMENT) Bien sûr, cela est un point approprié de mentionner que la restriction suid scripts dans de nombreux systèmes Unix, des coquillages et des interprètes, sont là pour une raison, qui est que si le script est pas très prudent À propos de la désinfection de son entrée et de l'état de l'environnement lors de son exécution, ils sont dangereux et peuvent être exploités pour une escalade de la sécurité. Soyez donc très prudent quand vous faites cela. Définissez l'accès à votre script et encapsuleur aussi strict que possible, n'autorisez que ce script très spécifique que vous avez l'intention d'exécuter et effacez l'environnement de votre programme C avant de démarrer le script, en définissant des variables d'environnement telles que PATH est nécessaire dans le bon ordre et pas de répertoires qui sont accessibles en écriture pour les autres.

+0

Est-il plus sûr d'enregistrer l'UID d'origine et de le réinitialiser à la fin du programme? – skinp

+0

Si votre programme fait d'autres choses après la fin du script, cela n'a pas besoin de cela, alors oui. Si tout ce que vous faites est de revenir, alors cela n'a pas vraiment d'importance. Dans le cas typique, un wrapper de script utilisera exec et non system (...), donc de toute façon le wrapper ne fonctionnera plus après la fin du script. –

+0

@TomAlsberg Connaissez-vous le code source/la documentation pour confirmer le comportement de Bash pour cet 'uid de réinitialisation automatique'? – steveyang

6

Une autre chose à noter ici est que la limitation ici est de bash et non le système * nix lui-même. Bash fait des vérifications sur les scripts SUID pour les exécuter uniquement avec la racine EUID. Si vous prenez des coquilles plus vieilles, vous obtiendrez souvent ce que vous voulez hors de la boîte. Par exemple, sh ne fait pas ce genre de vérifications:

$ cat wrapper.c 
int main(void) 
{ 
      system("/bin/sh -c whoami"); 
} 

$ ls -l wrapper 
-rwsr-sr-x 1 root users 8887 Feb 17 14:15 wrapper 
$ ./wrapper 
root 

Avec bash:

$ cat wrapper.c 
int main(void) 
{ 
      system("/bin/bash -c whoami"); 
} 

$ ls -l wrapper 
-rwsr-sr-x 1 root users 8887 Feb 17 14:18 wrapper 
$ ./wrapper 
skinp 

encore, la réponse de Tom est généralement la voie à suivre pour faire un wrapper pour les programmes SUID root

+0

Vous avez raison, bien sûr. Linux gère la restriction des scripts suid en vérifiant le mode de l'exécutable dans l'appel exec, et cette restriction est une mesure de sécurité supplémentaire de certains interprètes. Je ne sais pas pourquoi j'ai eu cette confusion quand j'ai écrit ceci. J'ai corrigé ma réponse. Merci! –

+0

Et bien sûr, j'ai manqué que dans le code de l'OP, il n'est pas en train d'exécuter un script avec un #! spécification de l'interpréteur, mais appelant directement bash, donc la restriction du noyau ne s'appliquerait pas dans ce cas de toute façon - mais le noyau a cette restriction pour #! scripts avec le mode fichier suid. –

+0

Ne fonctionne plus (plus). D'un côté, 'man system' dit' Ne pas utiliser system() depuis un programme avec des privilèges set-user-ID ou set-group-ID, parce que ... '. D'un autre côté, cela fonctionne dans Ubuntu 14.04 mais pas dans Ubuntu 16.04. – anumi

3

Ajoutez le setuid (0) dans le script et conformez-le. Il devrait travailler après cela.

$ cat wrapper.c 
int main(void) 
{ 
     setuid(0); 
     system("/bin/bash ./should_run_as_root.sh"); 
} 
$ gcc -o wrapper wrapper.c 
$ sudo chown root wrapper 
$ sudo chmod ug+s wrapper 
$ ll wrapper 
-rwsr-sr-x 1 root users 6667 2009-02-17 11:11 wrapper 
$ 
+2

N'utilisez pas system() d'un programme avec des privilèges set-user-ID ou set-group-ID, car des valeurs étranges pour certaines variables d'environnement peuvent être utilisées pour subvertir l'intégrité du système. Utilisez la famille de fonctions exec (3) à la place, mais pas execlp (3) ou execvp (3). En fait, system() ne fonctionnera pas correctement avec les programmes avec set-user-ID ou les privilèges group-ID sur les systèmes sur lesquels/bin/sh est bash version 2, puisque bash 2 supprime les privilèges au démarrage. – cateof

0

Pourquoi sudo n'est-il pas viable?Il évite fait rage trous de sécurité tels que:

bash-3.2$ cat test 
#!/bin/bash 
echo ima shell script durp durp 
bash-3.2$ chmod +x test 
bash-3.2$ ./test 
heh heh 
bash-3.2$ 

En raison de l'environnement ne sont pas correctement filtrées, par exemple dans ce cas:

export echo='() { builtin echo heh heh; }' 

sudo assainit ce cas, et peut-être d'autres cas de pointe et gotchas que serait bien de ne pas écrire dans un wrapper suid personnalisé.

+0

man sudo: "Exécuter des scripts shell via sudo peut exposer les mêmes bogues du noyau qui rendent les scripts shell setuid dangereux sur certains systèmes d'exploitation ..." Un standard wrapper pour faire des scripts suid est probablement le meilleur, mais en connaissez-vous un? Sudo n'est pas sûr ici, car il dépend du noyau pour passer le script via/dev/fd/...! –

1

Les exemples sont horriblement peu sûrs et permettent à n'importe qui avec deux bits de connaissances d'exécuter n'importe quel programme en tant qu'utilisateur setuid.

Ne passez jamais par un shell à moins de désinfecter l'environnement en premier, la plupart des exemples montrés ici sont vulnérables à la mise en place d'IFS et PATH avant de l'exécuter.

Questions connexes