Como impedir que o shell do chamador seja usado no sudo

8

Estou executando o sudo-1.8.6 no CentOS 6.5. Minha pergunta é muito simples: como impedir que o SHELL se propague do ambiente de um usuário para um ambiente sudo?

Normalmente, as pessoas estão indo para o outro lado - elas querem preservar uma variável de ambiente. No entanto, estou tendo um problema em que meu usuário "zabbix", cujo shell /sbin/nologintenta executar um comando via sudo. O Sudo está preservando o arquivo /sbin/nologinpara que o root não possa executar subshells. (Atualização: Esta parte é verdadeira, mas não é a variável de ambiente SHELL. É o valor do shell que está sendo extraído de / etc / passwd que é o problema.)

Eu incluo um teste que ilustra o problema; esse não é meu caso de uso do mundo real, mas simplesmente ilustra que o SHELL do usuário que está chamando é preservado. Eu tenho um programa que roda como usuário zabbix. Ele chama /usr/bin/sudo -u root /tmp/doit(a programação sendo executada como zabbixé um daemon, para que o /sbin/nologinshell no arquivo de senhas não o impeça). /tmp/doité um shell script que simplesmente possui:

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

(seu modo é 755, obviamente). Em outfileposso ver que SHELLé /sbin/nologin. No entanto, neste ponto, o script está sendo executado como root, via sudo, portanto, não deve ter as variáveis ​​de ambiente do usuário anterior, certo?

Aqui está o meu / etc / sudoers:

Padrões requiretty
Padrões! Visiblepw

Padrões always_set_home
Padrões env_reset
Padrões env_keep = "NOME DO NOME DE HOSPEDAGEM DE CORES HISTSIZE INPUTRC KDEDIR LS_COLORS"
Padrões env_keep + = "MAIL PS1 PS2 QTDIR NOME DO USUÁRIO LANG LC_ADDRESS LC_CTYPE"
Padrões env_keep + = "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Padrões env_keep + = "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Padrões env_keep + = "LC_TIME LC_ALL LINGUAS IDIOMAS _XKB_CHARSET XAUTHORITY"
O caminho padrão é secure_path = / sbin: / bin: / usr / sbin: / usr / bin: / usr / local / bin: / usr / local / sbin

## Permitir que o root execute qualquer comando em qualquer lugar 
raiz ALL = (ALL) ALL

#includedir /etc/sudoers.d

E aqui está o meu /etc/sudoers.d/zabbix:

Padrões: zabbix! Requiretty

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

Edit: Um pouco mais de informação:

O processo que executa o sudo é zabbix_agentd, a partir do software de monitoramento Zabbix. Há uma entrada no /etc/zabbix/zabbix_agentd.d/userparameter_disk.confarquivo que se parece com:

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

/usr/local/bin/zabbix_raid_discoveryé um script Python. Eu o modifiquei para fazer isso simplesmente:

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

/tmp/doit simplesmente faz isso:

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

Eu executo o seguinte no meu servidor Zabbix para executar o /usr/local/bin/zabbix_raid_discoveryscript:

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

Então eu verifico /tmp/outfilee vejo:

SHELL = / sbin / nologin
TERM = linux
USER = raiz
SUDO_USER = zabbix
SUDO_UID = 497
USERNAME = root
PATH = / sbin: / bin: / usr / sbin: / usr / bin: / usr / local / bin: / usr / local / sbin
CORREIO = / var / mail / root
PWD = /
LANG = pt_BR.UTF-8
SHLVL = 1
SUDO_COMMAND = / tmp / doit
HOME = / root
LOGNAME = root
SUDO_GID = 497
_ = / bin / env

Essa SHELLfrase realmente me incomoda. O arquivo pertence à raiz, então eu sei que está sendo criado pelo usuário raiz, mas o shell é do usuário que está chamando ( zabbix).

Mike S
fonte
Será que sudo env SHELL=/bin/sh shfornecer um tempo com / bin / sh conjunto como a variável SHELL em seu sistema?
@adonis - Veja minha pergunta atualizada. BTW, você é muito bonito.
Mike S
@BinaryZebra - Sim, eu sei env_delete, mas concordo que o cerne do problema é que o comportamento padrão de env_reset ...causes commands to be executed with a new, minimal environment.Temos um sistema Linux com PAM, de acordo com a página de manual The new environment contains the ... SHELL ... (variable). Como você pode ver no meu /etc/sudoersarquivo acima, não permitimos SHELLno env_keep. Portanto SHELL, não deve ser preservado; devemos ter o usuário root SHELL.
Mike S
@BinaryZebra - adicionei zabbix ALL=(root) NOPASSWD: /bin/env SHELL=/bin/sh /tmp/doit *ao meu /etc/sudoers/zabbixarquivo e ele possui um shell apropriado. Obrigado, agora tenho uma solução alternativa. A questão é: por que eu preciso incluí-lo? Parece perigoso (e quebrado) passar o SHELL do chamador, mas não consigo encontrar um lugar onde o sudo esteja configurado para modificá-lo. Eu corri find /etc/sudoers /etc/sysconfig -type f -exec grep env_ {} \;e não encontro bandeiras vermelhas; /etc/sudoerscontém a única env_string. Então eu não acho que há uma bandeira sudoers interferir ...
Mike S
Mike: Em um primeiro nível: Um simples sudo bashdeve iniciar um shell bash como root e DEVE ter a variável SHELL definida como o valor de / etc / password. Você informa que SHELL está sendo definido como (ou preservado como) /sbin/nologin. Esse é um problema de segurança, o shell iniciado pelo root não deve ser controlado por uma variável de ambiente definida por um usuário. Isso é algo que você deve investigar.

