Come impedire che la shell del chiamante venga usata in sudo


8

Sto eseguendo sudo-1.8.6 su CentOS 6.5. La mia domanda è molto semplice: come posso impedire a SHELL di propagarsi dall'ambiente di un utente a un ambiente sudo?

Di solito le persone vanno dall'altra parte, vogliono preservare una variabile d'ambiente. Tuttavia, sto riscontrando un problema in cui il mio utente "zabbix", la cui shell /sbin/nologintenta di eseguire un comando tramite sudo. Il Sudo sta preservando il /sbin/nologinmodo in cui root non può eseguire subshells. (Aggiornamento: questa parte è vera, ma non è la variabile di ambiente SHELL. È il valore della shell che viene estratto da / etc / passwd che è il problema.)

Includo un test che illustra il problema; questo non è il mio caso d'uso reale ma illustra semplicemente che lo SHELL dell'utente chiamante viene preservato. Ho un programma che funziona come utente zabbix. Chiama /usr/bin/sudo -u root /tmp/doit(la programmazione in esecuzione come zabbixè un demone, quindi la /sbin/nologinshell nel file delle password non lo impedisce). /tmp/doitè uno script di shell che ha semplicemente:

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

(la sua modalità è 755, ovviamente). In outfileposso vedere che SHELLè /sbin/nologin. Tuttavia, a questo punto lo script viene eseguito come root, tramite sudo, quindi non dovrebbe avere le variabili di ambiente dell'utente precedente, giusto?

Ecco il mio / etc / sudoers:

Predefiniti richiesti
Predefiniti! Visiblepw

Predefiniti always_set_home
Predefiniti env_reset
Valori predefiniti env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS"
Valori predefiniti env_keep + = "MAIL PS1 PS2 QTDIR NOME UTENTE LANG LC_ADDRESS LC_CTYPE"
Valori predefiniti env_keep + = "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Valori predefiniti env_keep + = "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Valori predefiniti env_keep + = "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Valori predefiniti secure_path = / sbin: / bin: / usr / sbin: / usr / bin: / usr / local / bin: / usr / local / sbin

## Consenti a root di eseguire qualsiasi comando ovunque 
root ALL = (ALL) ALL

#includedir /etc/sudoers.d

Ed ecco il mio /etc/sudoers.d/zabbix:

Valori predefiniti: zabbix! Requiretty

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

Modifica: qualche informazione in più:

Il processo che esegue il sudo è zabbix_agentd, dal software di monitoraggio Zabbix. C'è una voce nel /etc/zabbix/zabbix_agentd.d/userparameter_disk.conffile che assomiglia a:

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

/usr/local/bin/zabbix_raid_discoveryè uno script Python. L'ho modificato per fare semplicemente questo:

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

/tmp/doit fa semplicemente questo:

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

Eseguo quanto segue sul mio server Zabbix per eseguire lo /usr/local/bin/zabbix_raid_discoveryscript:

zabbix_get -s nome_host client -k 'esempio.disk.discovery'

Quindi controllo il /tmp/outfilee vedo:

SHELL = / sbin / nologin
TERM = linux
USER = radice
SUDO_USER = Zabbix
SUDO_UID = 497
USERNAME = radice
PATH = / sbin: / bin: / usr / sbin: / usr / bin: / usr / local / bin: / usr / local / sbin
MAIL = / var / mail / root
PWD = /
LANG = it_IT.UTF-8
SHLVL = 1
SUDO_COMMAND = / tmp / doit
HOME = / root
LOGNAME = radice
SUDO_GID = 497
_ = / Bin / ENV

Quella SHELLlinea mi infastidisce davvero. Il file è di proprietà di root, quindi so che viene creato dall'utente root, ma la shell proviene dall'utente chiamante ( zabbix).


Non sudo env SHELL=/bin/sh shfornire una con / bin / sh set pronta come variabile SHELL nel vostro sistema?

@adonis - Vedi la mia domanda aggiornata. A proposito, sei molto bello.
Mike S,

@BinaryZebra - Sì, lo conosce env_delete, ma sono d'accordo il nocciolo del problema è che il comportamento predefinito di env_reset ...causes commands to be executed with a new, minimal environment.Abbiamo un sistema Linux con PAM, così secondo la pagina man, The new environment contains the ... SHELL ... (variable). Come puoi vedere dal mio /etc/sudoersfile sopra, non consentiamo SHELLnel env_keep. Quindi SHELLnon dovrebbe essere preservato; dovremmo avere l'utente root SHELL.
Mike S,

@BinaryZebra - Ho aggiunto zabbix ALL=(root) NOPASSWD: /bin/env SHELL=/bin/sh /tmp/doit *al mio /etc/sudoers/zabbixfile e ha una shell corretta. Grazie, ora ho una soluzione alternativa. La domanda è: perché ho dovuto includerlo? Sembra pericoloso (e rotto) passare SHELL del chiamante ma non riesco a trovare un posto in cui sudo è impostato per modificarlo. Ho corso find /etc/sudoers /etc/sysconfig -type f -exec grep env_ {} \;e non trovo bandiere rosse; /etc/sudoerscontiene l'unica env_stringa. Quindi non penso che ci sia una bandiera sudoers che interferisce ...
Mike S,

