Uwierzytelnianie przez PAM może się udać, gdy uruchomisz klienta ręcznie, i zawieść z AUTH_FAILED, gdy systemd uruchomi ten sam profil. Hasło nie zmienia się między tymi uruchomieniami; zmienia się zbiór ograniczeń wokół procesu, który zadaje PAM pytanie. PAM odpowiada przez helper, którego zdolność do zmiany własnych poświadczeń jest dokładnie tym, co usuwa utwardzona jednostka. Znajdź ten helper i granicę, której potrzebuje, zanim dotkniesz listy uprawnień.

unix_chkpwd to plik binarny, który odpowiada na pytanie PAM

Przy lokalnym uwierzytelnianiu hasłem pam_unix rzadko sam czyta plik skrótu. Uruchamia unix_chkpwd, który dystrybucje instalują jako setuid root lub setgid shadow, aby jedno hasło można było sprawdzić w imieniu procesu, który nie powinien czytać /etc/shadow. Odbierz możliwość uzyskania tej tożsamości, a helper nie zdoła dokończyć sprawdzania, więc moduł zwróci zwykły błąd uwierzytelniania.

Awaria wygląda wtedy we wszystkich logach widocznych dla klienta jak problem z poświadczeniami. To pułapka: klient raportuje to, co powiedział mu PAM, a PAM raportuje tylko, że stos powiedział nie. Uruchomienie helpera ręcznie jako root też niczego nie dowodzi, bo ćwiczy ścieżkę uprawnień, której usługa nigdy nie używa. Przeczytaj jednostkę, którą systemd faktycznie załadował, a potem dziennik systemowy o podjętej próbie. Te dwa widoki oddzielają problem piaskownicy od problemu złego hasła.

Przeczytaj jednostkę, zanim przeczytasz log haseł

Spakowana jednostka może nieść drop-in, którego nie napisałeś, a efektywna konfiguracja jest wynikiem scalenia. Wydrukuj jednostkę tak, jak widzi ją systemd, wraz z ustawieniami piaskownicy, które decydują, czy helper może podnieść własne uprawnienia. Inspekcja tylko do odczytu wystarcza na tym etapie.

systemctl cat [email protected]
systemctl show [email protected] -p User -p Group -p CapabilityBoundingSet -p AmbientCapabilities -p NoNewPrivileges
journalctl -u [email protected] -b

Pierwsze polecenie pokazuje, skąd pochodzi jednostka i jej drop-iny, co ma znaczenie, bo nadpisanie dodane miesiące temu żyje dłużej niż pamięć o tym, dlaczego istnieje. Drugie drukuje wartości piaskownicy, od których zależą dwa następne rozdziały.

Porównaj to, co widzisz, z działającym hostem tej samej dystrybucji i wersji. Różnica w User, CapabilityBoundingSet lub NoNewPrivileges to konkretny trop; różnica w komentarzach prozatorskich nie jest. Zapisz wartości przed jakąkolwiek zmianą, bo późniejsze porównanie z ruchomym celem niczego nie dowodzi. Jeśli usługa działa na nieuprzywilejowanym koncie z pustym zbiorem granicznym, helper nie ma prawie nic do pracy.

Transformacja poświadczeń, dostęp do plików i polityka to trzy granice

Zacznij od tego, co dzieje się podczas exec. Plik binarny setuid lub plik z file capabilities wywołuje transformację poświadczeń, więc wynikowa tożsamość nie jest kontynuacją wywołującego. Zbiór graniczny ogranicza to, co taki plik może uzyskać, a NoNewPrivileges całkowicie blokuje setuid, setgid i file capabilities. Każda z tych trzech rzeczy może zatrzymać helper, pozostawiając każdą inną funkcję usługi nietkniętą.

Następnie oddziel szerokie obejście dyskrecjonalne od wąskiego dostępu do odczytu. CAP_DAC_OVERRIDE pomija kontrole dyskrecjonalne niemal wszędzie, podczas gdy CAP_DAC_READ_SEARCH obejmuje odczyt i przechodzenie katalogów z własnymi dodatkowymi uprawnieniami. To różne narzędzia o różnym zasięgu rażenia i żadne z nich nie jest sposobem zapisu pozwól PAM czytać plik shadow.

Na koniec zapytaj, czy polityka obowiązkowa w ogóle pozwala na tę czynność. Uprawnienie Linuksa nie nadpisuje SELinux, a posiadanie go niczego nie dowodzi o regule wymuszania typów. Traktuj odmowę dostępu do pliku i odmowę uprawnienia jako różne dowody, bo wskazują różne poprawki i często różnych właścicieli. Czytaj każde pole rekordu, a nie samo słowo denied. Który plik wykonywalny wykonał czynność, w której domenie działał, jakiego typu celu dotknął, jaka klasa obiektu była zaangażowana i jakiego uprawnienia odmówiła polityka - każde z tych pytań zawęża odpowiedź inaczej.

Wyjmij odmowę z dziennika audytu

Na hoście w trybie enforcing ścieżka audytu jest jedynym miejscem, które zapisuje odmowę. Odpytaj o ostatnie zdarzenia i czytaj je według znacznika czasu nieudanego logowania, a nie według czasu, w którym zacząłeś dochodzenie.

ausearch -m AVC,USER_AVC -ts recent

Pusty wynik nie jest dowodem niewinności. Oznacza albo że audyt nie zbiera danych, albo że twoje okno ominęło próbę, i obie te możliwości trzeba wykluczyć, zanim wykluczysz politykę.

Wskazówki Red Hata dotyczące rozwiązywania problemów z SELinux stawiają sprawdzanie etykiet i konfiguracji przed generowaniem reguł zezwalających, co jest właściwą kolejnością również w tym problemie. Błędnie oznaczony plik binarny helpera i luka w polityce dają podobne odmowy, ale wymagają różnych napraw. Wygenerowanie reguły zezwalającej dla błędu etykiety ukrywa usterkę i sprawia, że następna aktualizacja pakietu wprowadzi ją ponownie. Potwierdź etykietę zainstalowanego helpera, zanim napiszesz jakąkolwiek politykę.

Udowodnij zmianę jednym udanym i jednym odrzuconym logowaniem

Zmień tylko granicę, którą wykazałeś, a następnie przetestuj oba wyniki. Konto, które powinno się uwierzytelnić, musi odnieść sukces, a konto z błędnym hasłem musi nadal zawodzić. Zmiana, po której każda próba się udaje, usunęła uwierzytelnianie, a nie je naprawiła.

Wykonaj prawdziwą próbę połączenia i natychmiast potem przeczytaj journal. Wierszem dowodzącym poprawki jest wpis pam_unix(openvpn:auth) dla tej próby: powinien mówić o sukcesie uwierzytelnienia, a żaden rekord AVC nie powinien mieć tej samej sekundy.

journalctl -u [email protected] -n 30 --no-pager
ss -tnp | grep openvpn

Działający tunel wymaga też ponownego połączenia, bo zmiany piaskownicy psują drugie połączenie częściej niż pierwsze. Sprawdź ustanowione gniazdo po ponownym połączeniu i potwierdź, że nadal obsługuje je ta sama jednostka.

Powiązane artykuły