Linux ignoruje bit setuid¹ na wszystkich interpretowanych plikach wykonywalnych (tj. Plikach rozpoczynających się od #!
linii). Comp.unix.questions FAQ wyjaśnia problemy bezpieczeństwa z setuid skryptów powłoki. Problemy te są dwojakiego rodzaju: związane z shebangiem i związane z powłoką; Więcej szczegółów poniżej.
Jeśli nie dbasz o bezpieczeństwo i chcesz zezwolić na skrypty setuid, pod Linuksem musisz załatać jądro. Jeśli chodzi o jądra 3.x, myślę, że musisz dodać wywołanie install_exec_creds
w load_script
funkcji przed wywołaniem do open_exec
, ale nie testowałem.
Setuid shebang
Występuje warunek wyścigu nieodłącznie związany ze sposobem, w jaki shebang ( #!
) jest zwykle implementowany:
- Jądro otwiera plik wykonywalny i stwierdza, że zaczyna się od
#!
.
- Jądro zamyka plik wykonywalny i zamiast tego otwiera interpreter.
- Jądro wstawia ścieżkę do skryptu na listę argumentów (as
argv[1]
) i wykonuje interpreter.
Jeśli w tej implementacji dozwolone są skrypty setuid, osoba atakująca może wywołać dowolny skrypt, tworząc dowiązanie symboliczne do istniejącego skryptu setuid, wykonując go i organizując zmianę łącza po wykonaniu kroku 1 przez jądro i zanim interpreter przejdzie do otwierając swój pierwszy argument. Z tego powodu większość jednorożców ignoruje bit setuid, gdy wykrywa shebang.
Jednym ze sposobów zabezpieczenia tej implementacji byłoby zablokowanie pliku skryptu przez jądro, dopóki interpreter go nie otworzy (pamiętaj, że musi to zapobiegać nie tylko odłączeniu lub zastąpieniu pliku, ale także zmianie nazwy dowolnego katalogu na ścieżce). Ale systemy uniksowe zwykle unikają obowiązkowych blokad, a dowiązania symboliczne sprawiłyby, że poprawna funkcja blokady byłaby szczególnie trudna i inwazyjna. Nie sądzę, żeby ktokolwiek to robił w ten sposób.
Kilka systemów uniksowych (głównie OpenBSD, NetBSD i Mac OS X, z których wszystkie wymagają włączenia ustawienia jądra) implementuje bezpieczny shebang setuid za pomocą dodatkowej funkcji: ścieżka odnosi się do pliku już otwartego w deskryptorze pliku N (więc otwieranie jest z grubsza odpowiada ). Wiele systemów uniksowych (w tym Linux) ma skrypty setuid./dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- Jądro otwiera plik wykonywalny i stwierdza, że zaczyna się od
#!
. Powiedzmy, że deskryptorem pliku dla pliku wykonywalnego jest 3.
- Jądro otwiera interpreter.
- Jądro wstawia
/dev/fd/3
listę argumentów (as argv[1]
) i wykonuje interpreter.
Strona shebang Svena Maschecka zawiera wiele informacji na temat shebang u jednorożców, w tym wsparcie setuid .
Tłumacze Setuid
Załóżmy, że udało Ci się uruchomić program jako root, albo dlatego, że twój system obsługuje setuid shebang, albo dlatego, że użyłeś natywnego binarnego opakowania (takiego jak sudo
). Czy otworzyłeś lukę bezpieczeństwa? Może . Tutaj nie chodzi o programy interpretowane a skompilowane. Problem polega na tym, czy system wykonawczy zachowuje się bezpiecznie, jeśli jest wykonywany z uprawnieniami.
Każdy dynamicznie połączony natywny binarny plik wykonywalny jest w sposób interpretowany przez program ładujący dynamiczny (np. /lib/ld.so
), Który ładuje biblioteki dynamiczne wymagane przez program. W wielu jednostkach unikalnych można skonfigurować ścieżkę wyszukiwania bibliotek dynamicznych za pośrednictwem środowiska ( LD_LIBRARY_PATH
jest to wspólna nazwa zmiennej środowiskowej), a nawet załadować dodatkowe biblioteki do wszystkich wykonywanych plików binarnych ( LD_PRELOAD
). Wywołującego programu można wykonać dowolny kod w kontekście tego programu poprzez umieszczenie specjalnie spreparowane libc.so
w $LD_LIBRARY_PATH
(między innymi taktyki). Wszystkie zdrowe systemy ignorują LD_*
zmienne w plikach wykonywalnych setuid.
W powłokach, takich jak sh, csh i pochodne, zmienne środowiskowe automatycznie stają się parametrami powłoki. Poprzez parametrów takich jak PATH
, IFS
i wiele więcej, wywołującego skrypt ma wiele szans na wykonanie dowolnego kodu w kontekście skryptów powłoki. Niektóre powłoki ustawiają te zmienne na rozsądne wartości domyślne, jeśli wykryją, że skrypt został wywołany z uprawnieniami, ale nie wiem, czy istnieje jakaś konkretna implementacja, której mógłbym zaufać.
Większość środowisk wykonawczych (macierzystych, kodu bajtowego lub interpretowanych) ma podobne funkcje. Niewielu zachowuje szczególne środki ostrożności w plikach wykonywalnych setuid, chociaż te, które uruchamiają natywny kod, często nie robią nic bardziej wymyślnego niż dynamiczne łączenie (które podejmuje środki ostrożności).
Perl jest godnym uwagi wyjątkiem. To wyraźnie obsługuje skryptów setuid w bezpieczny sposób. W rzeczywistości skrypt może uruchamiać setuid, nawet jeśli system operacyjny zignorował bit setuid w skryptach. Wynika to z faktu, że Perl jest dostarczany z pomocnikiem setuid root, który wykonuje niezbędne kontrole i ponownie wywołuje interpreter na pożądanych skryptach z pożądanymi uprawnieniami. Jest to wyjaśnione w podręczniku perlsec . Kiedyś potrzebne były #!/usr/bin/suidperl -wT
zamiast tego skrypty pertu z setuid #!/usr/bin/perl -wT
, ale w większości nowoczesnych systemów #!/usr/bin/perl -wT
są wystarczające.
Zauważ, że użycie natywnego opakowania binarnego samo w sobie nie zapobiega tym problemom . W rzeczywistości może to pogorszyć sytuację , ponieważ może uniemożliwić środowisku wykonawczemu wykrycie, że jest wywoływane z uprawnieniami i pominięcie jego konfigurowalności.
Natywne opakowanie binarne może uczynić skrypt powłoki bezpiecznym, jeśli opakowanie dezynfekuje środowisko . Skrypt musi uważać, aby nie przyjmować zbyt wielu założeń (np. Dotyczących bieżącego katalogu), ale tak jest. Możesz użyć do tego sudo, pod warunkiem, że jest skonfigurowany do odkażania środowiska. Zmienne na czarnej liście są podatne na błędy, dlatego zawsze należy do białej listy. W sudo upewnij się, że env_reset
opcja jest włączona, że setenv
jest wyłączona env_file
i env_keep
zawiera tylko nieszkodliwe zmienne.
TL, DR:
- Setuid shebang jest niepewny, ale zwykle jest ignorowany.
- Jeśli uruchamiasz program z uprawnieniami (przez sudo lub setuid), napisz kod natywny lub perl lub uruchom program z opakowania, które dezynfekuje środowisko (takie jak sudo z
env_reset
opcją).
¹ Dyskusja ta ma zastosowanie również w przypadku zastąpienia słowa „setgid” słowem „setuid”; oba są ignorowane przez jądro Linuksa w skryptach