Como passar com segurança variáveis ​​para scripts habilitados para raiz?

13

Esta pergunta é totalmente geral e não se aplica apenas à minha situação, mas ... Eu tenho um pequeno dispositivo busybox no qual desejo que um usuário não root possa executar um script específico com privilégios de root. Por exemplo, algo como este pequeno script para ativar o DHCP, onde a única variável ( $1) a ser enviada no cmdline (!!) é o nome do host a ser enviado:

#!/bin/bash
udhcpc -b -i eth0 -h $1

executar udhcpc como este requer acesso root, portanto, para isso, planejo modificar /etc/sudoerspara conter esta linha:

joe ALL = NOPASSWD: /path/to/enable_dhcp.sh

o que deve permitir que "joe" execute facilmente esse script com privilégios de root simplesmente executando:

sudo /path/to/enable_dhcp.sh

e não sendo solicitada uma senha (que é o que eu quero, pois quero que Joe seja capaz de escrever isso).

Agora .. eu sei (ou pelo menos acho que sim) que usar$1 um script que possa ser facilmente executado com privilégios de root é uma idéia HORRÍVEL, pois você pode injetar o que quiser nele.

Então ... qual é a melhor maneira de lidar com isso? Como deixo joe fazer o que quero com privilégios de root, permitir que ele passe uma variável (ou efetivamente o faça com uma variável de ambiente), sem estar aberto a ataques de injeção?

Russ
fonte

Respostas:

14

A execução de scripts de shell sob sudoé segura, desde que sudoconfigurada para redefinir o ambiente . Por outro lado, se sudonão redefinir o ambiente, a execução de um script de shell não será segura, mesmo que seu script não use seus parâmetros (consulte Permitir setuid em scripts de shell ). Certifique-se de que você tem Defaults env_resetem /etc/sudoersou que esta opção é o padrão de tempo de compilação (sudo sudo -V | grep env deve incluir Reset the environment to a default set of variables).

Não há perigo particular em usar os parâmetros de script. $1é uma string, tudo o que você precisa é ter certeza de que está sendo usada como uma string. (Por exemplo, não faça eval "$1".) Obviamente, é especialmente importante aqui não fazer suposições sobre o conteúdo da variável e colocar aspas duplas em todas as substituições de variáveis (por exemplo "$1", escrever , não$1 ). Observe que colocar aspas duplas em torno de substituições de variáveis ​​não é específico para scripts executados com privilégios, é algo que você deve fazer o tempo todo.

Convém validar ainda mais o parâmetro, dependendo do que udhcpcacontece com algo que não se parece com um nome de host. Por exemplo, isso executará uma primeira verificação sintática:

#!/bin/sh
case "$1" in
  *[!:-.0-9A-Za-z]*|-*) echo 1>&2 "Badly formed host name!"; exit 3;;
esac
udhcpc -b -i eth0 -h "$1"
Gilles 'SO- parar de ser mau'
fonte
Outras coisas a considerar que podem ter um impacto no comportamento desse comando: diretório de trabalho atual e o que stdin, stdout, stderr apontam, manipuladores de sinal e ulimits. Por exemplo, ao permitir dumps principais (em <kbd> Ctrl- \ </kbd>), você pode permitir que o usuário desarrume / execute / bloqueie, que no meu sistema é um tmpfs com tamanho muito limitado e pode permitir um DoS.
Stéphane Chazelas
5

Você deve combinar a entrada passada com um padrão conhecido.

Por exemplo, parece que um endereço IP pode ser uma entrada válida para você. Então você pode usar algo como isto:

if [[ "$1" =~ ^[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9]$ ]]
then
  udhcpc -b -i eth0 -h "$1"
else
  echo "Don't mess with me pork chop."
fi

Observe que o regexp não foi testado, você é responsável por garantir que o regexp não permita nada de perigoso.

bahamat
fonte