Jak bezpiecznie przekazywać zmienne do skryptów z włączonym rootem?

13

To pytanie jest całkowicie ogólne i dotyczy nie tylko mojej sytuacji, ale ... Mam małe urządzenie busybox, w którym chcę, aby użytkownik inny niż root mógł wykonać określony skrypt z uprawnieniami administratora. Na przykład coś takiego jak ten mały skrypt do włączenia DHCP, gdzie jedyną zmienną ( $1) do wysłania na cmdline (!!) jest nazwa hosta do wysłania:

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

uruchamianie udhcpc w ten sposób wymaga dostępu do konta root, więc w tym celu planuję zmodyfikować, /etc/sudoersaby zawierał ten wiersz:

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

które powinny umożliwić „Joe” łatwe uruchamianie tego skryptu z uprawnieniami administratora poprzez proste uruchomienie:

sudo /path/to/enable_dhcp.sh

i nie jest proszony o hasło (to jest to, czego chcę, ponieważ chcę, żeby Joe mógł to zrobić).

Teraz .. Wiem (a przynajmniej tak mi się wydaje), że użycie $1w skrypcie, który można łatwo uruchomić z uprawnieniami administratora, jest OGROMNYM pomysłem, ponieważ możesz do niego wstrzyknąć, co tylko chcesz.

Więc ... jaki jest najlepszy sposób, aby sobie z tym poradzić? Jak pozwolić Joe'emu robić, co chcę, z uprawnieniami roota, pozwalać mu przekazywać zmienną (lub skutecznie robić to tak, jak ze zmienną środowiskową), nie będąc jednocześnie szeroko otwartym na ataki iniekcyjne?

Russ
źródło

Odpowiedzi:

14

Uruchamianie skryptów powłoki pod sudojest bezpieczne, pod warunkiem, że sudojest skonfigurowane do resetowania środowiska . I odwrotnie, jeśli sudonie zresetuje środowiska, uruchomienie skryptu powłoki nie jest bezpieczne, nawet jeśli skrypt nie używa jego parametrów (zobacz Zezwalaj na setuid w skryptach powłoki ). Upewnij się, że masz Defaults env_resetw /etc/sudoersalbo, że ta opcja jest domyślnym czasu kompilacji ( sudo sudo -V | grep envpowinny zawierać Reset the environment to a default set of variables).

Używanie parametrów skryptu nie stanowi szczególnego zagrożenia. $1to ciąg znaków, wszystko, czego potrzebujesz, aby upewnić się, że używasz go jako łańcucha. (Na przykład nie rób eval "$1".) Oczywiście szczególnie ważne jest tutaj, aby nie przyjmować założeń dotyczących zawartości zmiennej i umieszczać podwójne cudzysłowy wokół wszystkich podstawień zmiennych (tj. Pisać "$1", nie $1). Zauważ, że umieszczanie podwójnych cudzysłowów wokół podstawień zmiennych nie jest specyficzne dla skryptów uruchamianych z uprawnieniami, jest to coś, co musisz robić cały czas.

Możesz dodatkowo sprawdzić poprawność parametru, w zależności od tego, co udhcpcrobi z czymś, co nie wygląda jak nazwa hosta. Na przykład wykona to pierwsze sprawdzenie składniowe:

#!/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- przestań być zły”
źródło
Inne rzeczy, które należy wziąć pod uwagę, które mogą mieć wpływ na zachowanie tego polecenia: bieżący katalog roboczy i to, na co wskazują stdin, stdout, stderr, programy obsługi sygnałów i ulimity. Na przykład, zezwalając na zrzuty rdzenia (po <kbd> Ctrl- \ </kbd>), możesz pozwolić użytkownikowi na zaśmiecanie / uruchamianie / blokowanie, który w moim systemie jest tmpfs o bardzo ograniczonym rozmiarze i może pozwolić na DoS.
Stéphane Chazelas
5

Powinieneś dopasować przekazane dane wejściowe do znanego dobrego wzorca.

Na przykład wygląda na to, że adres IP może być dla Ciebie prawidłowy. Możesz więc użyć czegoś takiego:

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

Pamiętaj, że wyrażenie regularne nie zostało przetestowane, jesteś odpowiedzialny za upewnienie się, że wyrażenie regularne nie zezwala na nic niebezpiecznego.

bahamat
źródło