Respostas:

5

Então a resposta é que sudotem um bug. Primeiro, a solução alternativa: coloquei isso no meu /etc/sudoers.d/zabbix file:

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

e agora subcomandos chamados do zabbix_raid_discoverytrabalho.

Um patch para corrigir isso estará no sudo 1.8.15. Do mantenedor, Todd Miller:

Este é apenas um caso de "sempre foi assim". Não há
realmente uma boa razão para isso. O diff abaixo deve tornar o comportamento
coincidir com a documentação.

 - todd

diff -r adb927ad5e86 plugins / sudoers / env.c
--- a / plugins / sudoers / env.c ter 06 de outubro 09:33:27 2015 -0600
+++ b / plugins / sudoers / env.c ter 06 de outubro 10:04:03 2015 -0600
@@ -939,8 +939,6 @@
            CHECK_SETENV2 ("USERNAME", runas_pw-> pw_name,
                ISSET (didvar, DID_USERNAME), verdadeiro);
        } outro {
- if (! ISSET (didvar, DID_SHELL))
- CHECK_SETENV2 ("SHELL", sudo_user.pw-> pw_shell, falso, verdadeiro);
            / * Definiremos LOGNAME posteriormente no 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);
                caso contrário, se (strncmp (* ep, "PATH =", 5) == 0)
                    SET (didvar, DID_PATH);
                caso contrário, se (strncmp (* ep, "TERM =", 5) == 0)
@@ -1039,7 +1039,9 @@
     if (reset_home)
        CHECK_SETENV2 ("HOME", runas_pw-> pw_dir, verdadeiro, verdadeiro);

- / * Forneça valores padrão para $ TERM e $ PATH se eles não estiverem configurados. * /
+ / * Forneça valores padrão para $ SHELL, $ TERM e $ PATH se não estiver definido. * /
+ if (! ISSET (didvar, DID_SHELL))
+ CHECK_SETENV2 ("SHELL", runas_pw-> pw_shell, falso, falso);
     if (! ISSET (didvar, DID_TERM))
        CHECK_PUTENV ("TERM = desconhecido", falso, falso);
     if (! ISSET (didvar, DID_PATH))
Mike S
fonte
Excelente Mike !, Obrigado pelo trabalho de detetive.
Mike, é possível que você coloque um link para o patch (futuro?).
O @BinaryZebra Diff está aqui: sudo.ws/repos/sudo/rev/b77adbc08c91 Ainda não vejo um patch.
Mike S
Mike: Eu acredito que você está latindo para a árvore errada. O ponto-chave aqui: Provide default values for $SHELL, $TERM and $PATH if not set.é: ... if not set.. Qualquer conjunto de valores será preservado pelo sudo. Quem está definindo o SHELL?
@BinaryZebra - Não é assim que eu leio. SHELL está desativado (por env_reset, por padrão). Como não está definido, o código antigo diz para usar a entrada pw do sudo_user. O novo código diz para usar a entrada pw do usuário runas.
Mike S
4

A pergunta era sobre onde eu achava que estava o problema, mas acontece que o problema não é o que acontece com a variável SHELL, mas o que o sudo realmente faz. Por exemplo:

-bash-4.1 $ whoami
testdude
-bash-4.1 $ grep testdude / etc / passwd
testdude: x: 1001: 10: Cara de teste: / tmp: / bin / bash
-bash-4.1 $ sudo env
[sudo] senha para testdude: 
...
SHELL = / bin / bash
...

Por enquanto, tudo bem. ... mas o problema é que o sudo usa o shell do chamador em vez do chamado, ao contrário dos documentos. De fato, se eu mudar meu shell editando / etc / passwd, você pode ver que o sudo segue o shell do chamador e não SHELL:

-bash-4.1 $ grep root / etc / passwd
raiz: x: 0: 0: raiz: / raiz: / bin / bash
Você pode usar o seguinte comando:
-bash-4.1 $ grep testdude / etc / passwd
testdude: x: 1001: 10: Cara de teste: / tmp: / bin / sh
-bash-4.1 $ sudo env
...
SHELL = / bin / sh
...
-bash-4.1 $ export SHELL = / completamente / sem sentido / caminho
-bash-4.1 $ sudo env
...
SHELL = / bin / sh
...

Não posso usar sudo -iporque não quero simular um login inicial. sudo -sfuncionará, desde que eu tenha o comando apropriado no arquivo sudoers. No entanto, o comportamento esperado (conforme refletido na página de manual: " The new environment contains the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables") é que o shell seja o chamado. Se você olhar o PATH, HOME, LOGNAME, e USERvariáveis para sudo env você vai ver as coisas de raiz. SHELLdeve ser o shell da raiz também.

Mike S
fonte