Mike: Al primo livello: un semplice sudo bashdovrebbe avviare una shell bash come root e DEVE avere la variabile SHELL impostata sul valore da / etc / password. Si segnala che SHELL è impostato su (o conservato come) /sbin/nologin. Questo è un problema di sicurezza, la shell avviata da root non deve essere controllata da una variabile d'ambiente impostata da un utente. Questo è qualcosa che devi investigare.

Risposte:


5

Quindi la risposta è che sudoha un bug. Innanzitutto, la soluzione alternativa: l'ho inserito nel mio /etc/sudoers.d/zabbix file:

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

e ora i sottocomandi chiamati dal zabbix_raid_discoverylavoro.

Una patch per risolvere questo problema sarà in sudo 1.8.15. Dal manutentore, Todd Miller:

Questo è solo un caso di "è sempre stato così". Non c'è
davvero una buona ragione per questo. La differenza di seguito dovrebbe rendere il comportamento
abbinare la documentazione.

 - todd

diff -r adb927ad5e86 plugin / sudoers / env.c
--- a / plugins / sudoers / env.c mar 06 ott 09:33:27 2015 -0600
+++ b / plugins / sudoers / env.c mar 06 ott 10:04:03 2015 -0600
@@ -939,8 +939,6 @@
            CHECK_SETENV2 ("USERNAME", runas_pw-> pw_name,
                ISSET (didvar, DID_USERNAME), vero);
        } altro {
- if (! ISSET (didvar, DID_SHELL))
- CHECK_SETENV2 ("SHELL", sudo_user.pw-> pw_shell, false, true);
            / * In seguito imposteremo LOGNAME nel caso 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);
                else if (strncmp (* ep, "PATH =", 5) == 0)
                    SET (didvar, DID_PATH);
                else if (strncmp (* ep, "TERM =", 5) == 0)
@@ -1039,7 +1039,9 @@
     if (reset_home)
        CHECK_SETENV2 ("HOME", runas_pw-> pw_dir, true, true);

- / * Fornire i valori predefiniti per $ TERM e $ PATH se non sono impostati. * /
+ / * Fornire i valori predefiniti per $ SHELL, $ TERM e $ PATH se non impostato. * /
+ if (! ISSET (didvar, DID_SHELL))
+ CHECK_SETENV2 ("SHELL", runas_pw-> pw_shell, false, false);
     if (! ISSET (didvar, DID_TERM))
        CHECK_PUTENV ("TERM = sconosciuto", falso, falso);
     if (! ISSET (didvar, DID_PATH))

Eccellente Mike!, Grazie per il lavoro investigativo.

Mike, è possibile che tu abbia messo un link alla patch (futura?).

@BinaryZebra Diff è qui: sudo.ws/repos/sudo/rev/b77adbc08c91 Non vedo ancora una patch.
Mike S,

Mike: Credo che tu stia abbaiando all'albero sbagliato. Il punto chiave qui: Provide default values for $SHELL, $TERM and $PATH if not set.è: ... if not set.. Qualsiasi valore impostato verrà conservato da sudo. Chi sta impostando SHELL?

@BinaryZebra - Non è così che l'ho letto. SHELL non è impostato (da env_reset, per impostazione predefinita). Poiché non è impostato, il vecchio codice dice di usare la voce pw di sudo_user. Il nuovo codice dice di usare la voce pw dell'utente runas.
Mike S,

4

La domanda era su dove pensavo fosse il problema, ma si scopre che il problema non è cosa succede alla variabile SHELL, ma cosa fa effettivamente sudo. Per esempio:

-bash-4.1 $ whoami
testdude
-bash-4.1 $ grep testdude / etc / passwd
testdude: x: 1001: 10: Test dude: / tmp: / bin / bash
-bash-4.1 $ sudo env
[sudo] password per testdude: 
...
SHELL = / bin / bash
...

Fin qui tutto bene. ... ma il problema è che sudo usa la shell del chiamante invece della chiamata, contrariamente ai documenti. Infatti, se cambio la mia shell modificando / etc / passwd, puoi vedere che sudo segue la shell del chiamante e non SHELL:

-bash-4.1 $ grep root / 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 dude: / tmp: / bin / sh
-bash-4.1 $ sudo env
...
SHELL = / bin / sh
...
-bash-4.1 $ export SHELL = / completamente / insignificante / percorso
-bash-4.1 $ sudo env
...
SHELL = / bin / sh
...

Non posso usare sudo -iperché non voglio simulare un accesso iniziale. sudo -sfunzionerà, finché avrò il comando corretto nel file sudoers. Tuttavia, il comportamento previsto (come indicato nella pagina man: " The new environment contains the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables") è che la shell sia quella della chiamata. Se si guarda alla PATH, HOME, LOGNAME, e USERvariabili per sudo env vedrete roba di root. SHELLdovrebbe essere anche la shell di root.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.