O Linux ignora o bit setuid¹ em todos os executáveis interpretados (ou seja, executáveis iniciando com uma #!
linha). As perguntas frequentes do comp.unix.questions explicam os problemas de segurança com scripts shell setuid. Esses problemas são de dois tipos: relacionados ao shebang e ao shell; Entro em mais detalhes abaixo.
Se você não se importa com a segurança e deseja permitir scripts setuid, no Linux, precisará corrigir o kernel. No kernel 3.x, acho que você precisa adicionar uma chamada install_exec_creds
na load_script
função antes da chamada open_exec
, mas ainda não testei.
Setuid shebang
Há uma condição de corrida inerente à maneira #!
como normalmente é implementado o shebang ( ):
- O kernel abre o executável e descobre que ele começa com
#!
.
- O kernel fecha o executável e abre o intérprete.
- O kernel insere o caminho para o script na lista de argumentos (como
argv[1]
) e executa o intérprete.
Se scripts setuid forem permitidos com esta implementação, um invasor poderá chamar um script arbitrário criando um link simbólico para um script setuid existente, executando-o e organizando a alteração do link após o kernel ter executado a etapa 1 e antes que o intérprete chegue ao abrindo seu primeiro argumento. Por esta razão, maioria das unidades ignora o bit setuid quando detecta um shebang.
Uma maneira de proteger essa implementação seria o kernel bloquear o arquivo de script até que o intérprete o abrisse (observe que isso deve impedir não apenas desvincular ou sobrescrever o arquivo, mas também renomear qualquer diretório no caminho). Mas os sistemas unix tendem a evitar os bloqueios obrigatórios, e os links simbólicos tornariam um recurso de bloqueio correto especialmente difícil e invasivo. Eu não acho que alguém faça dessa maneira.
Alguns sistemas unix (principalmente o OpenBSD, o NetBSD e o Mac OS X, que exigem a habilitação de uma configuração do kernel) implementam o shebang do setuid seguro usando um recurso adicional: o caminho refere-se ao arquivo já aberto no descritor de arquivo N (portanto, a abertura é aproximadamente equivalente a ). Muitos sistemas unix (incluindo Linux) possuem/dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
mas não scripts setuid.
- O kernel abre o executável e descobre que ele começa com
#!
. Digamos que o descritor de arquivo do executável seja 3.
- O kernel abre o intérprete.
- O kernel insere
/dev/fd/3
a lista de argumentos (as argv[1]
) e executa o intérprete.
A página shebang de Sven Mascheck tem muitas informações sobre shebang nos departamentos, incluindo suporte a setuid .
Intérpretes Setuid
Vamos supor que você tenha conseguido executar seu programa como root, seja porque o seu sistema operacional suporta setuid shebang ou porque você usou um invólucro binário nativo (como sudo
). Você abriu uma brecha na segurança? Talvez . O problema aqui não é sobre programas interpretados versus compilados. O problema é se o sistema de tempo de execução se comporta com segurança se executado com privilégios.
Qualquer executável binário nativo vinculado dinamicamente é interpretado pelo carregador dinâmico (por exemplo /lib/ld.so
), que carrega as bibliotecas dinâmicas exigidas pelo programa. Em muitos departamentos, você pode configurar o caminho de pesquisa para bibliotecas dinâmicas por meio do ambiente ( LD_LIBRARY_PATH
é um nome comum para a variável de ambiente) e até carregar bibliotecas adicionais em todos os binários executados ( LD_PRELOAD
). O invocador do programa pode executar código arbitrário no contexto desse programa, colocando um especialmente criado libc.so
em $LD_LIBRARY_PATH
(entre outras táticas). Todos os sistemas sãos ignoram as LD_*
variáveis nos executáveis setuid.
Em shells como sh, csh e derivadas, as variáveis de ambiente se tornam automaticamente parâmetros de shell. Por meio de parâmetros como PATH
, IFS
e muitos mais, o invocador do script tem muitas oportunidades para executar código arbitrário no contexto dos scripts de shell. Alguns shells definem essas variáveis como padrões saudáveis, se detectarem que o script foi invocado com privilégios, mas não sei se há alguma implementação específica em que eu confiaria.
A maioria dos ambientes de tempo de execução (nativos, bytecode ou interpretados) possui recursos semelhantes. Poucos tomam precauções especiais em executáveis setuid, embora os que executam código nativo geralmente não façam nada mais sofisticado do que a vinculação dinâmica (que toma precauções).
Perl é uma exceção notável. Ele suporta explicitamente scripts setuid de maneira segura. De fato, seu script pode executar o setuid, mesmo que seu SO tenha ignorado o bit setuid nos scripts. Isso ocorre porque o perl é fornecido com um assistente raiz setuid que executa as verificações necessárias e reinicia o intérprete nos scripts desejados com os privilégios desejados. Isso é explicado no manual do perlsec . Antes, os scripts setuid perl necessários, em #!/usr/bin/suidperl -wT
vez de #!/usr/bin/perl -wT
, mas na maioria dos sistemas modernos, #!/usr/bin/perl -wT
são suficientes.
Observe que o uso de um wrapper binário nativo não faz nada por si só para evitar esses problemas . Na verdade, ele pode tornar a situação pior , porque pode evitar que o seu ambiente de tempo de execução de detectar que é invocada com privilégios e ignorando sua configurabilidade execução.
Um wrapper binário nativo pode tornar um script de shell seguro se o wrapper higienizar o ambiente . O script deve tomar cuidado para não fazer muitas suposições (por exemplo, sobre o diretório atual), mas isso vale. Você pode usar o sudo para isso, desde que esteja configurado para higienizar o ambiente. As variáveis da lista negra estão sujeitas a erros, portanto, sempre use a lista de permissões. Com sudo, certifique-se de que a env_reset
opção está ligada, que setenv
está desligado, e que env_file
e env_keep
contêm apenas variáveis inócuos.
TL, DR:
- Shebang Setuid é inseguro, mas geralmente ignorado.
- Se você executar um programa com privilégios (por meio do sudo ou setuid), escreva código nativo ou perl ou inicie o programa com um wrapper que higienize o ambiente (como o sudo com a
env_reset
opção).
Discussion Esta discussão se aplica igualmente se você substituir “setgid” por “setuid”; ambos são ignorados pelo kernel do Linux em scripts
suidperl
material foi preterido e marcado para remoção por anos (mas persiste não-a-menos)suidperl
, foi removido a partir do perl 5.11 (5.12 estável): perl5110delta:> "suidperl" foi removido. Ele costumava fornecer um mecanismo para emular bits de permissão setuid em sistemas que não o suportam adequadamente. perl5120delta:> "suidperl" não faz mais parte do Perl. Ele costumava fornecer um mecanismo para emular bits de permissão setuid em sistemas que não o suportam adequadamente.Uma maneira de resolver esse problema é chamar o shell script de um programa que pode usar o bit setuid.
é algo como sudo. Por exemplo, aqui está como você faria isso em um programa C:
Salve-o como setuid-test2.c.
compile
Agora faça o setuid neste programa binário:
Agora, você deve poder executá-lo e verá seu script sendo executado sem permissão de ninguém.
Mas aqui também você precisa codificar o caminho do script ou passá-lo como linha de comando arg para acima do exe.
fonte
PATH
eLD_LIBRARY_PATH
são vetores óbvios. Alguns escudos executar$ENV
ou$BASHENV
ou~/.zshenv
até mesmo antes de começar a executar o script adequado, então você não pode proteger contra estes em tudo de dentro do script. A única maneira segura de chamar um script de shell com privilégios é limpar o ambiente . Sudo sabe como fazer isso com segurança. Portanto , não escreva seu próprio invólucro, use sudo .LD_LIBRARY_PATH
entre outras coisas, quando encontra o bit setuid.system
, você pode achar mais simples (e mais eficiente) usar um membro daexec
família - provavelmenteexecve
. Dessa forma, você não cria um novo processo ou inicia um shell e pode encaminhar argumentos (assumindo que seu script privilegiado possa manipular argumentos com segurança).Prefixo alguns scripts que estão neste barco assim:
Observe que isso não usa,
setuid
mas simplesmente executa o arquivo atual comsudo
.fonte
sudo
prompt. (Para mim, todo o ponto de setuid é permitir que as coisas executado como root sem necessidade de sudo.)Se você quiser evitar ligar,
sudo some_script
basta:Os programas SETUID precisam ser projetados com extremo cuidado, pois são executados com privilégios de root e os usuários têm grande controle sobre eles. Eles precisam verificar a sanidade de tudo. Você não pode fazer isso com scripts porque:
sed
,awk
etc. também precisariam ser verificadosObserve que isso
sudo
fornece algumas verificações de integridade, mas não é suficiente - verifique todas as linhas em seu próprio código.Como uma última observação: considere o uso de recursos. Eles permitem que você conceda a um processo em execução como usuário privilégios especiais que normalmente exigiriam privilégios de root. No entanto, por exemplo, embora seja
ping
necessário manipular a rede, ele não precisa ter acesso aos arquivos. Não tenho certeza, no entanto, se eles são herdados.fonte
/ust/bin/env
deveria ser/usr/bin/env
.Você pode criar um alias para sudo + o nome do script. Claro, isso é ainda mais trabalhoso de configurar, pois você também precisa configurar um alias, mas evita que você precise digitar sudo.
Mas se você não se importa com riscos horríveis de segurança, use um shell setuid como intérprete para o script do shell. Não sei se isso funcionará para você, mas acho que pode.
Deixe-me declarar que eu aconselho a não fazer isso, no entanto. Estou apenas mencionando isso para fins educacionais ;-)
fonte
rm -rf /
Ou seja, qualquer um pode executar (e outros comandos da série NÃO O FAZEM EM CASA ).comando super [-r reqpath] [args]
Super permite que usuários especificados executem scripts (ou outros comandos) como se fossem root; ou pode definir os grupos uid, gid e / ou suplementares por comando antes de executar o comando. Ele pretende ser uma alternativa segura para criar scripts como setuid. Super também permite que usuários comuns forneçam comandos para execução por outros; estes são executados com o uid, gid e grupos do usuário que oferece o comando.
Super consulta um arquivo `` super.tab '' para ver se o usuário tem permissão para executar o comando solicitado. Se a permissão for concedida, super executará o pgm [args], em que pgm é o programa associado a este comando. (A raiz é permitida a execução por padrão, mas ainda pode ser negada se uma regra excluir a raiz. Usuários comuns não podem executar a execução por padrão.)
Se o comando for um link simbólico (ou link físico também) para o super programa, digitar% command args é equivalente a digitar% super command args (o comando não deve ser super ou super não reconhecerá que está sendo chamado por meio de um ligação.)
http://www.ucolick.org/~will/RUE/super/README
http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html
fonte
Se, por algum motivo,
sudo
não estiver disponível, você poderá escrever um script de wrapper fino em C:E depois de compilá-lo, defina-o como
setuid
comchmod 4511 wrapper_script
.Isso é semelhante a outra resposta publicada, mas executa o script com um ambiente limpo e usa explicitamente, em
/bin/bash
vez do shell chamado porsystem()
, e, portanto, fecha algumas falhas de segurança em potencial.Observe que isso descarta o ambiente completamente. Se você deseja usar algumas variáveis ambientais sem abrir vulnerabilidades, você realmente só precisa usá-lo
sudo
.Obviamente, você deseja garantir que o próprio script seja gravável apenas pela raiz.
fonte
Encontrei essa pergunta pela primeira vez, não convencida de todas as respostas, e aqui está uma muito melhor, que também permite ofuscar completamente o script do bash, se você quiser!
Deve ser auto-explicativo.
Então você corre
fonte