Comment empêcher le shell de l'appelant d'être utilisé dans sudo

8

J'utilise sudo-1.8.6 sur CentOS 6.5. Ma question est très simple: comment empêcher SHELL de se propager de l'environnement d'un utilisateur vers un environnement sudo?

Habituellement, les gens vont dans l'autre sens - ils veulent conserver une variable d'environnement. Cependant, j'ai un problème où mon utilisateur "zabbix" dont le shell /sbin/nologinessaie d'exécuter une commande via sudo. Sudo préserve le /sbin/nologinafin que root ne puisse pas exécuter de sous-shell. (Mise à jour: cette partie est vraie, mais ce n'est pas la variable d'environnement SHELL. C'est la valeur du shell qui est extraite de / etc / passwd qui est le problème.)

J'inclus un test qui illustre le problème; ce n'est pas mon cas d'utilisation réel, mais cela illustre simplement que le SHELL de l'utilisateur appelant est préservé. J'ai un programme qui fonctionne en tant qu'utilisateur zabbix. Il appelle /usr/bin/sudo -u root /tmp/doit(la programmation fonctionnant comme zabbixun démon, donc le /sbin/nologinshell dans le fichier de mot de passe ne l'empêche pas). /tmp/doitest un script shell qui a simplement:

#!/bin/sh
env > /tmp/outfile

(son mode est 755, évidemment). En outfileje peux voir que SHELLc'est /sbin/nologin. Cependant, à ce stade, le script s'exécute en tant que root, via sudo, donc il ne devrait pas avoir les variables d'environnement de l'utilisateur précédent, non?

Voici mon / etc / sudoers:

Valeurs par défaut requises
Par défaut! Visiblepw

Valeurs par défaut always_set_home
Par défaut env_reset
Def_ults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS"
Valeurs par défaut env_keep + = "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Valeurs par défaut env_keep + = "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Paramètres par défaut env_keep + = "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Valeurs par défaut env_keep + = "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Par défaut secure_path = / sbin: / bin: / usr / sbin: / usr / bin: / usr / local / bin: / usr / local / sbin

## Autoriser root à exécuter n'importe quelle commande n'importe où 
root ALL = (ALL) ALL

#includedir /etc/sudoers.d

Et voici mon /etc/sudoers.d/zabbix:

Paramètres par défaut: zabbix!

zabbix ALL = (root) NOPASSWD: / tmp / doit

Edit: Un peu plus d'informations:

Le processus exécutant le sudo est zabbix_agentd, à partir du logiciel de surveillance Zabbix. Il y a une entrée dans le /etc/zabbix/zabbix_agentd.d/userparameter_disk.conffichier qui ressemble à:

UserParameter = example.disk.discovery, / usr / local / bin / zabbix_raid_discovery

/usr/local/bin/zabbix_raid_discoveryest un script Python. Je l'ai modifié pour faire simplement ceci:

print subprocess.check_output (['/ usr / bin / sudo', '-u', 'root', '/ tmp / doit'])

/tmp/doit fait simplement ceci:

#! / bin / sh
env >> / tmp / outfile

J'exécute ce qui suit sur mon serveur Zabbix pour exécuter le /usr/local/bin/zabbix_raid_discoveryscript:

zabbix_get -s client_hostname -k 'example.disk.discovery'

Ensuite, je vérifie le /tmp/outfile, et je vois:

SHELL = / sbin / nologin
TERM = linux
USER = root
SUDO_USER = zabbix
SUDO_UID = 497
USERNAME = root
CHEMIN = / sbin: / bin: / usr / sbin: / usr / bin: / usr / local / bin: / usr / local / sbin
MAIL = / var / mail / root
PWD = /
LANG = en_US.UTF-8
SHLVL = 1
SUDO_COMMAND = / tmp / doit
ACCUEIL = / root
LOGNAME = root
SUDO_GID = 497
_ = / bin / env

Cette SHELLligne me dérange vraiment. Le fichier appartient à root, donc je sais qu'il est créé par l'utilisateur root, mais le shell vient de l'utilisateur appelant ( zabbix).

Mike S
la source
Fournit sudo env SHELL=/bin/sh shune invite avec / bin / sh défini comme variable SHELL dans votre système?
@adonis - Voir ma question mise à jour. BTW, tu es très beau.
Mike S
@BinaryZebra - Oui , je sais au sujet env_delete, mais je suis d' accord le nœud du problème est que le comportement par défaut de env_reset ...causes commands to be executed with a new, minimal environment.Nous avons un système Linux avec PAM, donc en fonction de la page de manuel, The new environment contains the ... SHELL ... (variable). Comme vous pouvez le voir dans mon /etc/sudoersfichier ci-dessus, nous n'autorisons pas SHELLle env_keep. Il SHELLne faut donc pas le conserver; nous devrions avoir l'utilisateur root SHELL.
Mike S
@BinaryZebra - J'ai ajouté zabbix ALL=(root) NOPASSWD: /bin/env SHELL=/bin/sh /tmp/doit *à mon /etc/sudoers/zabbixfichier, et il a un bon shell. Merci, j'ai maintenant une solution de contournement. La question est, pourquoi ai-je besoin de l'inclure? Il semble dangereux (et cassé) de passer le SHELL de l'appelant mais je ne trouve aucun endroit où sudo est configuré pour le modifier. J'ai couru find /etc/sudoers /etc/sysconfig -type f -exec grep env_ {} \;et je ne trouve aucun drapeau rouge; /etc/sudoerscontient la seule env_chaîne. Je ne pense donc pas qu'il y ait un drapeau sudoers qui interfère ...
Mike S
Mike: Au premier niveau: un simple sudo bashdevrait démarrer un shell bash en tant que root et il DOIT avoir la variable SHELL définie sur la valeur de / etc / password. Vous signalez que SHELL est défini sur (ou conservé sous) /sbin/nologin. C'est un problème de sécurité, le shell démarré par root ne doit pas être contrôlé par une variable d'environnement définie par un utilisateur. C'est quelque chose que vous devez étudier.

Réponses:

5

Alors la réponse est qu'il y sudoa un bug. Tout d'abord, la solution de contournement: je mets ceci dans mon /etc/sudoers.d/zabbix file:

zabbix ALL = (root) NOPASSWD: / bin / env SHELL = / bin / sh / usr / local / bin / zabbix_raid_discovery

et maintenant des sous-commandes appelées depuis le zabbix_raid_discoverytravail.

Un correctif pour résoudre ce problème sera dans sudo 1.8.15. Du responsable, Todd Miller:

C'est juste un cas de "ça a toujours été comme ça". Il n'y a pas
vraiment une bonne raison. Le diff ci-dessous devrait rendre le comportement
correspondre à la documentation.

 - todd

diff -r adb927ad5e86 plugins / sudoers / env.c
--- a / plugins / sudoers / env.c mar oct 06 09:33:27 2015 -0600
+++ b / plugins / sudoers / env.c mar oct 06 10:04:03 2015 -0600
@@ -939,8 +939,6 @@
            CHECK_SETENV2 ("USERNAME", runas_pw-> pw_name,
                ISSET (didvar, DID_USERNAME), vrai);
        } autre {
- si (! ISSET (didvar, DID_SHELL))
- CHECK_SETENV2 ("SHELL", sudo_user.pw-> pw_shell, false, true);
            / * Nous définirons LOGNAME plus tard dans le cas def_set_logname. * /
            if (! def_set_logname) {
                if (! ISSET (didvar, DID_LOGNAME))
@@ -984,6 +982,8 @@
            if (! env_should_delete (* ep)) {
                if (strncmp (* ep, "SUDO_PS1 =", 9) == 0)
                    ps1 = * ep + 5;
+ else if (strncmp (* ep, "SHELL =", 6) == 0)
+ SET (didvar, DID_SHELL);
                sinon if (strncmp (* ep, "PATH =", 5) == 0)
                    SET (didvar, DID_PATH);
                sinon si (strncmp (* ep, "TERM =", 5) == 0)
@@ -1039,7 +1039,9 @@
     if (reset_home)
        CHECK_SETENV2 ("HOME", runas_pw-> pw_dir, true, true);

- / * Fournissez des valeurs par défaut pour $ TERM et $ PATH si elles ne sont pas définies. * /
+ / * Fournir des valeurs par défaut pour $ SHELL, $ TERM et $ PATH si non défini. * /
+ if (! ISSET (didvar, DID_SHELL))
+ CHECK_SETENV2 ("SHELL", runas_pw-> pw_shell, false, false);
     if (! ISSET (didvar, DID_TERM))
        CHECK_PUTENV ("TERM = inconnu", faux, faux);
     if (! ISSET (didvar, DID_PATH))
Mike S
la source
Excellent Mike!, Merci pour le travail de détective.
Mike, est-il possible que vous mettiez un lien vers le (futur?) Patch.
@BinaryZebra Diff est ici: sudo.ws/repos/sudo/rev/b77adbc08c91 Je ne vois pas encore de patch.
Mike S
Mike: Je crois que vous aboyez au mauvais arbre. Le point clé ici: Provide default values for $SHELL, $TERM and $PATH if not set.est: ... if not set.. Tout ensemble de valeurs sera conservé par sudo. Qui met SHELL?
@BinaryZebra - Ce n'est pas ainsi que je l'ai lu. SHELL n'est pas défini (par env_reset, par défaut). Puisqu'il n'est pas défini, l'ancien code dit d'utiliser l'entrée pw de sudo_user. Le nouveau code dit d'utiliser l'entrée pw de l'utilisateur runas.
Mike S
4

La question était de savoir où je pensais que le problème était, mais il s'avère que le problème n'est pas ce qui arrive à la variable SHELL, mais ce que fait réellement sudo. Par exemple:

-bash-4.1 $ whoami
testdude
-bash-4.1 $ grep testdude / etc / passwd
testdude: x: 1001: 10: Test mec: / tmp: / bin / bash
-bash-4.1 $ sudo env
[sudo] mot de passe pour testdude: 
...
SHELL = / bin / bash
...

Jusqu'ici tout va bien. ... mais le problème est que sudo utilise le shell de l'appelant au lieu de l'appelé, contrairement aux docs. En effet, si je change de shell en éditant / etc / passwd, vous pouvez voir que sudo suit le shell de l'appelant et non SHELL:

-bash-4.1 $ racine grep / etc / passwd
root: x: 0: 0: root: / root: / bin / bash
-bash-4.1 $ sudo sed -i -e '/ testdude / s / bash / sh /' / etc / passwd
-bash-4.1 $ grep testdude / etc / passwd
testdude: x: 1001: 10: Test mec: / tmp: / bin / sh
-bash-4.1 $ sudo env
...
SHELL = / bin / sh
...
-bash-4.1 $ export SHELL = / complètement / sans signification / chemin
-bash-4.1 $ sudo env
...
SHELL = / bin / sh
...

Je ne peux pas l'utiliser sudo -icar je ne veux pas simuler une connexion initiale. sudo -sfonctionnera, tant que j'ai la commande appropriée dans le fichier sudoers. Cependant, le comportement attendu (tel que reflété dans la page de manuel: " The new environment contains the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables") est que le shell appartient à l'appelé. Si vous regardez le PATH, HOME, LOGNAMEet USERvariables pour env sudo vous verrez des choses de la racine. SHELLdevrait également être le shell de root.

Mike S
la source